Vaishnavi Asawale has proposed merging ~vaishnavi-asawale/launchpad/+git/launchpad-1:move-use-fetch-service-button into launchpad:master.
Commit message: Move 'Use fetch service' button from Administer recipe to Edit recipe for snaps The user can initiate a snap build with the fetch service enabled (strict mode default) from the Edit recipe page. The SNAP_USE_FETCH_SERVICE_FEATURE_FLAG has been removed, as the use_fetch_service feature is now considered stable and unlikely to be disabled. All related tests using fixtures to simulate the feature flag have been updated accordingly. Requested reviews: Launchpad code reviewers (launchpad-reviewers) For more details, see: https://code.launchpad.net/~vaishnavi-asawale/launchpad/+git/launchpad-1/+merge/490217 -- Your team Launchpad code reviewers is requested to review the proposed merge of ~vaishnavi-asawale/launchpad/+git/launchpad-1:move-use-fetch-service-button into launchpad:master.
diff --git a/lib/lp/snappy/browser/snap.py b/lib/lp/snappy/browser/snap.py index dc4d330..a65b679 100644 --- a/lib/lp/snappy/browser/snap.py +++ b/lib/lp/snappy/browser/snap.py @@ -77,7 +77,6 @@ from lp.snappy.browser.widgets.snaparchive import SnapArchiveWidget from lp.snappy.browser.widgets.storechannels import StoreChannelsWidget from lp.snappy.interfaces.snap import ( SNAP_SNAPCRAFT_CHANNEL_FEATURE_FLAG, - SNAP_USE_FETCH_SERVICE_FEATURE_FLAG, CannotAuthorizeStoreUploads, CannotFetchSnapcraftYaml, CannotParseSnapcraftYaml, @@ -550,6 +549,8 @@ class ISnapEditSchema(Interface): store_name = copy_field(ISnap["store_name"], required=True) store_channels = copy_field(ISnap["store_channels"], required=True) + use_fetch_service = copy_field(ISnap["use_fetch_service"], required=True) + def log_oops(error, request): """Log an oops report without raising an error.""" @@ -941,9 +942,6 @@ class SnapAdminView(BaseSnapEditView): "pro_enable", ] - if getFeatureFlag(SNAP_USE_FETCH_SERVICE_FEATURE_FLAG): - fields.append("use_fetch_service") - return fields @property @@ -988,6 +986,7 @@ class SnapEditView(BaseSnapEditView, EnableProcessorsMixin): "store_upload", "store_name", "store_channels", + "use_fetch_service", ] custom_widget_store_distro_series = LaunchpadRadioWidget custom_widget_vcs = LaunchpadRadioWidget diff --git a/lib/lp/snappy/browser/tests/test_snap.py b/lib/lp/snappy/browser/tests/test_snap.py index 819d770..cd3f5af 100644 --- a/lib/lp/snappy/browser/tests/test_snap.py +++ b/lib/lp/snappy/browser/tests/test_snap.py @@ -61,7 +61,6 @@ from lp.snappy.browser.snap import ( ) from lp.snappy.interfaces.snap import ( SNAP_SNAPCRAFT_CHANNEL_FEATURE_FLAG, - SNAP_USE_FETCH_SERVICE_FEATURE_FLAG, CannotModifySnapProcessor, ISnapSet, SnapBuildRequestStatus, @@ -821,10 +820,6 @@ class TestSnapAdminView(BaseTestSnapView): def test_admin_snap(self): # Admins can change require_virtualized, privacy, and allow_internet. - self.useFixture( - FeatureFixture({SNAP_USE_FETCH_SERVICE_FEATURE_FLAG: True}) - ) - login("ad...@canonical.com") admin = self.factory.makePerson( member_of=[getUtility(ILaunchpadCelebrities).admin] @@ -839,7 +834,6 @@ class TestSnapAdminView(BaseTestSnapView): self.assertFalse(snap.private) self.assertTrue(snap.allow_internet) self.assertFalse(snap.pro_enable) - self.assertFalse(snap.use_fetch_service) self.factory.makeAccessPolicy( pillar=project, type=InformationType.PRIVATESECURITY @@ -852,39 +846,13 @@ class TestSnapAdminView(BaseTestSnapView): browser.getControl(name="field.information_type").value = private browser.getControl("Allow external network access").selected = False browser.getControl("Enable Ubuntu Pro").selected = True - browser.getControl("Use fetch service").selected = True browser.getControl("Update snap package").click() - - # XXX ines-almeida 2024-03-11: Browser tests work oddly with fixtures. - # This ensures that the feature flag is ON during the rest of the test. - # Further investigation on this issue is required. - self.useFixture( - FeatureFixture({SNAP_USE_FETCH_SERVICE_FEATURE_FLAG: True}) - ) login_admin() self.assertEqual(project, snap.project) self.assertFalse(snap.require_virtualized) self.assertTrue(snap.private) self.assertFalse(snap.allow_internet) self.assertTrue(snap.pro_enable) - self.assertTrue(snap.use_fetch_service) - - def test_admin_use_fetch_service_feature_flag(self): - admin = self.factory.makePerson( - member_of=[getUtility(ILaunchpadCelebrities).admin] - ) - snap = self.factory.makeSnap(registrant=admin) - browser = self.getViewBrowser(snap, user=admin) - - browser.getLink("Administer snap package").click() - self.assertFalse("Use fetch service" in browser.contents) - - self.useFixture( - FeatureFixture({SNAP_USE_FETCH_SERVICE_FEATURE_FLAG: True}) - ) - - browser.reload() - self.assertTrue("Use fetch service" in browser.contents) def test_admin_snap_private_without_project(self): # Cannot make snap private if it doesn't have a project associated. @@ -1458,6 +1426,32 @@ class TestSnapEditView(BaseTestSnapView): MatchesTagText(content, "source"), ) + def test_edit_use_fetch_service(self): + series = self.factory.makeUbuntuDistroSeries() + with admin_logged_in(): + snappy_series = self.factory.makeSnappySeries( + usable_distro_series=[series] + ) + login_person(self.person) + snap = self.factory.makeSnap( + registrant=self.person, + owner=self.person, + distroseries=series, + branch=self.factory.makeAnyBranch(), + store_series=snappy_series, + ) + browser = self.getViewBrowser(snap, user=self.person) + browser.getLink("Edit snap package").click() + self.assertTrue("Use fetch service" in browser.contents) + with person_logged_in(self.person): + self.assertFalse(snap.use_fetch_service) + browser.getControl("Use fetch service").selected = True + browser.getControl("Update snap package").click() + browser = self.getViewBrowser(snap, user=self.person) + browser.getLink("Edit snap package").click() + with person_logged_in(self.person): + self.assertTrue(snap.use_fetch_service) + def setUpSeries(self): """Set up {distro,snappy}series with some available processors.""" distroseries = self.factory.makeUbuntuDistroSeries() diff --git a/lib/lp/snappy/interfaces/snap.py b/lib/lp/snappy/interfaces/snap.py index 684c280..4c56003 100644 --- a/lib/lp/snappy/interfaces/snap.py +++ b/lib/lp/snappy/interfaces/snap.py @@ -19,11 +19,11 @@ __all__ = [ "ISnapDelete", "ISnapSet", "ISnapView", + "ISnapEditableAttributes", "MissingSnapcraftYaml", "NoSourceForSnap", "NoSuchSnap", "SNAP_SNAPCRAFT_CHANNEL_FEATURE_FLAG", - "SNAP_USE_FETCH_SERVICE_FEATURE_FLAG", "SnapAuthorizationBadGeneratedMacaroon", "SnapBuildAlreadyPending", "SnapBuildArchiveOwnerMismatch", @@ -1140,6 +1140,32 @@ class ISnapEditableAttributes(IHasOwner): ) ) + use_fetch_service = exported( + Bool( + title=_("Use fetch service"), + required=True, + readonly=False, + description=_( + "If set, Snap builds will use the fetch-service instead " + "of the builder-proxy to access external resources." + ), + ) + ) + + fetch_service_policy = exported( + Choice( + title=_("Fetch service policy"), + vocabulary=FetchServicePolicy, + required=False, + readonly=False, + default=FetchServicePolicy.STRICT, + description=_( + "Which policy to use when using the fetch service. Ignored if " + "`use_fetch_service` flag is False." + ), + ) + ) + def setProject(project): """Set the pillar project of this snap recipe.""" @@ -1194,32 +1220,6 @@ class ISnapAdminAttributes(Interface): ) ) - use_fetch_service = exported( - Bool( - title=_("Use fetch service"), - required=True, - readonly=False, - description=_( - "If set, Snap builds will use the fetch-service instead " - "of the builder-proxy to access external resources." - ), - ) - ) - - fetch_service_policy = exported( - Choice( - title=_("Fetch service policy"), - vocabulary=FetchServicePolicy, - required=False, - readonly=False, - default=FetchServicePolicy.STRICT, - description=_( - "Which policy to use when using the fetch service. Ignored if " - "`use_fetch_service` flag is False." - ), - ) - ) - def subscribe(person, subscribed_by): """Subscribe a person to this snap recipe.""" @@ -1270,6 +1270,8 @@ class ISnapSet(Interface): "store_name", "store_channels", "project", + "use_fetch_service", + "fetch_service_policy", ], ) @operation_for_version("devel") diff --git a/lib/lp/snappy/model/snap.py b/lib/lp/snappy/model/snap.py index dfe2282..acb41ab 100644 --- a/lib/lp/snappy/model/snap.py +++ b/lib/lp/snappy/model/snap.py @@ -125,7 +125,6 @@ from lp.services.database.stormexpr import ( IsDistinctFrom, NullsLast, ) -from lp.services.features import getFeatureFlag from lp.services.job.interfaces.job import JobStatus from lp.services.job.model.job import Job from lp.services.librarian.model import LibraryFileAlias, LibraryFileContent @@ -138,7 +137,6 @@ from lp.services.webhooks.interfaces import IWebhookSet from lp.services.webhooks.model import WebhookTargetMixin from lp.snappy.adapters.buildarch import determine_architectures_to_build from lp.snappy.interfaces.snap import ( - SNAP_USE_FETCH_SERVICE_FEATURE_FLAG, BadMacaroon, BadSnapSearchContext, BadSnapSource, @@ -396,7 +394,7 @@ class Snap(StormBase, WebhookTargetMixin): pro_enable = Bool(name="pro_enable", allow_none=False) - _use_fetch_service = Bool(name="use_fetch_service", allow_none=False) + use_fetch_service = Bool(name="use_fetch_service", allow_none=False) fetch_service_policy = DBEnum( enum=FetchServicePolicy, @@ -696,17 +694,6 @@ class Snap(StormBase, WebhookTargetMixin): def store_channels(self, value): self._store_channels = value or None - @property - def use_fetch_service(self): - if getFeatureFlag(SNAP_USE_FETCH_SERVICE_FEATURE_FLAG): - return self._use_fetch_service - return None - - @use_fetch_service.setter - def use_fetch_service(self, value): - if getFeatureFlag(SNAP_USE_FETCH_SERVICE_FEATURE_FLAG): - self._use_fetch_service = value - def getAllowedInformationTypes(self, user): """See `ISnap`.""" if user_has_special_snap_access(user): diff --git a/lib/lp/snappy/templates/snap-edit.pt b/lib/lp/snappy/templates/snap-edit.pt index ad92312..5f911e5 100644 --- a/lib/lp/snappy/templates/snap-edit.pt +++ b/lib/lp/snappy/templates/snap-edit.pt @@ -133,6 +133,10 @@ <tal:widget define="widget nocall:view/widgets/processors"> <metal:block use-macro="context/@@launchpad_form/widget_row" /> </tal:widget> + + <tal:widget define="widget nocall:view/widgets/use_fetch_service"> + <metal:block use-macro="context/@@launchpad_form/widget_row" /> + </tal:widget> </table> </metal:formbody> </div> diff --git a/lib/lp/snappy/tests/test_snap.py b/lib/lp/snappy/tests/test_snap.py index dba8e01..b77b02e 100644 --- a/lib/lp/snappy/tests/test_snap.py +++ b/lib/lp/snappy/tests/test_snap.py @@ -69,7 +69,7 @@ from lp.services.database.sqlbase import ( flush_database_caches, get_transaction_timestamp, ) -from lp.services.features.testing import FeatureFixture, MemoryFeatureFixture +from lp.services.features.testing import MemoryFeatureFixture from lp.services.job.interfaces.job import JobStatus from lp.services.job.runner import JobRunner from lp.services.log.logger import BufferLogger @@ -80,7 +80,6 @@ from lp.services.webapp.publisher import canonical_url from lp.services.webapp.snapshot import notify_modified from lp.services.webhooks.testing import LogsScheduledWebhooks from lp.snappy.interfaces.snap import ( - SNAP_USE_FETCH_SERVICE_FEATURE_FLAG, BadSnapSearchContext, CannotFetchSnapcraftYaml, CannotModifySnapProcessor, @@ -1940,6 +1939,15 @@ class TestSnap(TestCaseWithFactory): ) self.assertThat(recorder2, HasQueryCount.byEquality(recorder1)) + def test_snap_use_fetch_service(self): + person = self.factory.makePerson() + with person_logged_in(person): + snap = self.factory.makeSnap(registrant=person, owner=person) + + self.assertFalse(snap.use_fetch_service) + snap.use_fetch_service = True + self.assertTrue(snap.use_fetch_service) + class TestSnapDeleteWithBuilds(TestCaseWithFactory): layer = LaunchpadFunctionalLayer @@ -2353,8 +2361,6 @@ class TestSnapSet(TestCaseWithFactory): "allow_internet": True, "pro_enable": True, "require_virtualized": True, - "use_fetch_service": True, - "fetch_service_policy": FetchServicePolicy.PERMISSIVE, } for field_name, field_value in admin_fields.items(): @@ -2366,10 +2372,6 @@ class TestSnapSet(TestCaseWithFactory): def test_admins_can_update_admin_only_fields(self): # The admin fields can be updated by an admin - self.useFixture( - FeatureFixture({SNAP_USE_FETCH_SERVICE_FEATURE_FLAG: "on"}) - ) - [ref] = self.factory.makeGitRefs() components = self.makeSnapComponents(git_ref=ref) snap = getUtility(ISnapSet).new(**components) @@ -2378,8 +2380,6 @@ class TestSnapSet(TestCaseWithFactory): "allow_internet": True, "pro_enable": True, "require_virtualized": True, - "use_fetch_service": True, - "fetch_service_policy": FetchServicePolicy.PERMISSIVE, } for field_name, field_value in admin_fields.items(): @@ -2388,26 +2388,6 @@ class TestSnapSet(TestCaseWithFactory): setattr(snap, field_name, field_value) self.assertEqual(field_value, getattr(snap, field_name)) - def test_snap_use_fetch_service_feature_flag(self): - # The snap.use_fetch_service API only works when feature flag is set - [ref] = self.factory.makeGitRefs() - components = self.makeSnapComponents(git_ref=ref) - snap = getUtility(ISnapSet).new(**components) - - # admin cannot get the actual value or set a new value to the - # use_fetch_service field when the feature flag is OFF - login_admin() - self.assertEqual(None, snap.use_fetch_service) - snap.use_fetch_service = True - self.assertEqual(None, snap.use_fetch_service) - - # when feature flag is ON, admin can see the real value of - # `use_fetch_service` and opt in and out of it - with MemoryFeatureFixture({SNAP_USE_FETCH_SERVICE_FEATURE_FLAG: "on"}): - self.assertFalse(snap.use_fetch_service) - snap.use_fetch_service = True - self.assertTrue(snap.use_fetch_service) - def test_create_private_snap_with_open_team_as_owner_fails(self): components = self.makeSnapComponents() with admin_logged_in(): diff --git a/lib/lp/snappy/tests/test_snapbuildbehaviour.py b/lib/lp/snappy/tests/test_snapbuildbehaviour.py index 8a0bcf3..91ce9cf 100644 --- a/lib/lp/snappy/tests/test_snapbuildbehaviour.py +++ b/lib/lp/snappy/tests/test_snapbuildbehaviour.py @@ -78,7 +78,6 @@ from lp.services.statsd.tests import StatsMixin from lp.services.webapp import canonical_url from lp.snappy.interfaces.snap import ( SNAP_SNAPCRAFT_CHANNEL_FEATURE_FLAG, - SNAP_USE_FETCH_SERVICE_FEATURE_FLAG, SnapBuildArchiveOwnerMismatch, ) from lp.snappy.model.snapbuildbehaviour import ( @@ -293,9 +292,6 @@ class TestAsyncSnapBuildBehaviourFetchService( without populating `proxy_url` and `revocation_endpoint`. """ self.pushConfig("builddmaster", fetch_service_host=None) - self.useFixture( - FeatureFixture({SNAP_USE_FETCH_SERVICE_FEATURE_FLAG: "on"}) - ) snap = self.factory.makeSnap(use_fetch_service=True) request = self.factory.makeSnapBuildRequest(snap=snap) job = self.makeJob(snap=snap, build_request=request) @@ -314,9 +310,6 @@ class TestAsyncSnapBuildBehaviourFetchService( the function raises a `CannotBuild` error. """ self.pushConfig("builddmaster", fetch_service_mitm_certificate=None) - self.useFixture( - FeatureFixture({SNAP_USE_FETCH_SERVICE_FEATURE_FLAG: "on"}) - ) snap = self.factory.makeSnap(use_fetch_service=True) request = self.factory.makeSnapBuildRequest(snap=snap) @@ -338,9 +331,6 @@ class TestAsyncSnapBuildBehaviourFetchService( self.pushConfig( "builddmaster", fetch_service_control_admin_secret=None ) - self.useFixture( - FeatureFixture({SNAP_USE_FETCH_SERVICE_FEATURE_FLAG: "on"}) - ) snap = self.factory.makeSnap(use_fetch_service=True) request = self.factory.makeSnapBuildRequest(snap=snap) job = self.makeJob(snap=snap, build_request=request) @@ -357,9 +347,6 @@ class TestAsyncSnapBuildBehaviourFetchService( `proxy_url` and `revocation_endpoint` are correctly populated. """ - self.useFixture( - FeatureFixture({SNAP_USE_FETCH_SERVICE_FEATURE_FLAG: "on"}) - ) snap = self.factory.makeSnap(use_fetch_service=True) request = self.factory.makeSnapBuildRequest(snap=snap) job = self.makeJob(snap=snap, build_request=request) @@ -414,9 +401,6 @@ class TestAsyncSnapBuildBehaviourFetchService( `proxy_url` and `revocation_endpoint` are correctly populated. """ - self.useFixture( - FeatureFixture({SNAP_USE_FETCH_SERVICE_FEATURE_FLAG: "on"}) - ) snap = self.factory.makeSnap( use_fetch_service=True, fetch_service_policy=FetchServicePolicy.PERMISSIVE, @@ -468,25 +452,9 @@ class TestAsyncSnapBuildBehaviourFetchService( ) @defer.inlineCallbacks - def test_requestFetchServiceSession_flag_off(self): - """Create a snap build request turning off the feature flag.""" - self.useFixture( - FeatureFixture({SNAP_USE_FETCH_SERVICE_FEATURE_FLAG: None}) - ) - snap = self.factory.makeSnap(use_fetch_service=True) - request = self.factory.makeSnapBuildRequest(snap=snap) - job = self.makeJob(snap=snap, build_request=request) - yield job.extraBuildArgs() - self.assertEqual([], self.fetch_service_api.sessions.requests) - - @defer.inlineCallbacks def test_requestFetchServiceSession_mitm_certficate_redacted(self): """The `fetch_service_mitm_certificate` field in the build arguments is redacted in the build logs.""" - - self.useFixture( - FeatureFixture({SNAP_USE_FETCH_SERVICE_FEATURE_FLAG: "on"}) - ) snap = self.factory.makeSnap(use_fetch_service=True) request = self.factory.makeSnapBuildRequest(snap=snap) job = self.makeJob(snap=snap, build_request=request) @@ -524,9 +492,6 @@ class TestAsyncSnapBuildBehaviourFetchService( fetch service and saved to a file; and call to end the session and removing resources are made. """ - self.useFixture( - FeatureFixture({SNAP_USE_FETCH_SERVICE_FEATURE_FLAG: "on"}) - ) tem_upload_path = self.useFixture(fixtures.TempDir()).path snap = self.factory.makeSnap(use_fetch_service=True) @@ -594,9 +559,6 @@ class TestAsyncSnapBuildBehaviourFetchService( def test_endProxySession_fetch_Service_false(self): """When `use_fetch_service` is False, we don't make any calls to the fetch service API.""" - self.useFixture( - FeatureFixture({SNAP_USE_FETCH_SERVICE_FEATURE_FLAG: "on"}) - ) snap = self.factory.makeSnap(use_fetch_service=False) request = self.factory.makeSnapBuildRequest(snap=snap) job = self.makeJob(snap=snap, build_request=request) @@ -619,9 +581,6 @@ class TestAsyncSnapBuildBehaviourFetchService( """When `allow_internet` is False, we don't send proxy variables to the buildd, and ending the session does not make calls to the fetch service.""" - self.useFixture( - FeatureFixture({SNAP_USE_FETCH_SERVICE_FEATURE_FLAG: "on"}) - ) snap = self.factory.makeSnap(allow_internet=False) request = self.factory.makeSnapBuildRequest(snap=snap) job = self.makeJob(snap=snap, build_request=request) @@ -631,7 +590,7 @@ class TestAsyncSnapBuildBehaviourFetchService( job._worker.proxy_info = MagicMock( return_value={ "revocation_endpoint": None, - "use_fetch_service": None, + "use_fetch_service": False, } ) @@ -803,10 +762,6 @@ class TestAsyncSnapBuildBehaviourBuilderProxy( with dbuser(config.builddmaster.dbuser): args = yield job.extraBuildArgs() - # XXX ines-almeida 2024-04-26: use_fetch_service is `None` because we - # are not setting the fetch-service feature flag 'ON' for these tests - # (since that's not the point of these test). Once we remove the - # feature flag, this will either be True or False - not None. self.assertThat( args, MatchesDict( @@ -828,7 +783,7 @@ class TestAsyncSnapBuildBehaviourBuilderProxy( "series": Equals("unstable"), "trusted_keys": Equals(expected_trusted_keys), "target_architectures": Equals(["i386"]), - "use_fetch_service": Is(None), + "use_fetch_service": Is(False), "launchpad_instance": Equals("devel"), "launchpad_server_url": Equals("launchpad.test"), } @@ -884,7 +839,7 @@ class TestAsyncSnapBuildBehaviourBuilderProxy( "series": Equals("unstable"), "trusted_keys": Equals(expected_trusted_keys), "target_architectures": Equals(["i386"]), - "use_fetch_service": Is(None), + "use_fetch_service": Is(False), "launchpad_instance": Equals("devel"), "launchpad_server_url": Equals("launchpad.test"), } @@ -929,7 +884,7 @@ class TestAsyncSnapBuildBehaviourBuilderProxy( "series": Equals("unstable"), "trusted_keys": Equals(expected_trusted_keys), "target_architectures": Equals(["i386"]), - "use_fetch_service": Is(None), + "use_fetch_service": Is(False), "launchpad_instance": Equals("devel"), "launchpad_server_url": Equals("launchpad.test"), } @@ -1005,7 +960,7 @@ class TestAsyncSnapBuildBehaviourBuilderProxy( "series": Equals("unstable"), "trusted_keys": Equals(expected_trusted_keys), "target_architectures": Equals(["i386"]), - "use_fetch_service": Is(None), + "use_fetch_service": Is(False), "launchpad_instance": Equals("devel"), "launchpad_server_url": Equals("launchpad.test"), } @@ -1053,7 +1008,7 @@ class TestAsyncSnapBuildBehaviourBuilderProxy( "series": Equals("unstable"), "trusted_keys": Equals(expected_trusted_keys), "target_architectures": Equals(["i386"]), - "use_fetch_service": Is(None), + "use_fetch_service": Is(False), "launchpad_instance": Equals("devel"), "launchpad_server_url": Equals("launchpad.test"), } @@ -1098,7 +1053,7 @@ class TestAsyncSnapBuildBehaviourBuilderProxy( "series": Equals("unstable"), "trusted_keys": Equals(expected_trusted_keys), "target_architectures": Equals(["i386"]), - "use_fetch_service": Is(None), + "use_fetch_service": Is(False), "launchpad_instance": Equals("devel"), "launchpad_server_url": Equals("launchpad.test"), }
_______________________________________________ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp