diff --git a/NEWS.md b/NEWS.md index 81ffaf47638..fd905078031 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,8 +1,10 @@ # New in snapd 2.74.1 * FDE: measure DeployedMode and AuditMode variables if they appear as disabled in the event log to avoid a potential reseal-failure boot loop +* LP: #2141328 FDE: reuse preinstall check context during install to account for user-ignored errors * LP: #2139611 FDE: fix db updates by allowing multiple payloads * LP: #2139300 snap-confine: add CAP_SYS_RESOURCE to allow raising memory lock limit when required * LP: #2139099 snap-confine: bump the max element count of the BPF map used to store IDs of allowed/matched devices to 1000 +* LP: #2141607 Desktop: revert change that caused user daemons declaring the desktop plug to implicitly depend on graphical-session.target * Interfaces: Added pidfd_open and memfd_secret to seccomp template * Interfaces: camera | add locking permission for /dev/video diff --git a/mkversion.sh b/mkversion.sh index e2cca63c53d..50409d28986 100755 --- a/mkversion.sh +++ b/mkversion.sh @@ -65,7 +65,12 @@ fi # switch to the real source dir for the changelog parsing : "${DPKG_PARSECHANGELOG=$(command -v dpkg-parsechangelog)}" if [ -n "$DPKG_PARSECHANGELOG" ]; then - version_from_changelog="$(cd "$PKG_BUILDDIR"; "$DPKG_PARSECHANGELOG" --file packaging/ubuntu-16.04/changelog --show-field Version)"; + + changelog=debian/changelog + if [ ! -e "$changelog" ]; then + changelog=packaging/ubuntu-16.04/changelog + fi + version_from_changelog="$(cd "$PKG_BUILDDIR" && "$DPKG_PARSECHANGELOG" --file "$changelog" --show-field Version)" fi # select version based on priority diff --git a/overlord/devicestate/devicestate_install_api_test.go b/overlord/devicestate/devicestate_install_api_test.go index 09f019ecc54..b07192481f4 100644 --- a/overlord/devicestate/devicestate_install_api_test.go +++ b/overlord/devicestate/devicestate_install_api_test.go @@ -864,7 +864,7 @@ func (s *deviceMgrInstallAPISuite) testInstallSetupStorageEncryption(c *C, isSup gadgetSnapPath, kernelSnapPath, _, ginfo, mountCmd, _ := s.mockSystemSeedWithLabel( c, label, seedCopyFn, seedOpts) - callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, isSupportedHybrid, hasTPM) + callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, isSupportedHybrid, hasTPM, label) // Mock encryption of partitions encrytpPartCalls := 0 @@ -934,7 +934,7 @@ func (s *deviceMgrInstallAPISuite) testInstallSetupStorageEncryption(c *C, isSup // ensure the expected encryption availability check was used if isSupportedHybrid { - c.Assert(callCnt, DeepEquals, &callCounter{checkCnt: 1, checkActionCnt: 0, sealingSupportedCnt: 0}) + c.Assert(callCnt, DeepEquals, &callCounter{checkCnt: 0, checkActionCnt: 1, sealingSupportedCnt: 0}) } else { c.Assert(callCnt, DeepEquals, &callCounter{checkCnt: 0, checkActionCnt: 0, sealingSupportedCnt: 1}) } @@ -1170,7 +1170,7 @@ func (s *deviceMgrInstallAPISuite) testInstallSetupStorageEncryptionPassphraseAu s.state.Lock() defer s.state.Unlock() - callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, true, true) + callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, true, true, "") restore := devicestate.MockInstallEncryptPartitions(func( onVolumes map[string]*gadget.Volume, diff --git a/overlord/devicestate/devicestate_install_mode_test.go b/overlord/devicestate/devicestate_install_mode_test.go index da05888645a..a218b7dc853 100644 --- a/overlord/devicestate/devicestate_install_mode_test.go +++ b/overlord/devicestate/devicestate_install_mode_test.go @@ -360,7 +360,7 @@ func (s *deviceMgrInstallModeSuite) SetUpTest(c *C) { }) s.AddCleanup(restore) - mockHelperForEncryptionAvailabilityCheck(s, c, false, false) + mockHelperForEncryptionAvailabilityCheck(s, c, false, false, "") s.state.Lock() defer s.state.Unlock() @@ -648,7 +648,7 @@ func (s *deviceMgrInstallModeSuite) doRunChangeTestWithEncryption(c *C, grade st }) defer restore() - callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, tc.tpm) + callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, tc.tpm, "") if tc.trustedBootloader { tab := bootloadertest.Mock("trusted", bootloaderRootdir).WithTrustedAssets() @@ -1781,7 +1781,7 @@ func (s *deviceMgrInstallModeSuite) TestInstallBootloaderVarSetFails(c *C) { }) defer restore() - callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, false) + callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, false, "") err := os.WriteFile(filepath.Join(dirs.GlobalRootDir, "/var/lib/snapd/modeenv"), []byte("mode=install\nrecovery_system=1234"), 0644) @@ -1823,7 +1823,7 @@ func (s *deviceMgrInstallModeSuite) testInstallEncryptionValidityChecks(c *C, er restore := release.MockOnClassic(false) defer restore() - callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, true) + callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, true, "") err := os.WriteFile(filepath.Join(dirs.GlobalRootDir, "/var/lib/snapd/modeenv"), []byte("mode=install\n"), 0644) @@ -2010,7 +2010,7 @@ func (s *deviceMgrInstallModeSuite) TestInstallWithEncryptionValidatesGadgetErr( defer restore() // pretend we have a TPM - callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, true) + callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, true, "") // must be a model that requires encryption to error s.testInstallGadgetNoSave(c, "secured") @@ -2041,7 +2041,7 @@ func (s *deviceMgrInstallModeSuite) TestInstallWithEncryptionValidatesGadgetWarn defer restore() // pretend we have a TPM - callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, true) + callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, true, "") s.testInstallGadgetNoSave(c, "dangerous") @@ -2067,7 +2067,7 @@ func (s *deviceMgrInstallModeSuite) TestInstallWithoutEncryptionValidatesGadgetW defer restore() // pretend we have a TPM - callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, true) + callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, true, "") s.testInstallGadgetNoSave(c, "dangerous") @@ -2146,7 +2146,7 @@ func (s *deviceMgrInstallModeSuite) TestInstallCheckEncrypted(c *C) { makeInstalledMockKernelSnap(c, st, kernelYamlNoFdeSetup) } - callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, tc.hasTPM) + callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, tc.hasTPM, "") encryptionType, err := devicestate.DeviceManagerCheckEncryption(s.mgr, st, deviceCtx, secboot.TPMProvisionFull) c.Assert(callCnt.checkCnt, Equals, 0) @@ -2314,7 +2314,7 @@ func (s *deviceMgrInstallModeSuite) doRunFactoryResetChange(c *C, model *asserts }) defer restore() - callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, tc.tpm) + callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, tc.tpm, "") if tc.trustedBootloader { tab := bootloadertest.Mock("trusted", bootloaderRootdir).WithTrustedAssets() @@ -3135,7 +3135,7 @@ func (s *deviceMgrInstallModeSuite) TestFactoryResetExpectedTasks(c *C) { restore := release.MockOnClassic(false) defer restore() - callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, false) + callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, false, "") restore = devicestate.MockInstallFactoryReset(func(mod gadget.Model, gadgetRoot string, kernelSnapInfo *install.KernelSnapInfo, device string, options install.Options, obs gadget.ContentObserver, pertTimings timings.Measurer) (*install.InstalledSystemSideData, error) { c.Assert(os.MkdirAll(dirs.SnapDeviceDirUnder(filepath.Join(dirs.GlobalRootDir, "/run/mnt/ubuntu-data/system-data")), 0755), IsNil) @@ -3207,7 +3207,7 @@ func (s *deviceMgrInstallModeSuite) TestFactoryResetInstallDeviceHook(c *C) { restore := release.MockOnClassic(false) defer restore() - callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, false) + callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, false, "") hooksCalled := []*hookstate.Context{} restore = hookstate.MockRunHook(func(ctx *hookstate.Context, tomb *tomb.Tomb) ([]byte, error) { diff --git a/overlord/devicestate/devicestate_systems_test.go b/overlord/devicestate/devicestate_systems_test.go index 0e98df941be..d58f9ef35c6 100644 --- a/overlord/devicestate/devicestate_systems_test.go +++ b/overlord/devicestate/devicestate_systems_test.go @@ -2983,6 +2983,7 @@ var preinstallAction = &secboot.PreinstallAction{ type suiteWithAddCleanup interface { AddCleanup(func()) + DeviceManager() *devicestate.DeviceManager } type callCounter struct { @@ -2998,7 +2999,8 @@ type callCounter struct { // // isSupportedUbuntuHybrid: modify system release information and place current boot images to simulate supported Ubuntu hybrid install // hasTPM: indicates if we should simulate having a TPM (no error detected) or no TPM (some representative error) -func mockHelperForEncryptionAvailabilityCheck(s suiteWithAddCleanup, c *C, isSupportedUbuntuHybrid, hasTPM bool) *callCounter { +// cacheLabel: system label to use to cache check context where "" means do not cache check context +func mockHelperForEncryptionAvailabilityCheck(s suiteWithAddCleanup, c *C, isSupportedUbuntuHybrid, hasTPM bool, cacheLabel string) *callCounter { callCnt := &callCounter{} releaseInfo := &release.OS{ @@ -3035,6 +3037,21 @@ func mockHelperForEncryptionAvailabilityCheck(s suiteWithAddCleanup, c *C, isSup } } + if cacheLabel != "" { + // populate the cache with encryption support information that + // mimics what would happen when a preinstall check takes place + // as per usual installer flow + encInfo := &install.EncryptionSupportInfo{} + if isSupportedUbuntuHybrid { + // hybrid installation flow populates the preinstall check context + encInfo.SetAvailabilityCheckContext(&secboot.PreinstallCheckContext{}) + } + // non-hydrid install flow uses the simple availability check that does not produce + // a preinstall check context + + s.DeviceManager().SetEncryptionSupportInfoInCacheUnlocked(cacheLabel, encInfo) + } + restore := install.MockSecbootPreinstallCheck(func(ctx context.Context, bootImagePaths []string) (*secboot.PreinstallCheckContext, []secboot.PreinstallErrorDetails, error) { callCnt.checkCnt++ c.Assert(bootImagePaths, HasLen, 3) @@ -3051,7 +3068,11 @@ func mockHelperForEncryptionAvailabilityCheck(s suiteWithAddCleanup, c *C, isSup callCnt.checkActionCnt++ c.Assert(pcc, NotNil) c.Assert(ctx, NotNil) - c.Assert(action, DeepEquals, preinstallAction) + if cacheLabel != "" { + c.Assert(action, DeepEquals, &secboot.PreinstallAction{Action: secboot.ActionNone}) + } else { + c.Assert(action, DeepEquals, preinstallAction) + } c.Assert(isSupportedUbuntuHybrid, Equals, true) if hasTPM { @@ -3160,7 +3181,7 @@ func (s *modelAndGadgetInfoSuite) TestSystemAndGadgetAndEncryptionInfoNotSupport UnavailableWarning: "not encrypting device storage as checking TPM gave: cannot connect to TPM device", } - callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, isSupportedHybrid, false) + callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, isSupportedHybrid, false, "") // basic availability check - fill empty info cache encInfoFromCache := false @@ -3211,7 +3232,7 @@ func (s *modelAndGadgetInfoSuite) TestSystemAndGadgetAndEncryptionInfoSupportedH } expectedEncInfo.SetAvailabilityCheckContext(preinstallCheckContext) - callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, isSupportedHybrid, false) + callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, isSupportedHybrid, false, "") // comprehensive preinstall check - fill empty info cache encInfoFromCache := false @@ -3298,7 +3319,7 @@ func (s *modelAndGadgetInfoSuite) testSystemAndGadgetAndEncryptionInfoPassphrase PassphraseAuthAvailable: hasPassphraseSupport, } - callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, true) + callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, false, true, "") // refresh empty cache encInfoFromCache := false @@ -3431,7 +3452,7 @@ func (s *modelAndGadgetInfoSuite) TestSystemAndGadgetInfoBadClassicGadget(c *C) isClassic := true s.makeMockUC20SeedWithGadgetYaml(c, "some-label", mockGadgetUCYamlNoBootRole, isClassic, nil) - callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, true, true) + callCnt := mockHelperForEncryptionAvailabilityCheck(s, c, true, true, "") _, _, _, err := s.mgr.SystemAndGadgetAndEncryptionInfo("some-label", false) c.Assert(callCnt, DeepEquals, &callCounter{checkCnt: 1, checkActionCnt: 0, sealingSupportedCnt: 0}) diff --git a/overlord/devicestate/devicestate_test.go b/overlord/devicestate/devicestate_test.go index efd6cb3e1d9..7ef7c2f60af 100644 --- a/overlord/devicestate/devicestate_test.go +++ b/overlord/devicestate/devicestate_test.go @@ -510,6 +510,10 @@ func (s *deviceMgrBaseSuite) addKeyToManagerInState(c *C) { c.Assert(err, IsNil) } +func (s *deviceMgrBaseSuite) DeviceManager() *devicestate.DeviceManager { + return s.mgr +} + func (s *deviceMgrSuite) SetUpTest(c *C) { classic := false s.setupBaseTest(c, classic) diff --git a/overlord/devicestate/handlers_install.go b/overlord/devicestate/handlers_install.go index abd266a8130..ef0da4d0dd6 100644 --- a/overlord/devicestate/handlers_install.go +++ b/overlord/devicestate/handlers_install.go @@ -1370,12 +1370,24 @@ func (m *DeviceManager) doInstallSetupStorageEncryption(t *state.Task, _ *tomb.T return fmt.Errorf("reading gadget information: %v", err) } + var checkAction *secboot.PreinstallAction + cachedEncInfo := m.readCacheEncryptionSupportInfoLocked(systemLabel) + + if cachedEncInfo != nil && cachedEncInfo.CheckContext() != nil { + // If a cached context is available, the preinstall check was previously run + // and must be repeated. Set an action to signal reuse of the preinstall check + // context. Use the inert "ActionNone" to repeat the check without requesting + // any modifications. + checkAction = &secboot.PreinstallAction{Action: secboot.ActionNone} + } + constraints := installLogic.EncryptionConstraints{ Model: systemAndSeeds.Model, Kernel: systemAndSeeds.InfosByType[snap.TypeKernel], Gadget: gadgetInfo, TPMMode: secboot.TPMProvisionFull, SnapdVersions: systemAndSeeds.SystemSnapdVersions, + CheckAction: checkAction, } // do not use cached encryption information; perform a fresh encryption diff --git a/packaging/debian-sid/changelog b/packaging/debian-sid/changelog index 1a6122f1b89..ec86317f0a2 100644 --- a/packaging/debian-sid/changelog +++ b/packaging/debian-sid/changelog @@ -4,15 +4,20 @@ snapd (2.74.1-1) unstable; urgency=medium - FDE: measure DeployedMode and AuditMode variables if they appear as disabled in the event log to avoid a potential reseal-failure boot loop + - LP: #2141328 FDE: reuse preinstall check context during install to + account for user-ignored errors - LP: #2139611 FDE: fix db updates by allowing multiple payloads - LP: #2139300 snap-confine: add CAP_SYS_RESOURCE to allow raising memory lock limit when required - LP: #2139099 snap-confine: bump the max element count of the BPF map used to store IDs of allowed/matched devices to 1000 + - LP: #2141607 Desktop: revert change that caused user daemons + declaring the desktop plug to implicitly depend on graphical- + session.target - Interfaces: Added pidfd_open and memfd_secret to seccomp template - Interfaces: camera | add locking permission for /dev/video - -- Ernest Lotter Fri, 06 Feb 2026 19:40:03 +0200 + -- Ernest Lotter Thu, 12 Feb 2026 21:27:23 +0200 snapd (2.74-1) unstable; urgency=medium diff --git a/packaging/fedora/snapd.spec b/packaging/fedora/snapd.spec index fb8250669e8..d9b5525ef38 100644 --- a/packaging/fedora/snapd.spec +++ b/packaging/fedora/snapd.spec @@ -1008,16 +1008,21 @@ fi %endif %changelog -* Fri Feb 06 2026 Ernest Lotter +* Thu Feb 12 2026 Ernest Lotter - New upstream release 2.74.1 - FDE: measure DeployedMode and AuditMode variables if they appear as disabled in the event log to avoid a potential reseal-failure boot loop + - LP: #2141328 FDE: reuse preinstall check context during install to + account for user-ignored errors - LP: #2139611 FDE: fix db updates by allowing multiple payloads - LP: #2139300 snap-confine: add CAP_SYS_RESOURCE to allow raising memory lock limit when required - LP: #2139099 snap-confine: bump the max element count of the BPF map used to store IDs of allowed/matched devices to 1000 + - LP: #2141607 Desktop: revert change that caused user daemons + declaring the desktop plug to implicitly depend on graphical- + session.target - Interfaces: Added pidfd_open and memfd_secret to seccomp template - Interfaces: camera | add locking permission for /dev/video diff --git a/packaging/opensuse/snapd.changes b/packaging/opensuse/snapd.changes index fff0026fc32..37ca1e30e10 100644 --- a/packaging/opensuse/snapd.changes +++ b/packaging/opensuse/snapd.changes @@ -1,5 +1,5 @@ ------------------------------------------------------------------- -Fri Feb 06 17:40:03 UTC 2026 - ernest.lotter@canonical.com +Thu Feb 12 19:27:23 UTC 2026 - ernest.lotter@canonical.com - Update to upstream release 2.74.1 diff --git a/packaging/ubuntu-16.04/changelog b/packaging/ubuntu-16.04/changelog index 146fad28acb..3b92f0bb7e2 100644 --- a/packaging/ubuntu-16.04/changelog +++ b/packaging/ubuntu-16.04/changelog @@ -4,15 +4,20 @@ snapd (2.74.1) xenial; urgency=medium - FDE: measure DeployedMode and AuditMode variables if they appear as disabled in the event log to avoid a potential reseal-failure boot loop + - LP: #2141328 FDE: reuse preinstall check context during install to + account for user-ignored errors - LP: #2139611 FDE: fix db updates by allowing multiple payloads - LP: #2139300 snap-confine: add CAP_SYS_RESOURCE to allow raising memory lock limit when required - LP: #2139099 snap-confine: bump the max element count of the BPF map used to store IDs of allowed/matched devices to 1000 + - LP: #2141607 Desktop: revert change that caused user daemons + declaring the desktop plug to implicitly depend on graphical- + session.target - Interfaces: Added pidfd_open and memfd_secret to seccomp template - Interfaces: camera | add locking permission for /dev/video - -- Ernest Lotter Fri, 06 Feb 2026 19:40:03 +0200 + -- Ernest Lotter Thu, 12 Feb 2026 21:27:23 +0200 snapd (2.74) xenial; urgency=medium diff --git a/secboot/preinstall_nosb.go b/secboot/preinstall_nosb.go index 4fc86a61956..383c8f1b4cc 100644 --- a/secboot/preinstall_nosb.go +++ b/secboot/preinstall_nosb.go @@ -27,6 +27,8 @@ import ( type PreinstallCheckContext struct{} type PreinstallCheckResult struct{} +const ActionNone = "" + func PreinstallCheck(ctx context.Context, bootImagePaths []string) (*PreinstallCheckContext, []PreinstallErrorDetails, error) { return nil, nil, errBuildWithoutSecboot } diff --git a/secboot/preinstall_sb.go b/secboot/preinstall_sb.go index f648ab88289..ec7e4645b9a 100644 --- a/secboot/preinstall_sb.go +++ b/secboot/preinstall_sb.go @@ -61,6 +61,8 @@ var ( sbPreinstallRunChecks = (*sb_preinstall.RunChecksContext).Run ) +const ActionNone = string(sb_preinstall.ActionNone) + // PreinstallCheck runs preinstall checks using default check configuration and // TCG-compliant PCR profile generation options to evaluate whether the host // environment is an EFI system suitable for TPM-based Full Disk Encryption. The diff --git a/snap/info.go b/snap/info.go index e85080cc9e8..6c9db33aecb 100644 --- a/snap/info.go +++ b/snap/info.go @@ -1356,23 +1356,14 @@ type AppInfo struct { // list of other service names that this service will start after or // before - After []string - Before []string - BindsTo []string - PartOf []string - Requisite []string + After []string + Before []string Timer *TimerInfo Autostart string } -// HasPlug returns true if this AppInfo has the requested plug. -func (app *AppInfo) HasPlug(plug string) bool { - _, ok := app.Plugs[plug] - return ok -} - // Runnable returns a Runnable for this app. func (app *AppInfo) Runnable() Runnable { return Runnable{ diff --git a/snap/info_test.go b/snap/info_test.go index d11f11dec07..967e7a896a9 100644 --- a/snap/info_test.go +++ b/snap/info_test.go @@ -2318,10 +2318,6 @@ plugs: unscopedApps := info.AppsForPlug(unscoped) c.Assert(unscopedApps, testutil.DeepUnsortedMatches, []*snap.AppInfo{info.Apps["one"], info.Apps["two"]}) - - appInfo := info.Apps["one"] - c.Assert(appInfo.HasPlug("scoped-plug"), Equals, true) - c.Assert(appInfo.HasPlug("non-existing-plug"), Equals, false) } func (s *infoSuite) TestAppsForSlot(c *C) { diff --git a/tests/lib/external/snapd-testing-tools/remote/remote.wait-for b/tests/lib/external/snapd-testing-tools/remote/remote.wait-for index 5e4cffedc01..883d924a3e2 100755 --- a/tests/lib/external/snapd-testing-tools/remote/remote.wait-for +++ b/tests/lib/external/snapd-testing-tools/remote/remote.wait-for @@ -91,7 +91,7 @@ get_boot_id() { } wait_for_reconnect_ssh() { - echo "remote.wait-for: waiting for ssh to reconnect" + echo "remote.wait-for: waiting for ssh to be reconnected" wait_for_no_ssh "$DEFAULT_WAIT_FOR_NO_SSH_ATTEMPTS" "$DEFAULT_WAIT_FOR_NO_SSH_WAIT" wait_for_ssh "$DEFAULT_WAIT_FOR_SSH_ATTEMPTS" "$DEFAULT_WAIT_FOR_SSH_WAIT" } @@ -123,7 +123,7 @@ wait_for_reboot() { done echo "" - if [ "$last_boot_id" != "$initial_boot_id" ]; then + if [[ "$last_boot_id" =~ .*-.*-.*-.*-.* ]] && [ "$last_boot_id" != "$initial_boot_id" ]; then echo "remote.wait-for: reboot completed" else echo "remote.wait-for: boot id did not change" diff --git a/tests/lib/external/snapd-testing-tools/spread.yaml b/tests/lib/external/snapd-testing-tools/spread.yaml index a75fea7dd80..e6e5a6d346d 100644 --- a/tests/lib/external/snapd-testing-tools/spread.yaml +++ b/tests/lib/external/snapd-testing-tools/spread.yaml @@ -15,6 +15,7 @@ backends: - ubuntu-18.04-64: - ubuntu-20.04-64: image: ubuntu-2004-64 + storage: 16G - ubuntu-22.04-64: image: ubuntu-2204-64 - ubuntu-24.04-64: @@ -142,6 +143,31 @@ suites: tests/: summary: Main test suite for snapd-testing-tools project prepare: | + # setup snapd proxy if needed + if [ "${SNAPD_USE_PROXY:-}" = true ] && [ -n "$(command -v snap)" ]; then + mkdir -p /etc/systemd/system/snapd.service.d + PROXY_CONF=/etc/systemd/system/snapd.service.d/proxy.conf + { + echo "[Service]" + echo "Environment=HTTPS_PROXY=$HTTPS_PROXY HTTP_PROXY=$HTTP_PROXY https_proxy=$HTTPS_PROXY http_proxy=$HTTP_PROXY NO_PROXY=$NO_PROXY no_proxy=$NO_PROXY" + } >> "$PROXY_CONF" + + systemctl daemon-reload + systemctl restart snapd.service + fi + + # setup system proxy if needed + if [ -n "${HTTPS_PROXY:-}" ]; then + { + echo "HTTPS_PROXY=$HTTPS_PROXY" + echo "HTTP_PROXY=$HTTP_PROXY" + echo "https_proxy=$HTTPS_PROXY" + echo "http_proxy=$HTTP_PROXY" + echo "NO_PROXY=$NO_PROXY" + echo "no_proxy=$NO_PROXY" + } >> /etc/environment + fi + echo "Preparing snapd-testing-tools main suite" # Create users for the tests useradd -m tools-user-1 diff --git a/tests/lib/external/snapd-testing-tools/tests/check-test-format/task.yaml b/tests/lib/external/snapd-testing-tools/tests/check-test-format/task.yaml index c421e818359..99ca13e5faa 100644 --- a/tests/lib/external/snapd-testing-tools/tests/check-test-format/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/check-test-format/task.yaml @@ -4,9 +4,9 @@ details: | Verify that the check-test-format tool checks properly the desired order and mandatory keys in spread tasks. -backends: [google] +backends: [openstack] -systems: [ ubuntu-20.04-64 ] +systems: [ubuntu-22.04-64] prepare: | apt install -y python3-yamlordereddictloader diff --git a/tests/lib/external/snapd-testing-tools/tests/check-test-format/tasks/task3.yaml b/tests/lib/external/snapd-testing-tools/tests/check-test-format/tasks/task3.yaml index 55989a175d4..0386d0b9599 100644 --- a/tests/lib/external/snapd-testing-tools/tests/check-test-format/tasks/task3.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/check-test-format/tasks/task3.yaml @@ -2,6 +2,6 @@ summary: this is the summary details: details -systems: [ ubuntu-20.04-64 ] +systems: [ubuntu-22.04-64] backends: [ google ] diff --git a/tests/lib/external/snapd-testing-tools/tests/check-test-format/tasks/task4.yaml b/tests/lib/external/snapd-testing-tools/tests/check-test-format/tasks/task4.yaml index c712c79f503..9996e7a8b53 100644 --- a/tests/lib/external/snapd-testing-tools/tests/check-test-format/tasks/task4.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/check-test-format/tasks/task4.yaml @@ -3,6 +3,6 @@ summary: this is the summary environment: TEST: 1 -systems: [ ubuntu-20.04-64 ] +systems: [ubuntu-22.04-64] diff --git a/tests/lib/external/snapd-testing-tools/tests/check-test-format/tasks/task5.yaml b/tests/lib/external/snapd-testing-tools/tests/check-test-format/tasks/task5.yaml index ff45b068c14..fe08d118d8d 100644 --- a/tests/lib/external/snapd-testing-tools/tests/check-test-format/tasks/task5.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/check-test-format/tasks/task5.yaml @@ -4,7 +4,7 @@ details: details unsupported: not supported -systems: [ ubuntu-20.04-64 ] +systems: [ubuntu-22.04-64] execute: | echo "execute" diff --git a/tests/lib/external/snapd-testing-tools/tests/log-analyzer/task.yaml b/tests/lib/external/snapd-testing-tools/tests/log-analyzer/task.yaml index 8efc4897b15..93e3241d8f9 100644 --- a/tests/lib/external/snapd-testing-tools/tests/log-analyzer/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/log-analyzer/task.yaml @@ -5,7 +5,7 @@ details: | based on the spread log analysis. Also checks it properly retrieves the tests by result status and all the executed tasks. -backends: [google] +backends: [openstack] # Github actions agents are just running ubuntu jammy systems: [ubuntu-22.04-64] diff --git a/tests/lib/external/snapd-testing-tools/tests/log-filter/task.yaml b/tests/lib/external/snapd-testing-tools/tests/log-filter/task.yaml index 9d93d37c668..158b7e71f56 100644 --- a/tests/lib/external/snapd-testing-tools/tests/log-filter/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/log-filter/task.yaml @@ -5,7 +5,7 @@ details: | and filter the log following a set of rules. It is also checked that the output of the log-filter tool is the same than spread. -backends: [google] +backends: [openstack] # Github actions agents are just running ubuntu jammy systems: [ubuntu-22.04-64] diff --git a/tests/lib/external/snapd-testing-tools/tests/log-parser/task.yaml b/tests/lib/external/snapd-testing-tools/tests/log-parser/task.yaml index 39b9b4ca6a1..9dd1ccbb34e 100644 --- a/tests/lib/external/snapd-testing-tools/tests/log-parser/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/log-parser/task.yaml @@ -5,7 +5,7 @@ details: | logs and produce a json file with the logs info. This json file contains all the information from the log but structured in json format. -backends: [google] +backends: [openstack] # Github actions agents are just running ubuntu jammy systems: [ubuntu-22.04-64] diff --git a/tests/lib/external/snapd-testing-tools/tests/not/task.yaml b/tests/lib/external/snapd-testing-tools/tests/not/task.yaml index f48041d8d7a..a1686e4a540 100644 --- a/tests/lib/external/snapd-testing-tools/tests/not/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/not/task.yaml @@ -1,8 +1,9 @@ summary: test for the not tool +backends: [openstack] + details: | Check the not tool works the same as the logical not (!). - execute: | not false && echo test | MATCH test diff --git a/tests/lib/external/snapd-testing-tools/tests/os.paths/task.yaml b/tests/lib/external/snapd-testing-tools/tests/os.paths/task.yaml index e9f34449324..79485145ac1 100644 --- a/tests/lib/external/snapd-testing-tools/tests/os.paths/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/os.paths/task.yaml @@ -4,7 +4,7 @@ details: | Check the os.paths tool properly retrieves the snap-mount-dir, media-dir and libexec-dir in the current system. -backends: [google] +backends: [openstack] execute: | os.paths --help | MATCH 'usage: os.paths snap-mount-dir, media-dir, libexec-dir' diff --git a/tests/lib/external/snapd-testing-tools/tests/quiet/task.yaml b/tests/lib/external/snapd-testing-tools/tests/quiet/task.yaml index 23c7f51ca45..d5029afb3c6 100644 --- a/tests/lib/external/snapd-testing-tools/tests/quiet/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/quiet/task.yaml @@ -3,7 +3,7 @@ summary: test for the quiet tool details: | Check the quiet tool hides the command stdout and but shows the stderr -backends: [google] +backends: [openstack] execute: | quiet echo test | NOMATCH test diff --git a/tests/lib/external/snapd-testing-tools/tests/remote.exec/task.yaml b/tests/lib/external/snapd-testing-tools/tests/remote.exec/task.yaml index 249e8718c55..4e9c9ce3f24 100644 --- a/tests/lib/external/snapd-testing-tools/tests/remote.exec/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/remote.exec/task.yaml @@ -4,10 +4,9 @@ details: | Check the remote.exec tool is able to run commands in the remote instance through ssh. -backends: [google] +backends: [openstack] -# Amazon linux is skipped because no sshpass available -systems: [-amazon-linux-*] +systems: [ubuntu-22.04-64] prepare: | tests.pkgs install sshpass diff --git a/tests/lib/external/snapd-testing-tools/tests/remote.pull/task.yaml b/tests/lib/external/snapd-testing-tools/tests/remote.pull/task.yaml index 658add64e1c..a125c5655ea 100644 --- a/tests/lib/external/snapd-testing-tools/tests/remote.pull/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/remote.pull/task.yaml @@ -4,10 +4,9 @@ details: | Check the remote.pull tool is able to retrieve files from the remote instance through scp -backends: [google] +backends: [openstack] -# Amazon linux is skipped because no sshpass available -systems: [-amazon-linux-*] +systems: [ubuntu-22.04-64] prepare: | tests.pkgs install sshpass diff --git a/tests/lib/external/snapd-testing-tools/tests/remote.push/task.yaml b/tests/lib/external/snapd-testing-tools/tests/remote.push/task.yaml index 047e5cca070..ae4df3333f8 100644 --- a/tests/lib/external/snapd-testing-tools/tests/remote.push/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/remote.push/task.yaml @@ -4,10 +4,9 @@ details: | Check the remote.push tool is able to send files from localhost to the remote instance through scp -backends: [google] +backends: [openstack] -# Amazon linux is skipped because no sshpass available -systems: [-amazon-linux-*] +systems: [ubuntu-22.04-64] prepare: | tests.pkgs install sshpass diff --git a/tests/lib/external/snapd-testing-tools/tests/remote.refresh/task.yaml b/tests/lib/external/snapd-testing-tools/tests/remote.refresh/task.yaml index dcbdccfff86..a36170e3f68 100644 --- a/tests/lib/external/snapd-testing-tools/tests/remote.refresh/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/remote.refresh/task.yaml @@ -7,7 +7,7 @@ details: | backends: [google-nested] -systems: [ubuntu-20.04-64] +systems: [ubuntu-22.04-64] manual: true diff --git a/tests/lib/external/snapd-testing-tools/tests/remote.retry/task.yaml b/tests/lib/external/snapd-testing-tools/tests/remote.retry/task.yaml index 424714e7217..caf55edfaed 100644 --- a/tests/lib/external/snapd-testing-tools/tests/remote.retry/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/remote.retry/task.yaml @@ -5,10 +5,9 @@ details: | a command in the remote instance. Also verifies that on failure the exit code from the final attempt is returned. -backends: [google] +backends: [openstack] -# Amazon linux is skipped because no sshpass available -systems: [-amazon-linux-*] +systems: [ubuntu-22.04-64] prepare: | tests.pkgs install sshpass diff --git a/tests/lib/external/snapd-testing-tools/tests/remote.setup/task.yaml b/tests/lib/external/snapd-testing-tools/tests/remote.setup/task.yaml index 9ee820b8b02..a0195f3181c 100644 --- a/tests/lib/external/snapd-testing-tools/tests/remote.setup/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/remote.setup/task.yaml @@ -5,7 +5,9 @@ details: | information required to allow connecting to the remote instance through ssh. -backends: [google] +backends: [openstack] + +systems: [ubuntu-22.04-64] restore: | rm -f remote.setup.cfg my-key my-key-2 diff --git a/tests/lib/external/snapd-testing-tools/tests/remote.wait-for/task.yaml b/tests/lib/external/snapd-testing-tools/tests/remote.wait-for/task.yaml index 17e28b7d5b1..7de79817991 100644 --- a/tests/lib/external/snapd-testing-tools/tests/remote.wait-for/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/remote.wait-for/task.yaml @@ -7,7 +7,7 @@ details: | backends: [google-nested] -systems: [ubuntu-20.04-64] +systems: [ubuntu-22.04-64] manual: true diff --git a/tests/lib/external/snapd-testing-tools/tests/repack-kernel/task.yaml b/tests/lib/external/snapd-testing-tools/tests/repack-kernel/task.yaml index 86e210222a2..81a7356f633 100644 --- a/tests/lib/external/snapd-testing-tools/tests/repack-kernel/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/repack-kernel/task.yaml @@ -5,7 +5,7 @@ details: | kernel snap to a workspace directory, and then repacks it back to a snap -backends: [google] +backends: [openstack] # ubuntu-core-initramfs seems to be only available on ubuntu-20.04 systems: [ubuntu-20.04-64] diff --git a/tests/lib/external/snapd-testing-tools/tests/retry/task.yaml b/tests/lib/external/snapd-testing-tools/tests/retry/task.yaml index d0b329c2083..944e7a1c0e6 100644 --- a/tests/lib/external/snapd-testing-tools/tests/retry/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/retry/task.yaml @@ -4,7 +4,7 @@ details: | Check the retry tool allows retrying a command. Verify that on failure the exit code from the final attempt is returned -backends: [google] +backends: [openstack] execute: | # Retry runs the command that was passed as argument and returns the exit diff --git a/tests/lib/external/snapd-testing-tools/tests/snaps.cleanup/task.yaml b/tests/lib/external/snapd-testing-tools/tests/snaps.cleanup/task.yaml index 380c455bdb0..cea45da0f37 100644 --- a/tests/lib/external/snapd-testing-tools/tests/snaps.cleanup/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/snaps.cleanup/task.yaml @@ -5,7 +5,7 @@ details: | removal of the installed snaps in the current system. The test also verifies the fundamental snaps are not removed -backends: [google] +backends: [openstack] systems: [ubuntu-16.04-64, ubuntu-18.04-64, ubuntu-20.04-64, ubuntu-22.04-64] diff --git a/tests/lib/external/snapd-testing-tools/tests/snaps.name/task.yaml b/tests/lib/external/snapd-testing-tools/tests/snaps.name/task.yaml index 45e9deae1a9..ceb5efbddeb 100644 --- a/tests/lib/external/snapd-testing-tools/tests/snaps.name/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/snaps.name/task.yaml @@ -5,7 +5,7 @@ details: | gadget and kernel snaps installed in the system. Also verifies the snap-suffix command works properly. -backends: [google] +backends: [openstack] execute: | snaps.name --help | MATCH 'usage: snaps.name gadget, kernel, core' diff --git a/tests/lib/external/snapd-testing-tools/tests/spread-filter/task.yaml b/tests/lib/external/snapd-testing-tools/tests/spread-filter/task.yaml index 4c68576535e..0e9d53851d5 100644 --- a/tests/lib/external/snapd-testing-tools/tests/spread-filter/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/spread-filter/task.yaml @@ -5,7 +5,7 @@ details: | to execute, following the rules defined for the project and based on a set of changes. -backends: [google] +backends: [openstack] systems: [ubuntu-22.04-64] diff --git a/tests/lib/external/snapd-testing-tools/tests/spread-manager/task.yaml b/tests/lib/external/snapd-testing-tools/tests/spread-manager/task.yaml index 486711cd6f7..f154dbde472 100644 --- a/tests/lib/external/snapd-testing-tools/tests/spread-manager/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/spread-manager/task.yaml @@ -4,9 +4,9 @@ details: | Check the spread-manager tool allows setting a list of tests as manual. Also checks manual tag can be removed for a list of tests. -backends: [google] +backends: [openstack] -systems: [ ubuntu-20.04-64 ] +systems: [ubuntu-22.04-64] prepare: | wget -qO- wget https://storage.googleapis.com/snapd-spread-tests/spread/spread-amd64.tar.gz | tar xvz diff --git a/tests/lib/external/snapd-testing-tools/tests/spread-shellcheck/task.yaml b/tests/lib/external/snapd-testing-tools/tests/spread-shellcheck/task.yaml index bcbdb1ddfd7..17cbf6ad209 100644 --- a/tests/lib/external/snapd-testing-tools/tests/spread-shellcheck/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/spread-shellcheck/task.yaml @@ -6,9 +6,9 @@ details: | tool can run in a directory tree and skips checks when it finds "shellcheck disable". -backends: [google] +backends: [openstack] -systems: [ ubuntu-20.04-64 ] +systems: [ubuntu-22.04-64] prepare: | snap install shellcheck @@ -48,3 +48,7 @@ execute: | cp "$PWD/tasks/task4" "$PWD/tasks/task.yaml" spread-shellcheck "$PROJECT_PATH/tests" "$PWD/tasks/task.yaml" -e "$PWD/tasks" rm "$PWD/tasks/task.yaml" + + cp "$PWD/tasks/task5" "$PWD/tasks/task.yaml" + spread-shellcheck "$PWD/tasks" 2>&1 | MATCH "SC1035" + rm "$PWD/tasks/task.yaml" diff --git a/tests/lib/external/snapd-testing-tools/tests/spread-shellcheck/tasks/task5 b/tests/lib/external/snapd-testing-tools/tests/spread-shellcheck/tasks/task5 new file mode 100644 index 00000000000..0b7dd7bcafe --- /dev/null +++ b/tests/lib/external/snapd-testing-tools/tests/spread-shellcheck/tasks/task5 @@ -0,0 +1,20 @@ +summary: this is the summary + +skip: + - if: "false" + reason: not skipping + - if: | + ![ -z "something" ] + reason: skipping + +prepare: | + echo "preparing" + +restore: | + echo "restoring" + +debug: | + echo "debugging" + +execute: | + echo "executing" diff --git a/tests/lib/external/snapd-testing-tools/tests/tests.backup/task.yaml b/tests/lib/external/snapd-testing-tools/tests/tests.backup/task.yaml index 140abeb0add..7405869c82b 100644 --- a/tests/lib/external/snapd-testing-tools/tests/tests.backup/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/tests.backup/task.yaml @@ -4,7 +4,7 @@ details: | Check the tests.backup tool properly backs up and restores a specific directory. -backends: [google] +backends: [openstack] execute: | # Without any arguments a help message is printed. diff --git a/tests/lib/external/snapd-testing-tools/tests/tests.cleanup/task.yaml b/tests/lib/external/snapd-testing-tools/tests/tests.cleanup/task.yaml index d230365e713..1ac50a7b71b 100644 --- a/tests/lib/external/snapd-testing-tools/tests/tests.cleanup/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/tests.cleanup/task.yaml @@ -4,7 +4,7 @@ details: | Check the tests.cleanup tool allows to defer, pop and restore commands in tests. -backends: [google] +backends: [openstack] systems: [ubuntu-18.04-64] diff --git a/tests/lib/external/snapd-testing-tools/tests/tests.pkgs/task.yaml b/tests/lib/external/snapd-testing-tools/tests/tests.pkgs/task.yaml index 05e6b9f98ee..2b07f2deb93 100644 --- a/tests/lib/external/snapd-testing-tools/tests/tests.pkgs/task.yaml +++ b/tests/lib/external/snapd-testing-tools/tests/tests.pkgs/task.yaml @@ -5,7 +5,7 @@ details: | of the system being used. Verify that packages can be installed, queried and removed among other operations. -backends: [google] +backends: [openstack] execute: | if os.query is-core; then diff --git a/tests/lib/external/snapd-testing-tools/utils/spread-shellcheck b/tests/lib/external/snapd-testing-tools/utils/spread-shellcheck index 4769a7dc5da..d76c5e76ffd 100755 --- a/tests/lib/external/snapd-testing-tools/utils/spread-shellcheck +++ b/tests/lib/external/snapd-testing-tools/utils/spread-shellcheck @@ -29,44 +29,71 @@ from concurrent.futures import ThreadPoolExecutor from multiprocessing import cpu_count from pathlib import Path from threading import Lock -from typing import Dict +from typing import Dict, List # default shell for shellcheck -SHELLCHECK_SHELL = os.getenv('SHELLCHECK_SHELL', 'bash') +SHELLCHECK_SHELL = os.getenv("SHELLCHECK_SHELL", "bash") # set to non-empty to ignore all errors -NO_FAIL = os.getenv('NO_FAIL') +NO_FAIL = os.getenv("NO_FAIL") # set to non empty to enable 'set -x' -D = os.getenv('D') +D = os.getenv("D") # set to non-empty to enable verbose logging -V = os.getenv('V') +V = os.getenv("V") # set to a number to use these many threads -N = int(os.getenv('N') or cpu_count()) +N = int(os.getenv("N") or cpu_count()) # file with list of files that can fail validation -CAN_FAIL = os.getenv('CAN_FAIL') +CAN_FAIL = os.getenv("CAN_FAIL") # names of sections -SECTIONS = ['prepare', 'prepare-each', 'restore', 'restore-each', - 'debug', 'debug-each', 'execute', 'repack'] +SECTIONS: List[str] = [ + "prepare", + "prepare-each", + "restore", + "restore-each", + "debug", + "debug-each", + "execute", + "repack", + "skip", +] def parse_arguments(): - parser = argparse.ArgumentParser(description='spread shellcheck helper') - parser.add_argument('-s', '--shell', default='bash', - help='shell') - parser.add_argument('-n', '--no-errors', action='store_true', - default=False, help='ignore all errors ') - parser.add_argument('-v', '--verbose', action='store_true', - default=False, help='verbose logging') - parser.add_argument('--can-fail', default=None, - help=('file with list of files that are can fail ' - 'validation')) - parser.add_argument('-P', '--max-procs', default=N, type=int, metavar='N', - help='run these many shellchecks in parallel (default: %(default)s)') - parser.add_argument('-e', '--exclude', default=[], action="append", - help='path to exclude of the shell check') - parser.add_argument('--no-cache', help='disable caching', action='store_true') - parser.add_argument('paths', nargs='+', help='paths to check') + parser = argparse.ArgumentParser(description="spread shellcheck helper") + parser.add_argument("-s", "--shell", default="bash", help="shell") + parser.add_argument( + "-n", + "--no-errors", + action="store_true", + default=False, + help="ignore all errors ", + ) + parser.add_argument( + "-v", "--verbose", action="store_true", default=False, help="verbose logging" + ) + parser.add_argument( + "--can-fail", + default=None, + help=("file with list of files that are can fail " "validation"), + ) + parser.add_argument( + "-P", + "--max-procs", + default=N, + type=int, + metavar="N", + help="run these many shellchecks in parallel (default: %(default)s)", + ) + parser.add_argument( + "-e", + "--exclude", + default=[], + action="append", + help="path to exclude of the shell check", + ) + parser.add_argument("--no-cache", help="disable caching", action="store_true") + parser.add_argument("paths", nargs="+", help="paths to check") return parser.parse_args() @@ -112,30 +139,36 @@ class ShellcheckFailures(Exception): return iter(self.failures) +def iscomposite(section: str) -> bool: + return section == "skip" + + def checksection(data, env: Dict[str, str]): # spread shell snippets are executed under 'set -e' shell, make sure # shellcheck knows about that script_data = [] - script_data.append('set -e') + script_data.append("set -e") for key, value in env.items(): value = str(value) disabled_warnings = set() export_disabled_warnings = set() + def replacement(match): if match.group(0) == '"': # SC2089 and SC2090 are about quotes vs arrays # We cannot have arrays in environment variables of spread # So we do have to use quotes - disabled_warnings.add('SC2089') - export_disabled_warnings.add('SC2090') - return r'\"' + disabled_warnings.add("SC2089") + export_disabled_warnings.add("SC2090") + return r"\"" else: - assert(match.group('command') is not None) + assert match.group("command") is not None # "Useless" echo. This is what we get. # We cannot just evaluate to please shellcheck. - disabled_warnings.add('SC2116') - return '$({})'.format(match.group('command')) + disabled_warnings.add("SC2116") + return "$({})".format(match.group("command")) + value = re.sub(r'[$][(]HOST:(?P.*)[)]|"', replacement, value) # converts # FOO: "$(HOST: echo $foo)" -> FOO="$(echo $foo)" @@ -143,28 +176,48 @@ def checksection(data, env: Dict[str, str]): # FOO: "foo" -> FOO="foo" # FOO: "\"foo\"" -> FOO="\"foo\"" if disabled_warnings: - script_data.append("# shellcheck disable={}".format(','.join(disabled_warnings))) - script_data.append("{}=\"{}\"".format(key, value)) + script_data.append( + "# shellcheck disable={}".format(",".join(disabled_warnings)) + ) + script_data.append('{}="{}"'.format(key, value)) if export_disabled_warnings: - script_data.append("# shellcheck disable={}".format(','.join(export_disabled_warnings))) - script_data.append("export {}".format(key, value)) + script_data.append( + "# shellcheck disable={}".format(",".join(export_disabled_warnings)) + ) + script_data.append("export {}".format(key)) script_data.append(data) - proc = subprocess.Popen("shellcheck -s {} -x -".format(SHELLCHECK_SHELL), - stdout=subprocess.PIPE, - stdin=subprocess.PIPE, - shell=True) - stdout, _ = proc.communicate(input='\n'.join(script_data).encode('utf-8'), timeout=60) + proc = subprocess.Popen( + "shellcheck -s {} -x -".format(SHELLCHECK_SHELL), + stdout=subprocess.PIPE, + stdin=subprocess.PIPE, + shell=True, + ) + stdout, _ = proc.communicate( + input="\n".join(script_data).encode("utf-8"), timeout=60 + ) if proc.returncode != 0: raise ShellcheckRunError(stdout) +def checkcompositesection(compositesection: str, data, env): + if compositesection == "skip": + # skip data is a list of conditions + for entry in data: + if "if" not in entry: + continue + logging.debug("checking composite 'if' entry") + checksection(entry["if"], env) + else: + raise RuntimeError(f"unsupported composite section {compositesection}") + + class Cacher: _instance = None def __init__(self): self._enabled = True self._lock = Lock() - self._hit =0 + self._hit = 0 self._miss = 0 self._shellcheck_version = None self._probe_shellcheck_version() @@ -198,7 +251,9 @@ class Cacher: h.update(data) hdg = binascii.b2a_hex(h.digest()).decode() cachepath = Cacher._cache_path_for(hdg) - logging.debug("cache stamp %s, exists? %s", cachepath.as_posix(), cachepath.exists()) + logging.debug( + "cache stamp %s, exists? %s", cachepath.as_posix(), cachepath.exists() + ) hit = cachepath.exists() self._record_cache_event(hit) return hit, hdg @@ -225,12 +280,12 @@ class Cacher: @property def stats(self): - return namedtuple('Stats', ['hit', 'miss'])(self._hit, self._miss) + return namedtuple("Stats", ["hit", "miss"])(self._hit, self._miss) def checkfile(path, executor): logging.debug("checking file %s", path) - with open(path, mode='rb') as inf: + with open(path, mode="rb") as inf: rawdata = inf.read() cached, digest = Cacher.get().is_cached(rawdata, path) if cached: @@ -246,34 +301,51 @@ def checkfile(path, executor): for key, value in data.get("environment", {}).items(): if "/" in key: # TODO: re-check with each variant's value set. - key = key.split('/', 1)[0] + key = key.split("/", 1)[0] env[key] = value for section in SECTIONS: if section not in data: continue try: - logging.debug("%s: checking section %s", path, section) - checksection(data[section], env) + if not iscomposite(section): + logging.debug("%s: checking section %s", path, section) + checksection(data[section], env) + else: + logging.debug("%s: checking composite section %s", path, section) + checkcompositesection(section, data[section], env) except ShellcheckRunError as serr: - errors.addfailure(section, serr.stderr.decode('utf-8')) + errors.addfailure(section, serr.stderr.decode("utf-8")) - if path.endswith('spread.yaml') and 'suites' in data: + if path.endswith("spread.yaml") and "suites" in data: # check suites suites_sections_and_futures = [] - for suite in data['suites'].keys(): + for suite in data["suites"].keys(): for section in SECTIONS: - if section not in data['suites'][suite]: + if section not in data["suites"][suite]: continue - logging.debug("%s (suite %s): checking section %s", path, suite, section) - future = executor.submit(checksection, data['suites'][suite][section], env) + logging.debug( + "%s (suite %s): checking section %s", path, suite, section + ) + if not iscomposite(section): + future = executor.submit( + checksection, data["suites"][suite][section], env + ) + else: + future = executor.submit( + checkcompositesection, + section, + data["suites"][suite][section], + env, + ) suites_sections_and_futures.append((suite, section, future)) for item in suites_sections_and_futures: suite, section, future = item try: future.result() except ShellcheckRunError as serr: - errors.addfailure('suites/' + suite + '/' + section, - serr.stderr.decode('utf-8')) + errors.addfailure( + "suites/" + suite + "/" + section, serr.stderr.decode("utf-8") + ) if errors: raise errors @@ -283,8 +355,8 @@ def checkfile(path, executor): def is_file_in_dirs(file, dirs): for dir in dirs: - if os.path.abspath(file).startswith('{}/'.format(os.path.abspath(dir))): - print('Skipping {}'.format(file)) + if os.path.abspath(file).startswith("{}/".format(os.path.abspath(dir))): + print("Skipping {}".format(file)) return True return False @@ -295,7 +367,7 @@ def findfiles(locations, exclude): if os.path.isdir(loc): for root, _, files in os.walk(loc, topdown=True): for name in files: - if name in ['spread.yaml', 'task.yaml']: + if name in ["spread.yaml", "task.yaml"]: full_path = os.path.join(root, name) if not is_file_in_dirs(full_path, exclude): yield full_path @@ -320,9 +392,11 @@ def checkpaths(locs, exclude, executor): for serr in executor.map(check1path, locations, itertools.repeat(executor)): if serr is None: continue - logging.error(('shellcheck failed for file %s in sections: ' - '%s; error log follows'), - serr.path, ', '.join(serr.sectionerrors.keys())) + logging.error( + ("shellcheck failed for file %s in sections: " "%s; error log follows"), + serr.path, + ", ".join(serr.sectionerrors.keys()), + ) for section, error in serr.sectionerrors.items(): logging.error("%s: section '%s':\n%s", serr.path, section, error) failed.append(serr.path) @@ -335,13 +409,13 @@ def loadfilelist(flistpath): flist = set() with open(flistpath) as inf: for line in inf: - if not line.startswith('#'): + if not line.startswith("#"): flist.add(line.strip()) return flist def main(opts): - paths = opts.paths or ['.'] + paths = opts.paths or ["."] exclude = opts.exclude failures = ShellcheckFailures() with ThreadPoolExecutor(max_workers=opts.max_procs) as executor: @@ -360,25 +434,33 @@ def main(opts): unexpected = failures.difference(can_fail) if unexpected: - logging.error(('validation failed for the following ' - 'non-whitelisted files:\n%s'), - '\n'.join([' - ' + f for f in - sorted(unexpected)])) + logging.error( + ( + "validation failed for the following " + "non-whitelisted files:\n%s" + ), + "\n".join([" - " + f for f in sorted(unexpected)]), + ) raise SystemExit(1) did_not_fail = can_fail - failures.intersection(can_fail) if did_not_fail: - logging.error(('the following files are whitelisted ' - 'but validated successfully:\n%s'), - '\n'.join([' - ' + f for f in - sorted(did_not_fail)])) + logging.error( + ( + "the following files are whitelisted " + "but validated successfully:\n%s" + ), + "\n".join([" - " + f for f in sorted(did_not_fail)]), + ) raise SystemExit(1) # no unexpected failures return - logging.error('validation failed for the following files:\n%s', - '\n'.join([' - ' + f for f in sorted(failures)])) + logging.error( + "validation failed for the following files:\n%s", + "\n".join([" - " + f for f in sorted(failures)]), + ) if NO_FAIL or opts.no_errors: logging.warning("ignoring errors") @@ -386,7 +468,7 @@ def main(opts): raise SystemExit(1) -if __name__ == '__main__': +if __name__ == "__main__": opts = parse_arguments() if opts.verbose or D or V: lvl = logging.DEBUG @@ -404,7 +486,7 @@ if __name__ == '__main__': # TODO: temporary workaround for a deadlock when running with a single # worker opts.max_procs += 1 - logging.warning('workers count bumped to 2 to workaround a deadlock') + logging.warning("workers count bumped to 2 to workaround a deadlock") Cacher.init() if opts.no_cache: diff --git a/tests/lib/remodel-store-viewer.auth b/tests/lib/remodel-store-viewer.auth index 024282ed481..4201f511980 100644 --- a/tests/lib/remodel-store-viewer.auth +++ b/tests/lib/remodel-store-viewer.auth @@ -1 +1 @@ -eyJ0IjogInUxLW1hY2Fyb29uIiwgInYiOiB7InIiOiAiTURBeU9XeHZZMkYwYVc5dUlHMTVZWEJ3Y3k1a1pYWmxiRzl3WlhJdWRXSjFiblIxTG1OdmJRb3dNREUyYVdSbGJuUnBabWxsY2lCTmVVRndjSE1LTURBMFltTnBaQ0J0ZVdGd2NITXVaR1YyWld4dmNHVnlMblZpZFc1MGRTNWpiMjE4ZG1Gc2FXUmZjMmx1WTJWOE1qQXlOUzB3TWkwd05WUXhPRG95TnpveE5TNHdOVGd3TmpRS01ERTNaR05wWkNCN0luWmxjbk5wYjI0aU9pQXhMQ0FpYzJWamNtVjBJam9nSWxZeWVWQnhRMWxSZVVRemRVRnBWRzFNYTNkSFVtaDRabmR4Umtodk5Vd3dObE4xYVhBeE1YUmtNWEV6U0hKNlJTOUVNMGN3TTNBcmNGWmFSV2RsZFRKeFpYWkhiWGd3VUV4TU1VdGlSRzl4TlRsTWFtaDJZM3BwTmtjNVZIYzNaMk54ZUV0RVdHRnZWbFF4TlVZd1oxUmxWbFpNYjBGSlduZ3lTVU5hYTNOQ1YxaGFaRlF3ZWtrNGVIbGtWRmxPTlVWYU1rUlVNR2hMUzBoNWRraHNTRlo0TkVSV1NXRjNUV3ROZURWT2VtdGlWRWhuTUdOSFJEWlVaVFI0U2pGd2MycHhSakJwZEZvNFkzRmFWakl2ZEcxTlNXWTVRMU12T0hwbk5YcDBWRTVMTHpGYVRFNWtNa0Z4ZEdvM2VtMHhORWxXV0VGclJqSlVOeTgyZVVacVFXNDJXVTlEYjNWVGVUZzJhV2R4T1VWTFdXa3ZObWhyYkdoc1kwRklObEZKVm1KeGMyUlplSGMwWjFKU2FFSjBUVGQyVEZwS2FHNWFXblYxYm5kbWNrWlNjbWg1VmpkcFRucHFTazFXUkhCcWVrZGFTVWx3UVQwOUluMEtNREExTVhacFpDQ3FpblMwbEFjRlhsVlpUTEM4d0hQZDBSNTBmSGcyYldfMFVILWQ1SmtlQWRkejg1bVJYdGU1UTdhWVZWNWFKdFd5QVh0bEljVXhjWFV4Znc1a25UUVVaTHNCMHNoanhyTUtNREF4T0dOc0lHeHZaMmx1TG5WaWRXNTBkUzVqYjIwS01EQXpZbU5wWkNCdGVXRndjSE11WkdWMlpXeHZjR1Z5TG5WaWRXNTBkUzVqYjIxOFlXTnNmRnNpY0dGamEyRm5aVjloWTJObGMzTWlYUW93TURRM1kybGtJRzE1WVhCd2N5NWtaWFpsYkc5d1pYSXVkV0oxYm5SMUxtTnZiWHhsZUhCcGNtVnpmREl3TWpZdE1ESXRNRFZVTVRnNk1qYzZNVFF1TURBd01UYzJDakF3TW1aemFXZHVZWFIxY21VZzdwY2VxbnFYYTVWZDdfZXIycDM1NEJlaWlkOFJhZWN4UzNxUzFpdDBhbU1LIiwgImQiOiAiTURBeFpXeHZZMkYwYVc5dUlHeHZaMmx1TG5WaWRXNTBkUzVqYjIwS01ERTROR2xrWlc1MGFXWnBaWElnZXlKMlpYSnphVzl1SWpvZ01Td2dJbk5sWTNKbGRDSTZJQ0pXTW5sUWNVTlpVWGxFTTNWQmFWUnRUR3QzUjFKb2VHWjNjVVpJYnpWTU1EWlRkV2x3TVRGMFpERnhNMGh5ZWtVdlJETkhNRE53SzNCV1drVm5aWFV5Y1dWMlIyMTRNRkJNVERGTFlrUnZjVFU1VEdwb2RtTjZhVFpIT1ZSM04yZGpjWGhMUkZoaGIxWlVNVFZHTUdkVVpWWldURzlCU1ZwNE1rbERXbXR6UWxkWVdtUlVNSHBKT0hoNVpGUlpUalZGV2pKRVZEQm9TMHRJZVhaSWJFaFdlRFJFVmtsaGQwMXJUWGcxVG5wcllsUklaekJqUjBRMlZHVTBlRW94Y0hOcWNVWXdhWFJhT0dOeFdsWXlMM1J0VFVsbU9VTlRMemg2WnpWNmRGUk9TeTh4V2t4T1pESkJjWFJxTjNwdE1UUkpWbGhCYTBZeVZEY3ZObmxHYWtGdU5sbFBRMjkxVTNrNE5tbG5jVGxGUzFscEx6Wm9hMnhvYkdOQlNEWlJTVlppY1hOa1dYaDNOR2RTVW1oQ2RFMDNka3hhU21odVdscDFkVzUzWm5KR1VuSm9lVlkzYVU1NmFrcE5Wa1J3YW5wSFdrbEpjRUU5UFNKOUNqQXhNMkZqYVdRZ2JHOW5hVzR1ZFdKMWJuUjFMbU52Ylh4aFkyTnZkVzUwZkdWNVNteGlWMFp3WWtOSk5rbERTakJhV0U0d1RGaE9kVmxZUW10TVdFcHNZbGM1YTFwWGQzUmtNbWh3WkVkV2FXSXpaM1JqTTFKMlkyMVZkR1J0Ykd4a01sWjVVVWRPYUdKdE9YVmhWMDVvWWtNMWFtSXlNR2xNUTBGcFlqTkNiR0p0Ykd0SmFtOW5TV3RrTUZSWFZtdGhNMGxwVEVOQmFXRllUbVprYlZaNVlWZGFjRnBYVVdsUGFVSXdZMjVXYkV4RFFXbGtXRTVzWTIwMWFHSlhWV2xQYVVGcFpFZFdlbVJETVhwaWJVWjNXa014ZVZwWE1YWmFSMVp6VEZoYWNGcFlaR3hqYVVselNVTkthMkZZVG5kaVIwWTFZbTFHZEZwVFNUWkpRMG93V2xoT01FeFlUblZaV0VKclRGaEtiR0pYT1d0YVYzZDBaREpvY0dSSFZtbGlNMmQwWXpOU2RtTnRWWFJrYld4c1pESldlVWx1TUQwS01EQTBNR05wWkNCc2IyZHBiaTUxWW5WdWRIVXVZMjl0ZkhaaGJHbGtYM05wYm1ObGZESXdNalV0TURJdE1EVlVNVGc2TWpjNk1UVXVPVE0xT0Rjd0NqQXdNMlZqYVdRZ2JHOW5hVzR1ZFdKMWJuUjFMbU52Ylh4c1lYTjBYMkYxZEdoOE1qQXlOUzB3TWkwd05WUXhPRG95TnpveE5TNDVNelU0TnpBS01EQXlabk5wWjI1aGRIVnlaU0JRcms2UVZjX1dwSENsZHIzemR6cUQtSTlSY1RCYW1pcFVnb1g5aDBWb0lnbyJ9fQ== \ No newline at end of file +eyJ0IjogInUxLW1hY2Fyb29uIiwgInYiOiB7InIiOiAiTURBeU9XeHZZMkYwYVc5dUlHMTVZWEJ3Y3k1a1pYWmxiRzl3WlhJdWRXSjFiblIxTG1OdmJRb3dNREUyYVdSbGJuUnBabWxsY2lCTmVVRndjSE1LTURBMFltTnBaQ0J0ZVdGd2NITXVaR1YyWld4dmNHVnlMblZpZFc1MGRTNWpiMjE4ZG1Gc2FXUmZjMmx1WTJWOE1qQXlOaTB3TWkwd09WUXdPRG8xTmpveE5DNDROek16TlRBS01ERTNaR05wWkNCN0luWmxjbk5wYjI0aU9pQXhMQ0FpYzJWamNtVjBJam9nSW1vM1RrWnNaU3RHUWpodGRXTXJMMHhTVVVWbGJYWkNUek15YTJRM1JHWkNUa1Z5VVdadk9HUnNRV0pTU0hSclpFTm9VMmxXU1RGcVpqSXhiaXM0UkdoVmFqWnVUMVV6WVZoWlFUZFJVR0owZEdrNVdEUTVSbGxoVWtoUVdFeDZjWGhKUzBwbGJ5dGxRbkExVDFCd1ZTOU1kV0pYVXl0dGFqRlNWRGRSZVZReWFuTnFjSEZMVWxRck0wOTZLelJYZWs4d2JFWlFjRU5GVGxWdVdURnZSR1UwVmxWTWNYZ3ZWR3RIUjJZMldHUkhOR296UjNGb00wUjZUSEprUzIxdWVHeEZTM1JPUlN0VVVHaG1WbHB3ZEZGd05HNHlURTgxUzJsb1VYSjBlVTVGYUdGSE9HVlRSR0ZYY25SNlRXSlJhWEJFWWtGa016bFBPR3hLYmxWa2F6WnlXa292Vmk5WWVHZHVaRE5TTDFWU1IxaFNjR0UyUjFjdlR6aEZWR052VW1kRVUxZHlWWFp5Y1dKemVtaGpLMVJzWmtoMlNGaDFlblpDVTFwQmVEbGlZMWxFVGxaWGRFWmhhbkp1WkdOTFlXVllXVmM0WnowOUluMEtNREExTVhacFpDQUVtWkZoa3dEeV9kRjZ1bUhmaWRFd2s4ZkJ6RE1mUVlWNmQxLXZxX05TYWdJaGVRd0thTExrTDhjdzY0ZnI0ZHVaNndzWWlhcDdhSkV2cDJQSnJnRGFHN3FBbmhCWlF6WUtNREF4T0dOc0lHeHZaMmx1TG5WaWRXNTBkUzVqYjIwS01EQmhPV05wWkNCdGVXRndjSE11WkdWMlpXeHZjR1Z5TG5WaWRXNTBkUzVqYjIxOFlXTnNmRnNpY0dGamEyRm5aVjloWTJObGMzTWlMQ0FpY0dGamEyRm5aVjl0WVc1aFoyVWlMQ0FpY0dGamEyRm5aVjl0WlhSeWFXTnpJaXdnSW5CaFkydGhaMlZmY0hWemFDSXNJQ0p3WVdOcllXZGxYM0psWjJsemRHVnlJaXdnSW5CaFkydGhaMlZmY21Wc1pXRnpaU0lzSUNKd1lXTnJZV2RsWDNWd1pHRjBaU0pkQ2pBd05EZGphV1FnYlhsaGNIQnpMbVJsZG1Wc2IzQmxjaTUxWW5WdWRIVXVZMjl0ZkdWNGNHbHlaWE44TWpBeU55MHdNaTB3T1ZRd09EbzFOam94TkM0d01EQXdORFFLTURBeVpuTnBaMjVoZEhWeVpTQkljbXo4bGJDWVR1N2RTVjBVM1dFaHE4ZmpSdkNqYzRuMWJQU0tSOS1pYndvIiwgImQiOiAiTURBeFpXeHZZMkYwYVc5dUlHeHZaMmx1TG5WaWRXNTBkUzVqYjIwS01ERTROR2xrWlc1MGFXWnBaWElnZXlKMlpYSnphVzl1SWpvZ01Td2dJbk5sWTNKbGRDSTZJQ0pxTjA1R2JHVXJSa0k0YlhWakt5OU1VbEZGWlcxMlFrOHpNbXRrTjBSbVFrNUZjbEZtYnpoa2JFRmlVa2gwYTJSRGFGTnBWa2t4YW1ZeU1XNHJPRVJvVldvMmJrOVZNMkZZV1VFM1VWQmlkSFJwT1ZnME9VWlpZVkpJVUZoTWVuRjRTVXRLWlc4clpVSndOVTlRY0ZVdlRIVmlWMU1yYldveFVsUTNVWGxVTW1wemFuQnhTMUpVS3pOUGVpczBWM3BQTUd4R1VIQkRSVTVWYmxreGIwUmxORlpWVEhGNEwxUnJSMGRtTmxoa1J6UnFNMGR4YURORWVreHlaRXR0Ym5oc1JVdDBUa1VyVkZCb1psWmFjSFJSY0RSdU1reFBOVXRwYUZGeWRIbE9SV2hoUnpobFUwUmhWM0owZWsxaVVXbHdSR0pCWkRNNVR6aHNTbTVWWkdzMmNscEtMMVl2V0hobmJtUXpVaTlWVWtkWVVuQmhOa2RYTDA4NFJWUmpiMUpuUkZOWGNsVjJjbkZpYzNwb1l5dFViR1pJZGtoWWRYcDJRbE5hUVhnNVltTlpSRTVXVjNSR1lXcHlibVJqUzJGbFdGbFhPR2M5UFNKOUNqQXhNMkZqYVdRZ2JHOW5hVzR1ZFdKMWJuUjFMbU52Ylh4aFkyTnZkVzUwZkdWNVNuWmpSMVoxWVZkUmFVOXBRV2xTTTFKT1dsZFNjbU5wU1hOSlEwcHNZbGRHY0dKRFNUWkpRMG93V2xoT01FeFlUblZaV0VKclRGaEtiR0pYT1d0YVYzZDBaREpvY0dSSFZtbGlNMmQwWXpOU2RtTnRWWFJrYld4c1pESldlVkZIVG1oaWJUbDFZVmRPYUdKRE5XcGlNakJwVEVOQmFWcEhiSHBqUjNob1pWYzFhR0pYVldsUGFVRnBaRWRXZW1SRE1YcGliVVozV2tNeGVWcFhNWFphUjFaelRGaGtiMkZZVW14WmJUazBURmhPTUdJelNteE1XRnB3V2xoa2JHTnBTWE5KUTBveFl6SldlV0p0Um5SYVUwazJTVU5LTUZwWVRqQk1XRTUxV1ZoQ2EweFlTbXhpVnpscldsZDNkR1J0Ykd4a01sWjVTV2wzWjBsdGJIcFlNMXBzWTIxc2JXRlhWbXRKYW05blpFaEtNVnBZTUQwS01EQTBNR05wWkNCc2IyZHBiaTUxWW5WdWRIVXVZMjl0ZkhaaGJHbGtYM05wYm1ObGZESXdNall0TURJdE1EbFVNRGc2TlRZNk1UVXVOakV6TVRBd0NqQXdNMlZqYVdRZ2JHOW5hVzR1ZFdKMWJuUjFMbU52Ylh4c1lYTjBYMkYxZEdoOE1qQXlOaTB3TWkwd09WUXdPRG8xTmpveE5TNDJNVE14TURBS01EQXlabk5wWjI1aGRIVnlaU0NrR0VycHh6RHY5S054MTI1ZkRFa0VXZnpDUnFJd05GUkxIb04ycEdCNGlBbyJ9fQ== \ No newline at end of file diff --git a/tests/lib/snaps/test-implicit-graphical-user-daemon/meta/snap.yaml b/tests/lib/snaps/test-implicit-graphical-user-daemon/meta/snap.yaml deleted file mode 100644 index 40c428004c0..00000000000 --- a/tests/lib/snaps/test-implicit-graphical-user-daemon/meta/snap.yaml +++ /dev/null @@ -1,52 +0,0 @@ -name: test-implicit-graphical-user-daemon -version: 1 -summary: test snapd daemon user in graphical desktop - -slots: - dbus-slot: - interface: dbus - bus: session - name: org.example.implicit-graphical-daemon - -apps: - graphical: - command: usr/bin/ls - plugs: - - desktop - daemon: simple - daemon-scope: user - restart-condition: on-success - restart-delay: 2s - - graphical-dbus: - command: usr/bin/ls - plugs: - - desktop - daemon: dbus - daemon-scope: user - restart-condition: on-success - restart-delay: 2s - activates-on: - - dbus-slot - - graphical-dbus-socket: - command: usr/bin/ls - plugs: - - desktop - - network-bind - daemon: simple - daemon-scope: user - restart-condition: on-success - restart-delay: 2s - sockets: - mysocket: - listen-stream: $XDG_RUNTIME_DIR/mysocket-0 - socket-mode: 0644 - - normal: - command: usr/bin/ls - daemon: simple - daemon-scope: user - restart-condition: on-success - restart-delay: 2s - diff --git a/tests/lib/snaps/test-implicit-graphical-user-daemon/usr/bin/ls b/tests/lib/snaps/test-implicit-graphical-user-daemon/usr/bin/ls deleted file mode 100755 index cefd1e232bd..00000000000 --- a/tests/lib/snaps/test-implicit-graphical-user-daemon/usr/bin/ls +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/sh - -/usr/bin/ls -l \ No newline at end of file diff --git a/tests/main/implicit-graphical-user-daemon/task.yaml b/tests/main/implicit-graphical-user-daemon/task.yaml deleted file mode 100644 index bd6519a6e70..00000000000 --- a/tests/main/implicit-graphical-user-daemon/task.yaml +++ /dev/null @@ -1,40 +0,0 @@ -summary: Ensure that the graphical user daemons work as expected - -details: | - This test ensures that an user daemon with the desktop plug - will be launched with the desktop session only. - -# Same systems than `interfaces-desktop`, since we require that plug. -systems: [-ubuntu-core-*, -ubuntu-*-ppc64el, -fedora-*, -opensuse-*, -amazon-*, -centos-*] - -prepare: | - snap set system experimental.user-daemons=true - "$TESTSTOOLS"/snaps-state install-local test-implicit-graphical-user-daemon - -execute: | - NORMAL_SERVICE=/etc/systemd/user/snap.test-implicit-graphical-user-daemon.normal.service - DESKTOP_SERVICE=/etc/systemd/user/snap.test-implicit-graphical-user-daemon.graphical.service - DESKTOP_DBUS_SERVICE=/etc/systemd/user/snap.test-implicit-graphical-user-daemon.graphical-dbus.service - DESKTOP_DBUS_SOCKET_SERVICE=/etc/systemd/user/snap.test-implicit-graphical-user-daemon.graphical-dbus-socket.service - - echo "Ensure graphical daemon has the right dependencies" - - test -f "${NORMAL_SERVICE}" - test -f "${DESKTOP_SERVICE}" - test -f "${DESKTOP_DBUS_SERVICE}" - test -f "${DESKTOP_DBUS_SOCKET_SERVICE}" - - MATCH "WantedBy=graphical-session\.target" < "${DESKTOP_SERVICE}" - MATCH "After=graphical-session\.target" < "${DESKTOP_SERVICE}" - MATCH "Requisite=graphical-session\.target" < "${DESKTOP_SERVICE}" - MATCH "BindsTo=graphical-session\.target" < "${DESKTOP_SERVICE}" - - MATCH "After=graphical-session\.target" < "${DESKTOP_DBUS_SERVICE}" - MATCH "Requisite=graphical-session\.target" < "${DESKTOP_DBUS_SERVICE}" - MATCH "PartOf=graphical-session\.target" < "${DESKTOP_DBUS_SERVICE}" - - MATCH "After=graphical-session\.target" < "${DESKTOP_DBUS_SOCKET_SERVICE}" - MATCH "Requisite=graphical-session\.target" < "${DESKTOP_DBUS_SOCKET_SERVICE}" - MATCH "PartOf=graphical-session\.target" < "${DESKTOP_DBUS_SOCKET_SERVICE}" - - MATCH "WantedBy=default\.target" < "${NORMAL_SERVICE}" diff --git a/tests/nested/manual/core20-install-mode-shutdown-via-hook/task.yaml b/tests/nested/manual/core20-install-mode-shutdown-via-hook/task.yaml index 1e065d5c08b..a9763d19179 100644 --- a/tests/nested/manual/core20-install-mode-shutdown-via-hook/task.yaml +++ b/tests/nested/manual/core20-install-mode-shutdown-via-hook/task.yaml @@ -87,7 +87,13 @@ execute: | remote.exec "cloud-init status --wait" || ret=$? if [ "$ret" -ne 0 ] && [ "$ret" -ne 2 ]; then echo "cloud-init finished with error $ret" - exit 1 + # FIXME: remove core26 case. + # See https://github.com/canonical/cloud-init/issues/6699 + if nested_is_core_26_system; then + echo "Ignoring error on core26 for now" + else + exit 1 + fi fi echo "The device is using encrypted ubuntu-data and is in run mode now" diff --git a/wrappers/internal/service_unit_gen.go b/wrappers/internal/service_unit_gen.go index 78187b3a620..f0b29d2889c 100644 --- a/wrappers/internal/service_unit_gen.go +++ b/wrappers/internal/service_unit_gen.go @@ -37,8 +37,6 @@ import ( "github.com/snapcore/snapd/timeout" ) -const GraphicalSessionTarget = "graphical-session.target" - // SnapServicesUnitOptions is a struct for controlling the generated service // definition for a snap service. type SnapServicesUnitOptions struct { @@ -146,18 +144,9 @@ Wants={{.PrerequisiteTarget}} {{- if .After}} After={{ stringsJoin .After " " }} {{- end}} -{{- if .Requisite}} -Requisite={{ stringsJoin .Requisite " " }} -{{- end}} {{- if .Before}} Before={{ stringsJoin .Before " "}} {{- end}} -{{- if .BindsTo}} -BindsTo={{ stringsJoin .BindsTo " " }} -{{- end}} -{{- if .PartOf}} -PartOf={{ stringsJoin .PartOf " " }} -{{- end}} {{- if .CoreMountedSnapdSnapDep}} Wants={{ stringsJoin .CoreMountedSnapdSnapDep " "}} After={{ stringsJoin .CoreMountedSnapdSnapDep " "}} @@ -296,9 +285,6 @@ WantedBy={{.ServicesTarget}} Before []string After []string Requires []string - BindsTo []string - PartOf []string - Requisite []string InterfaceServiceSnippets string InterfaceUnitSnippets string SliceUnit string @@ -333,11 +319,8 @@ WantedBy={{.ServicesTarget}} BusName: busName, SuccessExitStatus: appInfo.SuccessExitStatus, - Before: generateServiceNames(appInfo.Snap, appInfo.Before), - After: generateServiceNames(appInfo.Snap, appInfo.After), - BindsTo: generateServiceNames(appInfo.Snap, appInfo.BindsTo), - PartOf: generateServiceNames(appInfo.Snap, appInfo.PartOf), - Requisite: generateServiceNames(appInfo.Snap, appInfo.Requisite), + Before: generateServiceNames(appInfo.Snap, appInfo.Before), + After: generateServiceNames(appInfo.Snap, appInfo.After), // systemd runs as PID 1 so %h will not work. Home: "/root", @@ -355,16 +338,6 @@ WantedBy={{.ServicesTarget}} // FIXME: ideally use UserDataDir("%h"), but then the // unit fails if the directory doesn't exist. wrapperData.WorkingDir = appInfo.Snap.DataDir() - if appInfo.HasPlug("desktop") { - wrapperData.After = append(wrapperData.After, GraphicalSessionTarget) - if appInfo.Daemon == "dbus" || len(appInfo.Sockets) != 0 { - wrapperData.PartOf = append(wrapperData.PartOf, GraphicalSessionTarget) - } else { - wrapperData.BindsTo = append(wrapperData.BindsTo, GraphicalSessionTarget) - } - wrapperData.ServicesTarget = GraphicalSessionTarget - wrapperData.Requisite = append(wrapperData.Requisite, GraphicalSessionTarget) - } default: panic("unknown snap.DaemonScope") } diff --git a/wrappers/internal/service_unit_gen_test.go b/wrappers/internal/service_unit_gen_test.go index d8228ee23f3..411d9924659 100644 --- a/wrappers/internal/service_unit_gen_test.go +++ b/wrappers/internal/service_unit_gen_test.go @@ -97,87 +97,15 @@ Type=%s WantedBy=default.target ` -const expectedGraphicalUserServiceFmt = `[Unit] -# Auto-generated, DO NOT EDIT -Description=Service for snap application snap.app -After=graphical-session.target -Requisite=graphical-session.target -BindsTo=graphical-session.target -X-Snappy=yes - -[Service] -EnvironmentFile=-/etc/environment -ExecStart=/usr/bin/snap run snap.app -SyslogIdentifier=snap.app -Restart=%s -WorkingDirectory=/var/snap/snap/44 -ExecStop=/usr/bin/snap run --command=stop snap.app -ExecReload=/usr/bin/snap run --command=reload snap.app -ExecStopPost=/usr/bin/snap run --command=post-stop snap.app -TimeoutStopSec=10s -Type=%s - -[Install] -WantedBy=graphical-session.target -` - -const expectedDBusGraphicalUserServiceFmt = `[Unit] -# Auto-generated, DO NOT EDIT -Description=Service for snap application snap.app -After=graphical-session.target -Requisite=graphical-session.target -PartOf=graphical-session.target -X-Snappy=yes - -[Service] -EnvironmentFile=-/etc/environment -ExecStart=/usr/bin/snap run snap.app -SyslogIdentifier=snap.app -Restart=%s -WorkingDirectory=/var/snap/snap/44 -ExecStop=/usr/bin/snap run --command=stop snap.app -ExecReload=/usr/bin/snap run --command=reload snap.app -ExecStopPost=/usr/bin/snap run --command=post-stop snap.app -TimeoutStopSec=10s -Type=%s - -[Install] -WantedBy=graphical-session.target -` - -const expectedSocketGraphicalUserServiceFmt = `[Unit] -# Auto-generated, DO NOT EDIT -Description=Service for snap application snap.app -After=graphical-session.target -Requisite=graphical-session.target -PartOf=graphical-session.target -X-Snappy=yes - -[Service] -EnvironmentFile=-/etc/environment -ExecStart=/usr/bin/snap run snap.app -SyslogIdentifier=snap.app -Restart=%s -WorkingDirectory=/var/snap/snap/44 -ExecStop=/usr/bin/snap run --command=stop snap.app -ExecReload=/usr/bin/snap run --command=reload snap.app -ExecStopPost=/usr/bin/snap run --command=post-stop snap.app -TimeoutStopSec=10s -Type=%s -` - var ( mountUnitPrefix = strings.Replace(dirs.SnapMountDir[1:], "/", "-", -1) ) var ( - expectedAppService = fmt.Sprintf(expectedServiceFmt, mountUnitPrefix, mountUnitPrefix, "on-failure", "simple", expectedInstallSection) - expectedDbusService = fmt.Sprintf(expectedServiceFmt, mountUnitPrefix, mountUnitPrefix, "on-failure", "dbus\nBusName=foo.bar.baz", "") - expectedOneshotService = fmt.Sprintf(expectedServiceFmt, mountUnitPrefix, mountUnitPrefix, "no", "oneshot\nRemainAfterExit=yes", expectedInstallSection) - expectedUserAppService = fmt.Sprintf(expectedUserServiceFmt, "on-failure", "simple") - expectedGraphicalUserAppService = fmt.Sprintf(expectedGraphicalUserServiceFmt, "on-failure", "simple") - expectedDBusGraphicalUserAppService = fmt.Sprintf(expectedDBusGraphicalUserServiceFmt, "on-failure", "dbus") - expectedSocketGraphicalUserAppService = fmt.Sprintf(expectedSocketGraphicalUserServiceFmt, "on-failure", "simple") + expectedAppService = fmt.Sprintf(expectedServiceFmt, mountUnitPrefix, mountUnitPrefix, "on-failure", "simple", expectedInstallSection) + expectedDbusService = fmt.Sprintf(expectedServiceFmt, mountUnitPrefix, mountUnitPrefix, "on-failure", "dbus\nBusName=foo.bar.baz", "") + expectedOneshotService = fmt.Sprintf(expectedServiceFmt, mountUnitPrefix, mountUnitPrefix, "no", "oneshot\nRemainAfterExit=yes", expectedInstallSection) + expectedUserAppService = fmt.Sprintf(expectedUserServiceFmt, "on-failure", "simple") ) var ( @@ -590,89 +518,6 @@ apps: c.Check(string(generatedWrapper), Equals, expectedUserAppService) } -func (s *serviceUnitGenSuite) TestGenerateSnapGraphicalUserServiceFile(c *C) { - yamlText := ` -name: snap -version: 1.0 -apps: - app: - command: bin/start - stop-command: bin/stop - reload-command: bin/reload - post-stop-command: bin/stop --post - stop-timeout: 10s - daemon: simple - daemon-scope: user - plugs: - - desktop -` - info, err := snap.InfoFromSnapYaml([]byte(yamlText)) - c.Assert(err, IsNil) - info.Revision = snap.R(44) - app := info.Apps["app"] - - generatedWrapper, err := internal.GenerateSnapServiceUnitFile(app, nil) - c.Assert(err, IsNil) - c.Check(string(generatedWrapper), Equals, expectedGraphicalUserAppService) -} - -func (s *serviceUnitGenSuite) TestGenerateSnapDBusGraphicalUserServiceFile(c *C) { - yamlText := ` -name: snap -version: 1.0 -apps: - app: - command: bin/start - stop-command: bin/stop - reload-command: bin/reload - post-stop-command: bin/stop --post - stop-timeout: 10s - daemon: dbus - daemon-scope: user - plugs: - - desktop -` - info, err := snap.InfoFromSnapYaml([]byte(yamlText)) - c.Assert(err, IsNil) - info.Revision = snap.R(44) - app := info.Apps["app"] - - generatedWrapper, err := internal.GenerateSnapServiceUnitFile(app, nil) - c.Assert(err, IsNil) - c.Check(string(generatedWrapper), Equals, expectedDBusGraphicalUserAppService) -} - -func (s *serviceUnitGenSuite) TestGenerateSnapSocketGraphicalUserServiceFile(c *C) { - yamlText := ` -name: snap -version: 1.0 -apps: - app: - command: bin/start - stop-command: bin/stop - reload-command: bin/reload - post-stop-command: bin/stop --post - stop-timeout: 10s - daemon: simple - sockets: - testsocket: - listen-stream: $SNAP_USER_COMMON/unix.socket - socket-mode: 0644 - daemon-scope: user - plugs: - - network-bind - - desktop -` - info, err := snap.InfoFromSnapYaml([]byte(yamlText)) - c.Assert(err, IsNil) - info.Revision = snap.R(44) - app := info.Apps["app"] - - generatedWrapper, err := internal.GenerateSnapServiceUnitFile(app, nil) - c.Assert(err, IsNil) - c.Check(string(generatedWrapper), Equals, expectedSocketGraphicalUserAppService) -} - func (s *serviceUnitGenSuite) TestServiceAfterBefore(c *C) { const expectedServiceFmt = `[Unit] # Auto-generated, DO NOT EDIT