Merge lp:~cjwatson/launchpad/init-branch-livefses into lp:launchpad

Proposed by Colin Watson
Status: Rejected
Rejected by: Colin Watson
Proposed branch: lp:~cjwatson/launchpad/init-branch-livefses
Merge into: lp:launchpad
Diff against target: 197 lines (+127/-1)
2 files modified
lib/lp/soyuz/scripts/initialize_distroseries.py (+31/-1)
lib/lp/soyuz/scripts/tests/test_initialize_distroseries.py (+96/-0)
To merge this branch: bzr merge lp:~cjwatson/launchpad/init-branch-livefses
Reviewer Review Type Date Requested Status
Colin Watson (community) Disapprove
Review via email: mp+274277@code.launchpad.net

Commit message

Copy live filesystems from the previous series on initialisation.

Description of the change

Copy live filesystems from the previous series on initialisation.

To avoid zombie livefses hanging around forever, this only copies those that have had builds created for them in the last 30 days, so at worst they should exist for one series longer than their true lifetime.

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) wrote :

We talked about this in the LP team meeting a couple of weeks ago. We might want to copy "official" livefses (mostly those owned by ~ubuntu-cdimage) but not other ones, because that isn't the kind of change LP would normally apply to user-owned artifacts. The 30-day limit is too much of a hack.

If somebody wants to tackle this in future, the place to start would be by introducing a database-backed notion of whether livefses are official. For now it's not too bad to keep this client-side.

review: Disapprove

Unmerged revisions

17814. By Colin Watson

Copy live filesystems from the previous series on initialisation.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/soyuz/scripts/initialize_distroseries.py'
--- lib/lp/soyuz/scripts/initialize_distroseries.py 2015-05-13 12:40:44 +0000
+++ lib/lp/soyuz/scripts/initialize_distroseries.py 2015-10-13 15:40:46 +0000
@@ -1,4 +1,4 @@
1# Copyright 2009-2014 Canonical Ltd. This software is licensed under the1# Copyright 2009-2015 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Initialize a distroseries from its parent distroseries."""4"""Initialize a distroseries from its parent distroseries."""
@@ -21,6 +21,7 @@
21from lp.registry.interfaces.pocket import PackagePublishingPocket21from lp.registry.interfaces.pocket import PackagePublishingPocket
22from lp.registry.model.distroseries import DistroSeries22from lp.registry.model.distroseries import DistroSeries
23from lp.services.database import bulk23from lp.services.database import bulk
24from lp.services.database.constants import THIRTY_DAYS_AGO
24from lp.services.database.interfaces import IMasterStore25from lp.services.database.interfaces import IMasterStore
25from lp.services.database.sqlbase import sqlvalues26from lp.services.database.sqlbase import sqlvalues
26from lp.services.helpers import ensure_unicode27from lp.services.helpers import ensure_unicode
@@ -38,6 +39,7 @@
38from lp.soyuz.interfaces.distributionjob import (39from lp.soyuz.interfaces.distributionjob import (
39 IDistroSeriesDifferenceJobSource,40 IDistroSeriesDifferenceJobSource,
40 )41 )
42from lp.soyuz.interfaces.livefs import ILiveFSSet
41from lp.soyuz.interfaces.packagecloner import IPackageCloner43from lp.soyuz.interfaces.packagecloner import IPackageCloner
42from lp.soyuz.interfaces.packageset import (44from lp.soyuz.interfaces.packageset import (
43 IPackagesetSet,45 IPackagesetSet,
@@ -45,6 +47,8 @@
45 )47 )
46from lp.soyuz.interfaces.queue import IPackageUploadSet48from lp.soyuz.interfaces.queue import IPackageUploadSet
47from lp.soyuz.model.binarypackagebuild import COPY_ARCHIVE_SCORE_PENALTY49from lp.soyuz.model.binarypackagebuild import COPY_ARCHIVE_SCORE_PENALTY
50from lp.soyuz.model.livefs import LiveFS
51from lp.soyuz.model.livefsbuild import LiveFSBuild
48from lp.soyuz.model.packageset import Packageset52from lp.soyuz.model.packageset import Packageset
49from lp.soyuz.scripts.packagecopier import do_copy53from lp.soyuz.scripts.packagecopier import do_copy
5054
@@ -289,6 +293,7 @@
289 self._copy_pocket_permissions()293 self._copy_pocket_permissions()
290 self._create_dsds()294 self._create_dsds()
291 self._set_initialized()295 self._set_initialized()
296 self._copy_livefses()
292 transaction.commit()297 transaction.commit()
293298
294 def _set_parents(self):299 def _set_parents(self):
@@ -737,3 +742,28 @@
737 """ % sqlvalues(742 """ % sqlvalues(
738 self.distroseries.main_archive, self.distroseries.id,743 self.distroseries.main_archive, self.distroseries.id,
739 parent.id))744 parent.id))
745
746 def _copy_livefses(self):
747 """Copy live filesystem configurations from the parent series."""
748 # We could probably be more efficient here, but the number of
749 # livefses is likely to be small.
750 livefs_set = getUtility(ILiveFSSet)
751 for parent in self.derivation_parents:
752 livefses = self._store.find(
753 LiveFS,
754 LiveFS.distro_series == parent,
755 LiveFSBuild.livefs == LiveFS.id,
756 LiveFSBuild.date_created >= THIRTY_DAYS_AGO)
757 for livefs in livefses:
758 if not livefs_set.exists(
759 livefs.owner, self.distroseries, livefs.name):
760 self._store.execute("""
761 INSERT INTO LiveFS (
762 registrant, owner, distro_series, name, json_data,
763 require_virtualized)
764 SELECT
765 registrant, owner, %s, name, json_data,
766 require_virtualized
767 FROM LiveFS AS parent_livefs
768 WHERE parent_livefs.id = %s
769 """ % sqlvalues(self.distroseries.id, livefs.id))
740770
=== modified file 'lib/lp/soyuz/scripts/tests/test_initialize_distroseries.py'
--- lib/lp/soyuz/scripts/tests/test_initialize_distroseries.py 2015-04-20 15:59:52 +0000
+++ lib/lp/soyuz/scripts/tests/test_initialize_distroseries.py 2015-10-13 15:40:46 +0000
@@ -5,6 +5,13 @@
55
6__metaclass__ = type6__metaclass__ = type
77
8from datetime import (
9 datetime,
10 timedelta,
11 )
12
13import pytz
14from testtools.matchers import MatchesStructure
8import transaction15import transaction
9from zope.component import getUtility16from zope.component import getUtility
1017
@@ -19,7 +26,9 @@
19 )26 )
20from lp.registry.interfaces.distroseriesparent import IDistroSeriesParentSet27from lp.registry.interfaces.distroseriesparent import IDistroSeriesParentSet
21from lp.registry.interfaces.pocket import PackagePublishingPocket28from lp.registry.interfaces.pocket import PackagePublishingPocket
29from lp.services.database.constants import ONE_DAY_AGO
22from lp.services.database.interfaces import IStore30from lp.services.database.interfaces import IStore
31from lp.services.features.testing import FeatureFixture
23from lp.soyuz.enums import (32from lp.soyuz.enums import (
24 ArchivePurpose,33 ArchivePurpose,
25 PackageUploadStatus,34 PackageUploadStatus,
@@ -28,6 +37,10 @@
28from lp.soyuz.interfaces.archivepermission import IArchivePermissionSet37from lp.soyuz.interfaces.archivepermission import IArchivePermissionSet
29from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuildSet38from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuildSet
30from lp.soyuz.interfaces.component import IComponentSet39from lp.soyuz.interfaces.component import IComponentSet
40from lp.soyuz.interfaces.livefs import (
41 ILiveFSSet,
42 LIVEFS_FEATURE_FLAG,
43 )
31from lp.soyuz.interfaces.packageset import (44from lp.soyuz.interfaces.packageset import (
32 IPackagesetSet,45 IPackagesetSet,
33 NoSuchPackageSet,46 NoSuchPackageSet,
@@ -1632,3 +1645,86 @@
1632 ("The selected architecture independent architecture tag is not "1645 ("The selected architecture independent architecture tag is not "
1633 "among the selected architectures."),1646 "among the selected architectures."),
1634 ids.check)1647 ids.check)
1648
1649 def test_copying_livefses(self):
1650 # If a parent series has live filesystems, we should copy them.
1651 self.parent, self.parent_das = self.setupParent()
1652 with FeatureFixture({LIVEFS_FEATURE_FLAG: u'on'}):
1653 livefs1 = self.factory.makeLiveFS(distroseries=self.parent)
1654 self.factory.makeLiveFSBuild(
1655 livefs=livefs1, date_created=ONE_DAY_AGO)
1656 livefs2 = self.factory.makeLiveFS(
1657 distroseries=self.parent,
1658 metadata={'project': 'ubuntu-core', 'image_format': 'plain'},
1659 require_virtualized=False)
1660 self.factory.makeLiveFSBuild(
1661 livefs=livefs2, date_created=ONE_DAY_AGO)
1662 child = self._fullInitialize([self.parent])
1663 child_livefs1 = getUtility(ILiveFSSet).getByName(
1664 livefs1.owner, child, livefs1.name)
1665 self.assertThat(child_livefs1, MatchesStructure.byEquality(
1666 registrant=livefs1.registrant, owner=livefs1.owner,
1667 distro_series=child, name=livefs1.name, metadata=livefs1.metadata,
1668 require_virtualized=livefs1.require_virtualized))
1669 child_livefs2 = getUtility(ILiveFSSet).getByName(
1670 livefs2.owner, child, livefs2.name)
1671 self.assertThat(child_livefs2, MatchesStructure.byEquality(
1672 registrant=livefs2.registrant, owner=livefs2.owner,
1673 distro_series=child, name=livefs2.name, metadata=livefs2.metadata,
1674 require_virtualized=livefs2.require_virtualized))
1675
1676 def test_copying_livefses_no_duplication(self):
1677 # Copying live filesystems only copies them from the most recent
1678 # series, rather than merging them from all series.
1679 previous_parent, _ = self.setupParent()
1680 parent = self._fullInitialize([previous_parent])
1681 with FeatureFixture({LIVEFS_FEATURE_FLAG: u'on'}):
1682 parent_livefs1 = self.factory.makeLiveFS(
1683 distroseries=parent, metadata={'marker': 'parent'})
1684 self.factory.makeLiveFSBuild(
1685 livefs=parent_livefs1, date_created=ONE_DAY_AGO)
1686 parent_livefs2 = self.factory.makeLiveFS(distroseries=parent)
1687 self.factory.makeLiveFSBuild(
1688 livefs=parent_livefs2, date_created=ONE_DAY_AGO)
1689 child = self._fullInitialize(
1690 [previous_parent], previous_series=parent,
1691 distribution=parent.distribution)
1692 child_livefs1 = getUtility(ILiveFSSet).getByName(
1693 parent_livefs1.owner, child, parent_livefs1.name)
1694 child_livefs1.metadata = {'marker': 'child'}
1695 with FeatureFixture({LIVEFS_FEATURE_FLAG: u'on'}):
1696 self.factory.makeLiveFSBuild(
1697 livefs=child_livefs1, date_created=ONE_DAY_AGO)
1698 child_livefs2 = getUtility(ILiveFSSet).getByName(
1699 parent_livefs2.owner, child, parent_livefs2.name)
1700 child_livefs2.destroySelf()
1701 grandchild = self._fullInitialize(
1702 [previous_parent], previous_series=child,
1703 distribution=parent.distribution)
1704 grandchild_livefs1 = getUtility(ILiveFSSet).getByName(
1705 child_livefs1.owner, grandchild, child_livefs1.name)
1706 self.assertEqual({'marker': 'child'}, grandchild_livefs1.metadata)
1707 self.assertFalse(
1708 getUtility(ILiveFSSet).exists(
1709 parent_livefs2.owner, grandchild, parent_livefs2.name))
1710
1711 def test_copying_livefses_skips_dormant(self):
1712 # Live filesystems that have not been built in the last 30 days are
1713 # not copied.
1714 self.parent, self.parent_das = self.setupParent()
1715 with FeatureFixture({LIVEFS_FEATURE_FLAG: u'on'}):
1716 livefs1 = self.factory.makeLiveFS(distroseries=self.parent)
1717 for days in 31, 30, 29:
1718 self.factory.makeLiveFSBuild(
1719 livefs=livefs1,
1720 date_created=datetime.now(pytz.UTC) - timedelta(days=days))
1721 livefs2 = self.factory.makeLiveFS(distroseries=self.parent)
1722 for days in 33, 32, 31:
1723 self.factory.makeLiveFSBuild(
1724 livefs=livefs2,
1725 date_created=datetime.now(pytz.UTC) - timedelta(days=days))
1726 child = self._fullInitialize([self.parent])
1727 self.assertTrue(
1728 getUtility(ILiveFSSet).exists(livefs1.owner, child, livefs1.name))
1729 self.assertFalse(
1730 getUtility(ILiveFSSet).exists(livefs2.owner, child, livefs2.name))