diff options
| author | Maciej Borzecki <maciej.zenon.borzecki@canonical.com> | 2021-07-07 08:42:32 +0200 |
|---|---|---|
| committer | Maciej Borzecki <maciej.zenon.borzecki@canonical.com> | 2021-07-07 08:42:32 +0200 |
| commit | d84e631699cb0e1ae15490a0ac1e039d04ca6be7 (patch) | |
| tree | 9f9a2af662ff583401782cf6089e58c519707dc7 | |
| parent | b590a78fa7ec689973422142ecb9e422e63237f1 (diff) | |
| parent | 1d23bf1e1464feb1f0f6664f89ea6fba81be68de (diff) | |
Merge remote-tracking branch 'upstream/master' into bboozzoo/pick-alternative-label-for-remodel
33 files changed, 726 insertions, 69 deletions
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index a9c4987c92..55fb2c8f26 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -240,6 +240,7 @@ jobs: - ubuntu-14.04-64 - ubuntu-16.04-32 - ubuntu-16.04-64 + - ubuntu-18.04-32 - ubuntu-18.04-64 - ubuntu-20.04-64 - ubuntu-20.10-64 diff --git a/asserts/extkeypairmgr.go b/asserts/extkeypairmgr.go index b7e345b51b..0a945a8f8d 100644 --- a/asserts/extkeypairmgr.go +++ b/asserts/extkeypairmgr.go @@ -34,6 +34,11 @@ import ( "github.com/snapcore/snapd/strutil" ) +type ExternalKeyInfo struct { + Name string + ID string +} + // ExternalKeypairManager is key pair manager implemented via an external program interface. // TODO: points to interface docs type ExternalKeypairManager struct { @@ -189,24 +194,24 @@ func (em *ExternalKeypairManager) Put(privKey PrivateKey) error { return fmt.Errorf("cannot import private key into external keypair manager") } -func (em *ExternalKeypairManager) loadAllKeys() error { +func (em *ExternalKeypairManager) loadAllKeys() ([]string, error) { names, err := em.keyNames() if err != nil { - return err + return nil, err } for _, name := range names { if _, err := em.loadKey(name); err != nil { - return err + return nil, err } } - return nil + return names, nil } func (em *ExternalKeypairManager) Get(keyID string) (PrivateKey, error) { cachedKey, ok := em.cache[keyID] if !ok { // try to load all keys - if err := em.loadAllKeys(); err != nil { + if _, err := em.loadAllKeys(); err != nil { return nil, err } cachedKey, ok = em.cache[keyID] @@ -217,6 +222,19 @@ func (em *ExternalKeypairManager) Get(keyID string) (PrivateKey, error) { return em.privateKey(cachedKey), nil } +func (em *ExternalKeypairManager) List() ([]ExternalKeyInfo, error) { + names, err := em.loadAllKeys() + if err != nil { + return nil, err + } + res := make([]ExternalKeyInfo, len(names)) + for i, name := range names { + res[i].Name = name + res[i].ID = em.cache[em.nameToID[name]].pubKey.ID() + } + return res, nil +} + // see https://datatracker.ietf.org/doc/html/rfc2313 and more recently // and more precisely about SHA-512: // https://datatracker.ietf.org/doc/html/rfc3447#section-9.2 Notes 1. diff --git a/asserts/extkeypairmgr_test.go b/asserts/extkeypairmgr_test.go index d2f2206903..c33180fa2a 100644 --- a/asserts/extkeypairmgr_test.go +++ b/asserts/extkeypairmgr_test.go @@ -272,3 +272,30 @@ func (s *extKeypairMgrSuite) TestExport(c *C) { c.Check(exported, DeepEquals, expected) } } + +func (s *extKeypairMgrSuite) TestList(c *C) { + kmgr, err := asserts.NewExternalKeypairManager("keymgr") + c.Assert(err, IsNil) + + keys, err := kmgr.List() + c.Assert(err, IsNil) + + defaultID := asserts.RSAPublicKey(s.defaultPub).ID() + modelsID := asserts.RSAPublicKey(s.modelsPub).ID() + + c.Check(keys, DeepEquals, []asserts.ExternalKeyInfo{ + {Name: "default", ID: defaultID}, + {Name: "models", ID: modelsID}, + }) +} + +func (s *extKeypairMgrSuite) TestListError(c *C) { + kmgr, err := asserts.NewExternalKeypairManager("keymgr") + c.Assert(err, IsNil) + + pgm := testutil.MockCommand(c, "keymgr", `exit 1`) + defer pgm.Restore() + + _, err = kmgr.List() + c.Check(err, ErrorMatches, `cannot get all external keypair manager key names:.*exit status 1.*`) +} diff --git a/asserts/gpgkeypairmgr.go b/asserts/gpgkeypairmgr.go index 2151a87c81..c6d0cafd8f 100644 --- a/asserts/gpgkeypairmgr.go +++ b/asserts/gpgkeypairmgr.go @@ -1,7 +1,7 @@ // -*- Mode: Go; indent-tabs-mode: t -*- /* - * Copyright (C) 2016 Canonical Ltd + * Copyright (C) 2016-2021 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -365,3 +365,18 @@ func (gkm *GPGKeypairManager) Delete(name string) error { } return nil } + +func (gkm *GPGKeypairManager) List() (res []ExternalKeyInfo, err error) { + collect := func(privk PrivateKey, fpr string, uid string) error { + key := ExternalKeyInfo{ + Name: uid, + ID: privk.PublicKey().ID(), + } + res = append(res, key) + return nil + } + if err := gkm.Walk(collect); err != nil { + return nil, err + } + return res, nil +} diff --git a/asserts/gpgkeypairmgr_test.go b/asserts/gpgkeypairmgr_test.go index 1991b80aae..6885214bc3 100644 --- a/asserts/gpgkeypairmgr_test.go +++ b/asserts/gpgkeypairmgr_test.go @@ -1,7 +1,7 @@ // -*- Mode: Go; indent-tabs-mode: t -*- /* - * Copyright (C) 2016 Canonical Ltd + * Copyright (C) 2016-2021 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -328,3 +328,13 @@ Preferences: SHA512 c.Check(parameters, Equals, baseParameters+test.extraParameters) } } + +func (gkms *gpgKeypairMgrSuite) TestList(c *C) { + gpgKeypairMgr := gkms.keypairMgr.(*asserts.GPGKeypairManager) + + keys, err := gpgKeypairMgr.List() + c.Assert(err, IsNil) + c.Check(keys, HasLen, 1) + c.Check(keys[0].ID, Equals, assertstest.DevKeyID) + c.Check(keys[0].Name, Not(Equals), "") +} diff --git a/cmd/libsnap-confine-private/cgroup-support-test.c b/cmd/libsnap-confine-private/cgroup-support-test.c index 9a3f4b8b11..779c364af0 100644 --- a/cmd/libsnap-confine-private/cgroup-support-test.c +++ b/cmd/libsnap-confine-private/cgroup-support-test.c @@ -236,6 +236,19 @@ static void test_sc_cgroupv2_is_tracking_dir_permissions(cgroupv2_is_tracking_fi g_test_trap_assert_stderr("cannot open directory entry \"badperm\": Permission denied\n"); } +static void test_sc_cgroupv2_is_tracking_no_cgroup_root(cgroupv2_is_tracking_fixture *fixture, + gconstpointer user_data) { + GError *err = NULL; + g_file_set_contents(fixture->self_cgroup, "0::/foo/bar/baz/snap.foo.app.1234-1234.scope", -1, &err); + g_assert_no_error(err); + + sc_set_cgroup_root("/does/not/exist"); + + // does not die when cgroup root is not present + bool is_tracking = sc_cgroup_v2_is_tracking_snap("foo"); + g_assert_false(is_tracking); +} + static void sc_set_self_cgroup_path(const char *mock) { self_cgroup = mock; } typedef struct _cgroupv2_own_group_fixture { @@ -370,4 +383,6 @@ static void __attribute__((constructor)) init(void) { cgroupv2_is_tracking_tear_down); g_test_add("/cgroup/v2/is_tracking_bad_nesting", cgroupv2_is_tracking_fixture, NULL, cgroupv2_is_tracking_set_up, test_sc_cgroupv2_is_tracking_bad_nesting, cgroupv2_is_tracking_tear_down); + g_test_add("/cgroup/v2/is_tracking_no_cgroup_root", cgroupv2_is_tracking_fixture, NULL, cgroupv2_is_tracking_set_up, + test_sc_cgroupv2_is_tracking_no_cgroup_root, cgroupv2_is_tracking_tear_down); } diff --git a/cmd/libsnap-confine-private/cgroup-support.c b/cmd/libsnap-confine-private/cgroup-support.c index cf2dcaba18..1ef4f789d0 100644 --- a/cmd/libsnap-confine-private/cgroup-support.c +++ b/cmd/libsnap-confine-private/cgroup-support.c @@ -109,7 +109,14 @@ static bool traverse_looking_for_prefix_in_dir(DIR *root, const char *prefix, co errno = 0; struct dirent *ent = readdir(root); if (ent == NULL) { + // is this an error? if (errno != 0) { + if (errno == ENOENT) { + // the processes may exit and the group entries may go away at + // any time + // the entries may go away at any time + break; + } die("cannot read directory entry"); } break; @@ -133,11 +140,17 @@ static bool traverse_looking_for_prefix_in_dir(DIR *root, const char *prefix, co // entfd is consumed by fdopendir() and freed with closedir() int entfd = openat(dirfd(root), ent->d_name, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); if (entfd == -1) { + if (errno == ENOENT) { + // the processes may exit and the group entries may go away at + // any time + return false; + } die("cannot open directory entry \"%s\"", ent->d_name); } // takes ownership of the file descriptor DIR *entdir SC_CLEANUP(sc_cleanup_closedir) = fdopendir(entfd); if (entdir == NULL) { + // we have the fd, so ENOENT isn't possible here die("cannot fdopendir directory \"%s\"", ent->d_name); } bool found = traverse_looking_for_prefix_in_dir(entdir, prefix, skip, depth + 1); @@ -181,6 +194,9 @@ bool sc_cgroup_v2_is_tracking_snap(const char *snap_instance) { debug("opening cgroup root dir at %s", cgroup_dir); DIR *root SC_CLEANUP(sc_cleanup_closedir) = opendir(cgroup_dir); if (root == NULL) { + if (errno == ENOENT) { + return false; + } die("cannot open cgroup root dir"); } // traverse the cgroup hierarchy tree looking for other groups that @@ -203,13 +219,12 @@ char *sc_cgroup_v2_own_path_full(void) { char *line SC_CLEANUP(sc_cleanup_string) = NULL; size_t linesz = 0; ssize_t sz = getline(&line, &linesz, in); - if (sz == -1) { - if (feof(in)) { - break; - } - if (ferror(in)) { - die("cannot read line from %s", self_cgroup); - } + if (sz < 0 && errno != 0) { + die("cannot read line from %s", self_cgroup); + } + if (sz < 0) { + // end of file + break; } if (!sc_startswith(line, "0::")) { continue; diff --git a/cmd/snap/cmd_export_key.go b/cmd/snap/cmd_export_key.go index 94aa702945..0149b13a8b 100644 --- a/cmd/snap/cmd_export_key.go +++ b/cmd/snap/cmd_export_key.go @@ -1,7 +1,7 @@ // -*- Mode: Go; indent-tabs-mode: t -*- /* - * Copyright (C) 2016 Canonical Ltd + * Copyright (C) 2021 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -66,9 +66,12 @@ func (x *cmdExportKey) Execute(args []string) error { keyName = "default" } - manager := asserts.NewGPGKeypairManager() + keypairMgr, err := getKeypairManager() + if err != nil { + return err + } if x.Account != "" { - privKey, err := manager.GetByName(keyName) + privKey, err := keypairMgr.GetByName(keyName) if err != nil { return err } @@ -90,7 +93,7 @@ func (x *cmdExportKey) Execute(args []string) error { } fmt.Fprint(Stdout, string(asserts.Encode(assertion))) } else { - encoded, err := manager.Export(keyName) + encoded, err := keypairMgr.Export(keyName) if err != nil { return err } diff --git a/cmd/snap/cmd_keys.go b/cmd/snap/cmd_keys.go index 9b22e3356c..426ff654ee 100644 --- a/cmd/snap/cmd_keys.go +++ b/cmd/snap/cmd_keys.go @@ -1,7 +1,7 @@ // -*- Mode: Go; indent-tabs-mode: t -*- /* - * Copyright (C) 2016 Canonical Ltd + * Copyright (C) 2016-2021 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -25,7 +25,6 @@ import ( "github.com/jessevdk/go-flags" - "github.com/snapcore/snapd/asserts" "github.com/snapcore/snapd/i18n" ) @@ -86,21 +85,21 @@ func (x *cmdKeys) Execute(args []string) error { return ErrExtraArgs } - keys := []Key{} - - manager := asserts.NewGPGKeypairManager() - collect := func(privk asserts.PrivateKey, fpr string, uid string) error { - key := Key{ - Name: uid, - Sha3_384: privk.PublicKey().ID(), - } - keys = append(keys, key) - return nil + keypairMgr, err := getKeypairManager() + if err != nil { + return err } - err := manager.Walk(collect) + + kinfos, err := keypairMgr.List() if err != nil { return err } + keys := make([]Key, len(kinfos)) + for i, kinfo := range kinfos { + keys[i].Name = kinfo.Name + keys[i].Sha3_384 = kinfo.ID + } + if x.JSON { return outputJSON(keys) } diff --git a/cmd/snap/cmd_sign.go b/cmd/snap/cmd_sign.go index 5f4b407a12..bd001f32b4 100644 --- a/cmd/snap/cmd_sign.go +++ b/cmd/snap/cmd_sign.go @@ -1,7 +1,7 @@ // -*- Mode: Go; indent-tabs-mode: t -*- /* - * Copyright (C) 2014-2015 Canonical Ltd + * Copyright (C) 2014-2021 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -25,7 +25,6 @@ import ( "github.com/jessevdk/go-flags" - "github.com/snapcore/snapd/asserts" "github.com/snapcore/snapd/asserts/signtool" "github.com/snapcore/snapd/i18n" ) @@ -81,7 +80,10 @@ func (x *cmdSign) Execute(args []string) error { return fmt.Errorf(i18n.G("cannot read assertion input: %v"), err) } - keypairMgr := asserts.NewGPGKeypairManager() + keypairMgr, err := getKeypairManager() + if err != nil { + return err + } privKey, err := keypairMgr.GetByName(string(x.KeyName)) if err != nil { // TRANSLATORS: %q is the key name, %v the error message diff --git a/cmd/snap/cmd_sign_build.go b/cmd/snap/cmd_sign_build.go index 9cfcf0e01d..5780403512 100644 --- a/cmd/snap/cmd_sign_build.go +++ b/cmd/snap/cmd_sign_build.go @@ -1,7 +1,7 @@ // -*- Mode: Go; indent-tabs-mode: t -*- /* - * Copyright (C) 2014-2015 Canonical Ltd + * Copyright (C) 2014-2021 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -84,8 +84,11 @@ func (x *cmdSignBuild) Execute(args []string) error { return err } - gkm := asserts.NewGPGKeypairManager() - privKey, err := gkm.GetByName(string(x.KeyName)) + keypairMgr, err := getKeypairManager() + if err != nil { + return err + } + privKey, err := keypairMgr.GetByName(string(x.KeyName)) if err != nil { // TRANSLATORS: %q is the key name, %v the error message return fmt.Errorf(i18n.G("cannot use %q key: %v"), x.KeyName, err) @@ -105,7 +108,7 @@ func (x *cmdSignBuild) Execute(args []string) error { } adb, err := asserts.OpenDatabase(&asserts.DatabaseConfig{ - KeypairManager: gkm, + KeypairManager: keypairMgr, }) if err != nil { return fmt.Errorf(i18n.G("cannot open the assertions database: %v"), err) diff --git a/cmd/snap/complete.go b/cmd/snap/complete.go index b1c7dc8840..617d72bed2 100644 --- a/cmd/snap/complete.go +++ b/cmd/snap/complete.go @@ -1,7 +1,7 @@ // -*- Mode: Go; indent-tabs-mode: t -*- /* - * Copyright (C) 2016 Canonical Ltd + * Copyright (C) 2016-2021 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -28,7 +28,6 @@ import ( "github.com/jessevdk/go-flags" - "github.com/snapcore/snapd/asserts" "github.com/snapcore/snapd/client" "github.com/snapcore/snapd/dirs" "github.com/snapcore/snapd/i18n" @@ -185,13 +184,20 @@ func (n assertTypeName) Complete(match string) []flags.Completion { type keyName string func (s keyName) Complete(match string) []flags.Completion { + keypairManager, err := getKeypairManager() + if err != nil { + return nil + } + keys, err := keypairManager.List() + if err != nil { + return nil + } var res []flags.Completion - asserts.NewGPGKeypairManager().Walk(func(_ asserts.PrivateKey, _ string, uid string) error { - if strings.HasPrefix(uid, match) { - res = append(res, flags.Completion{Item: uid}) + for _, k := range keys { + if strings.HasPrefix(k.Name, match) { + res = append(res, flags.Completion{Item: k.Name}) } - return nil - }) + } return res } diff --git a/cmd/snap/export_test.go b/cmd/snap/export_test.go index 891610d08b..6dbc430e91 100644 --- a/cmd/snap/export_test.go +++ b/cmd/snap/export_test.go @@ -91,6 +91,8 @@ var ( PrintInstallHint = printInstallHint IsStopping = isStopping + + GetKeypairManager = getKeypairManager ) func HiddenCmd(descr string, completeHidden bool) *cmdInfo { diff --git a/cmd/snap/keymgr.go b/cmd/snap/keymgr.go new file mode 100644 index 0000000000..6a3c613a02 --- /dev/null +++ b/cmd/snap/keymgr.go @@ -0,0 +1,49 @@ +// -*- Mode: Go; indent-tabs-mode: t -*- + +/* + * Copyright (C) 2021 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +package main + +import ( + "fmt" + "os" + + "github.com/snapcore/snapd/asserts" + "github.com/snapcore/snapd/i18n" +) + +type KeypairManager interface { + asserts.KeypairManager + + GetByName(keyNname string) (asserts.PrivateKey, error) + Export(keyName string) ([]byte, error) + List() ([]asserts.ExternalKeyInfo, error) +} + +func getKeypairManager() (KeypairManager, error) { + keymgrPath := os.Getenv("SNAPD_EXT_KEYMGR") + if keymgrPath != "" { + keypairMgr, err := asserts.NewExternalKeypairManager(keymgrPath) + if err != nil { + return nil, fmt.Errorf(i18n.G("cannot setup external keypair manager: %v"), err) + } + return keypairMgr, nil + } + keypairMgr := asserts.NewGPGKeypairManager() + return keypairMgr, nil +} diff --git a/cmd/snap/keymgr_test.go b/cmd/snap/keymgr_test.go new file mode 100644 index 0000000000..5b4759e1a3 --- /dev/null +++ b/cmd/snap/keymgr_test.go @@ -0,0 +1,72 @@ +// -*- Mode: Go; indent-tabs-mode: t -*- + +/* + * Copyright (C) 2021 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +package main_test + +import ( + "os" + + "gopkg.in/check.v1" + + "github.com/snapcore/snapd/asserts" + snap "github.com/snapcore/snapd/cmd/snap" + "github.com/snapcore/snapd/testutil" +) + +type keymgrSuite struct{} + +var _ = check.Suite(&keymgrSuite{}) + +func (keymgrSuite) TestGPGKeypairManager(c *check.C) { + keypairMgr, err := snap.GetKeypairManager() + c.Check(err, check.IsNil) + c.Check(keypairMgr, check.FitsTypeOf, &asserts.GPGKeypairManager{}) +} + +func (keymgrSuite) TestExternalKeypairManager(c *check.C) { + os.Setenv("SNAPD_EXT_KEYMGR", "keymgr") + defer os.Unsetenv("SNAPD_EXT_KEYMGR") + + pgm := testutil.MockCommand(c, "keymgr", ` +if [ "$1" == "features" ]; then + echo '{"signing":["RSA-PKCS"] , "public-keys":["DER"]}' + exit 0 +fi +exit 1 +`) + defer pgm.Restore() + + keypairMgr, err := snap.GetKeypairManager() + c.Check(err, check.IsNil) + c.Check(keypairMgr, check.FitsTypeOf, &asserts.ExternalKeypairManager{}) + c.Check(pgm.Calls(), check.HasLen, 1) +} + +func (keymgrSuite) TestExternalKeypairManagerError(c *check.C) { + os.Setenv("SNAPD_EXT_KEYMGR", "keymgr") + defer os.Unsetenv("SNAPD_EXT_KEYMGR") + + pgm := testutil.MockCommand(c, "keymgr", ` +exit 1 +`) + defer pgm.Restore() + + _, err := snap.GetKeypairManager() + c.Check(err, check.ErrorMatches, `cannot setup external keypair manager: external keypair manager "keymgr" \[features\] failed: exit status 1.*`) +} diff --git a/interfaces/apparmor/template.go b/interfaces/apparmor/template.go index 73e3d8ac0a..d262de67ba 100644 --- a/interfaces/apparmor/template.go +++ b/interfaces/apparmor/template.go @@ -927,6 +927,10 @@ profile snap-update-ns.###SNAP_INSTANCE_NAME### (attach_disconnected) { # golang runtime variables /sys/kernel/mm/transparent_hugepage/hpage_pmd_size r, + # glibc 2.27+ may poke this file to find out the number of CPUs + # available in the system when creating a new arena for malloc, see + # Golang issue 25628 + /sys/devices/system/cpu/online r, # Allow reading the command line (snap-update-ns uses it in pre-Go bootstrap code). @{PROC}/@{pid}/cmdline r, diff --git a/sandbox/cgroup/export_test.go b/sandbox/cgroup/export_test.go index b739f15a4c..2d4fcc46dc 100644 --- a/sandbox/cgroup/export_test.go +++ b/sandbox/cgroup/export_test.go @@ -34,6 +34,8 @@ var ( ErrDBusSpawnChildExited = errDBusSpawnChildExited SecurityTagFromCgroupPath = securityTagFromCgroupPath + + ApplyToSnap = applyToSnap ) func MockFsTypeForPath(mock func(string) (int64, error)) (restore func()) { diff --git a/sandbox/cgroup/freezer.go b/sandbox/cgroup/freezer.go index e4ead87d8c..cd3360de07 100644 --- a/sandbox/cgroup/freezer.go +++ b/sandbox/cgroup/freezer.go @@ -123,14 +123,25 @@ func thawSnapProcessesImplV1(snapName string) error { return nil } -func applyToSnap(snapName string, action func(groupName string) error, skipErrs bool) error { +func applyToSnap(snapName string, action func(groupName string) error, skipError func(err error) bool) error { + if action == nil { + return fmt.Errorf("internal error: action is nil") + } + if skipError == nil { + return fmt.Errorf("internal error: skip error is nil") + } canary := fmt.Sprintf("snap.%s.", snapName) cgroupRoot := filepath.Join(rootPath, cgroupMountPoint) if _, dir, _ := osutil.DirExists(cgroupRoot); !dir { return nil } return filepath.Walk(filepath.Join(rootPath, cgroupMountPoint), func(name string, info os.FileInfo, err error) error { - if err != nil && !skipErrs { + if err != nil { + if skipError(err) { + // we don't know whether it's a file or + // directory, so just return nil instead + return nil + } return err } if !info.IsDir() { @@ -140,13 +151,29 @@ func applyToSnap(snapName string, action func(groupName string) error, skipErrs return nil } // found a group - if err := action(name); err != nil && !skipErrs { + if err := action(name); err != nil && !skipError(err) { return err } return filepath.SkipDir }) } +// writeExistingFile can be used as a drop-in replacement for ioutil.WriteFile, +// but does not create a file when it does not exist +func writeExistingFile(where string, data []byte, mode os.FileMode) error { + f, err := os.OpenFile(where, os.O_WRONLY|os.O_TRUNC, mode) + if err != nil { + return err + } + _, errW := f.Write(data) + errC := f.Close() + // pick the right error + if errW != nil { + return errW + } + return errC +} + // freezeSnapProcessesImplV2 freezes all the processes originating from the // given snap. Processes are frozen regardless of which particular snap // application they originate from. @@ -166,15 +193,20 @@ func freezeSnapProcessesImplV2(snapName string) error { return nil } fname := filepath.Join(dir, "cgroup.freeze") - if err := ioutil.WriteFile(fname, []byte("1"), 0644); err != nil && os.IsNotExist(err) { - // the group may be gone already - return nil - } else if err != nil { + if err := writeExistingFile(fname, []byte("1"), 0644); err != nil { + if os.IsNotExist(err) { + // the group may be gone already + return nil + } return fmt.Errorf("cannot freeze processes of snap %q, %v", snapName, err) } for i := 0; i < 30; i++ { data, err := ioutil.ReadFile(fname) if err != nil { + if os.IsNotExist(err) { + // group may be gone + return nil + } return fmt.Errorf("cannot determine the freeze state of processes of snap %q, %v", snapName, err) } // If the cgroup is still freezing then wait a moment and try again. @@ -187,35 +219,40 @@ func freezeSnapProcessesImplV2(snapName string) error { } return fmt.Errorf("cannot freeze processes of snap %q in group %v", snapName, filepath.Base(dir)) } - const skipFreezeErrs = false - err = applyToSnap(snapName, freezeOne, skipFreezeErrs) + // freeze, skipping ENOENT errors + err = applyToSnap(snapName, freezeOne, os.IsNotExist) if err == nil { return nil } // we either got here because we hit a timeout freezing snap processes // or some other error - const skipThawErrs = true - thawSnapProcessesV2(snapName, skipThawErrs) // ignore the error, this is best-effort. + + // ignore errors when thawing processes, this is best-effort. + alwaysSkipError := func(_ error) bool { return true } + thawSnapProcessesV2(snapName, alwaysSkipError) return fmt.Errorf("cannot finish freezing processes of snap %q: %v", snapName, err) } -func thawSnapProcessesV2(snapName string, skipErrs bool) error { +func thawSnapProcessesV2(snapName string, skipError func(error) bool) error { + if skipError == nil { + return fmt.Errorf("internal error: skip error is nil") + } thawOne := func(dir string) error { fname := filepath.Join(dir, "cgroup.freeze") - if err := ioutil.WriteFile(fname, []byte("0"), 0644); err != nil && os.IsNotExist(err) { + if err := writeExistingFile(fname, []byte("0"), 0644); err != nil && os.IsNotExist(err) { // the group may be gone already return nil - } else if err != nil && !skipErrs { + } else if err != nil && !skipError(err) { return fmt.Errorf("cannot thaw processes of snap %q, %v", snapName, err) } return nil } - return applyToSnap(snapName, thawOne, skipErrs) + return applyToSnap(snapName, thawOne, skipError) } func thawSnapProcessesImplV2(snapName string) error { - const skipErrs = false - return thawSnapProcessesV2(snapName, skipErrs) + // thaw skipping ENOENT errors + return thawSnapProcessesV2(snapName, os.IsNotExist) } // MockFreezing replaces the real implementation of freeze and thaw. diff --git a/sandbox/cgroup/freezer_test.go b/sandbox/cgroup/freezer_test.go index 16f346d4b3..22bcfb5854 100644 --- a/sandbox/cgroup/freezer_test.go +++ b/sandbox/cgroup/freezer_test.go @@ -24,6 +24,8 @@ import ( "io/ioutil" "os" "path/filepath" + "sort" + "strings" . "gopkg.in/check.v1" @@ -277,6 +279,9 @@ func (s *freezerV2Suite) TestThawSnapProcessesV2(c *C) { } func (s *freezerV2Suite) TestFreezeThawSnapProcessesV2ErrWalking(c *C) { + if os.Getuid() == 0 { + c.Skip("the test cannot be run by the root user") + } defer cgroup.MockVersion(cgroup.V2, nil)() dirs.SetRootDir(c.MkDir()) defer dirs.SetRootDir("") @@ -336,3 +341,92 @@ func (s *freezerV2Suite) TestFreezeThawSnapProcessesV2ErrWalking(c *C) { os.Chmod(filepath.Dir(gUnfreeze), 0755) c.Check(gUnfreeze, testutil.FileEquals, "1") } + +func (s *freezerV2Suite) TestFreezeThawSnapProcessesV2ErrNotFound(c *C) { + defer cgroup.MockVersion(cgroup.V2, nil)() + dirs.SetRootDir(c.MkDir()) + defer dirs.SetRootDir("") + + // app started by root + g1 := filepath.Join(dirs.GlobalRootDir, "/sys/fs/cgroup/system.slice/snap.foo.app.1234-1234-1234.scope/cgroup.freeze") + g2 := filepath.Join(dirs.GlobalRootDir, "/sys/fs/cgroup/system.slice/snap.foo.svc.service/cgroup.freeze") + + pid := os.Getpid() + procPidCgroup := filepath.Join(dirs.GlobalRootDir, fmt.Sprintf("proc/%v/cgroup", pid)) + c.Assert(os.MkdirAll(filepath.Dir(procPidCgroup), 0755), IsNil) + // mock our own group + c.Assert(ioutil.WriteFile(procPidCgroup, []byte("0::/system.slice/snap.foo.app.own-own-own.scope"), 0755), IsNil) + // prepare the directories, but not the files, those should trigger ENOENT + c.Assert(os.MkdirAll(filepath.Dir(g1), 0755), IsNil) + c.Assert(os.MkdirAll(filepath.Dir(g2), 0755), IsNil) + + err := cgroup.FreezeSnapProcesses("foo") + c.Assert(err, IsNil) + + c.Check(g1, testutil.FileAbsent) + c.Check(g2, testutil.FileAbsent) + + err = cgroup.ThawSnapProcesses("foo") + c.Assert(err, IsNil) + c.Check(g1, testutil.FileAbsent) + c.Check(g2, testutil.FileAbsent) +} + +func (s *freezerV2Suite) TestApplyToSnapCallbacks(c *C) { + defer cgroup.MockVersion(cgroup.V2, nil)() + dirs.SetRootDir(c.MkDir()) + defer dirs.SetRootDir("") + + c.Check(cgroup.ApplyToSnap("foo", nil, nil), ErrorMatches, "internal error: action is nil") + nop := func(_ string) error { return nil } + c.Check(cgroup.ApplyToSnap("foo", nop, nil), ErrorMatches, "internal error: skip error is nil") + + g := filepath.Join(dirs.GlobalRootDir, "/sys/fs/cgroup/system.slice/snap.foo.app.1234-1234-1234.scope/cgroup.freeze") + gErr := filepath.Join(dirs.GlobalRootDir, "/sys/fs/cgroup/system.slice/snap.foo.app.fail.scope/cgroup.freeze") + + for _, p := range []string{g, gErr} { + c.Assert(os.MkdirAll(filepath.Dir(p), 0755), IsNil) + // groups aren't frozen + c.Assert(ioutil.WriteFile(p, []byte("0"), 0644), IsNil) + } + + var visited []string + err := cgroup.ApplyToSnap("foo", + func(p string) error { + visited = append(visited, p) + return nil + }, + func(err error) bool { + return true + }) + c.Assert(err, IsNil) + sort.Strings(visited) + c.Check(visited, DeepEquals, []string{filepath.Dir(g), filepath.Dir(gErr)}) + + visited = nil + skip := true + var errors []string + maybeFail := func(p string) error { + visited = append(visited, p) + if strings.HasSuffix(p, "fail.scope") { + return fmt.Errorf("do not skip") + } + return nil + } + maybeSkip := func(err error) bool { + errors = append(errors, err.Error()) + return skip + } + err = cgroup.ApplyToSnap("foo", maybeFail, maybeSkip) + c.Assert(err, IsNil) + c.Check(visited, DeepEquals, []string{filepath.Dir(g), filepath.Dir(gErr)}) + c.Check(errors, DeepEquals, []string{"do not skip"}) + + skip = false + visited = nil + errors = nil + err = cgroup.ApplyToSnap("foo", maybeFail, maybeSkip) + c.Assert(err, ErrorMatches, "do not skip") + c.Check(visited, DeepEquals, []string{filepath.Dir(g), filepath.Dir(gErr)}) + c.Check(errors, DeepEquals, []string{"do not skip"}) +} diff --git a/spread.yaml b/spread.yaml index e0baa192fe..19992a0ca1 100644 --- a/spread.yaml +++ b/spread.yaml @@ -85,6 +85,8 @@ backends: workers: 6 - ubuntu-16.04-64: workers: 8 + - ubuntu-18.04-32: + workers: 6 - ubuntu-18.04-64: workers: 8 - ubuntu-20.04-64: diff --git a/tests/lib/pkgdb.sh b/tests/lib/pkgdb.sh index 8de60b321a..40f2c71d3d 100755 --- a/tests/lib/pkgdb.sh +++ b/tests/lib/pkgdb.sh @@ -550,7 +550,7 @@ pkg_dependencies_ubuntu_classic(){ ubuntu-14.04-*) pkg_linux_image_extra ;; - ubuntu-16.04-32) + ubuntu-16.04-32|ubuntu-18.04-32) echo " dbus-user-session gccgo-6 diff --git a/tests/lib/snaps/store/test-snapd-refresh-control-provider.v1/build-aux/snap/snapcraft.yaml b/tests/lib/snaps/store/test-snapd-refresh-control-provider.v1/build-aux/snap/snapcraft.yaml new file mode 100644 index 0000000000..8705f4ea4a --- /dev/null +++ b/tests/lib/snaps/store/test-snapd-refresh-control-provider.v1/build-aux/snap/snapcraft.yaml @@ -0,0 +1,24 @@ +name: test-snapd-refresh-control-provider +version: 1.0.0 +summary: Test snap for gate-auto-refresh-hook feature - content slot provider. +description: | + Test snap for refresh control (gate-auto-refresh-hook) feature content slot + provider. +grade: stable +confinement: strict +type: app +base: core18 +architectures: + - build-on: amd64 + run-on: all + +parts: + test-snapd-refresh-control-provider: + plugin: nil + +slots: + content: + interface: content + content: test-content + read: + - / diff --git a/tests/lib/snaps/store/test-snapd-refresh-control-provider.v2/build-aux/snap/snapcraft.yaml b/tests/lib/snaps/store/test-snapd-refresh-control-provider.v2/build-aux/snap/snapcraft.yaml new file mode 100644 index 0000000000..da1d1bfab1 --- /dev/null +++ b/tests/lib/snaps/store/test-snapd-refresh-control-provider.v2/build-aux/snap/snapcraft.yaml @@ -0,0 +1,24 @@ +name: test-snapd-refresh-control-provider +version: 2.0.0 +summary: Test snap for gate-auto-refresh-hook feature - content slot provider. +description: | + Test snap for refresh control (gate-auto-refresh-hook) feature content slot + provider. +grade: stable +confinement: strict +type: app +base: core18 +architectures: + - build-on: amd64 + run-on: all + +parts: + test-snapd-refresh-control-provider: + plugin: nil + +slots: + content: + interface: content + content: test-content + read: + - / diff --git a/tests/lib/snaps/store/test-snapd-refresh-control.v1/build-aux/snap/hooks/gate-auto-refresh b/tests/lib/snaps/store/test-snapd-refresh-control.v1/build-aux/snap/hooks/gate-auto-refresh new file mode 100644 index 0000000000..7b8eb4fa7c --- /dev/null +++ b/tests/lib/snaps/store/test-snapd-refresh-control.v1/build-aux/snap/hooks/gate-auto-refresh @@ -0,0 +1,10 @@ +#!/bin/sh + +CONTROL_FILE="$SNAP_COMMON"/control + +snapctl refresh --pending > "$SNAP_COMMON"/debug.log + +if [ -f "$CONTROL_FILE" ]; then + COMMAND=$(cat "$CONTROL_FILE") + snapctl refresh "$COMMAND" >> "$SNAP_COMMON"/debug.log 2>&1 +fi diff --git a/tests/lib/snaps/store/test-snapd-refresh-control.v1/build-aux/snap/snapcraft.yaml b/tests/lib/snaps/store/test-snapd-refresh-control.v1/build-aux/snap/snapcraft.yaml new file mode 100644 index 0000000000..44b07318c2 --- /dev/null +++ b/tests/lib/snaps/store/test-snapd-refresh-control.v1/build-aux/snap/snapcraft.yaml @@ -0,0 +1,23 @@ +name: test-snapd-refresh-control +version: 1.0.0 +summary: Test snap for gate-auto-refresh-hook feature. +description: | + Test snap for refresh control (gate-auto-refresh-hook) feature. The behavior + of the gate-auto-refresh hook of this snap can be driven by a control file + in /var/snap/test-snapd-refresh-control/common/control +grade: stable +confinement: strict +base: core18 +architectures: + - build-on: amd64 + run-on: all + +parts: + test-snapd-refresh-control: + plugin: nil + +plugs: + content: + interface: content + content: test-content + target: $SNAP/content diff --git a/tests/lib/snaps/store/test-snapd-refresh-control.v2/build-aux/snap/hooks/gate-auto-refresh b/tests/lib/snaps/store/test-snapd-refresh-control.v2/build-aux/snap/hooks/gate-auto-refresh new file mode 100644 index 0000000000..7b8eb4fa7c --- /dev/null +++ b/tests/lib/snaps/store/test-snapd-refresh-control.v2/build-aux/snap/hooks/gate-auto-refresh @@ -0,0 +1,10 @@ +#!/bin/sh + +CONTROL_FILE="$SNAP_COMMON"/control + +snapctl refresh --pending > "$SNAP_COMMON"/debug.log + +if [ -f "$CONTROL_FILE" ]; then + COMMAND=$(cat "$CONTROL_FILE") + snapctl refresh "$COMMAND" >> "$SNAP_COMMON"/debug.log 2>&1 +fi diff --git a/tests/lib/snaps/store/test-snapd-refresh-control.v2/build-aux/snap/snapcraft.yaml b/tests/lib/snaps/store/test-snapd-refresh-control.v2/build-aux/snap/snapcraft.yaml new file mode 100644 index 0000000000..8e67bd03e0 --- /dev/null +++ b/tests/lib/snaps/store/test-snapd-refresh-control.v2/build-aux/snap/snapcraft.yaml @@ -0,0 +1,23 @@ +name: test-snapd-refresh-control +version: 2.0.0 +summary: Test snap for gate-auto-refresh-hook feature. +description: | + Test snap for refresh control (gate-auto-refresh-hook) feature. The behavior + of the gate-auto-refresh hook of this snap can be driven by a control file + in /var/snap/test-snapd-refresh-control/common/control +grade: stable +confinement: strict +base: core18 +architectures: + - build-on: amd64 + run-on: all + +parts: + test-snapd-refresh-control: + plugin: nil + +plugs: + content: + interface: content + content: test-content + target: $SNAP/content diff --git a/tests/main/auto-refresh-gating/task.yaml b/tests/main/auto-refresh-gating/task.yaml new file mode 100644 index 0000000000..7855c3860f --- /dev/null +++ b/tests/main/auto-refresh-gating/task.yaml @@ -0,0 +1,167 @@ +summary: Check that auto-refresh with gate-auto-refresh hooks works. + +details: | + Test auto-refresh with gate-auto-refresh hook support enabled + (experimental.gate-auto-refresh-hook feature) and verify the hook can control + automatic refreshes. The test uses two test snaps, one of them + being a content provider of the other. There are a few versions of these + snaps in the store (in stable/beta/edge channels) for this test. + +environment: + SNAP_NAME: test-snapd-refresh-control + CONTENT_SNAP_NAME: test-snapd-refresh-control-provider + CONTROL_FILE: /var/snap/test-snapd-refresh-control/common/control + DEBUG_LOG_FILE: /var/snap/test-snapd-refresh-control/common/debug.log + +prepare: | + snap install --devmode jq + snap set system experimental.gate-auto-refresh-hook=true + +debug: | + jq -r '.data["snaps-hold"]' < /var/lib/snapd/state.json || true + +execute: | + force_autorefresh() { + echo "And force auto-refresh to happen" + jq ".data[\"last-refresh\"] = \"2007-08-22T09:30:44.449455783+01:00\"" /var/lib/snapd/state.json > /var/lib/snapd/state.json.new + mv /var/lib/snapd/state.json.new /var/lib/snapd/state.json + } + + wait_for_autorefresh() { + local EXPECTED_SNAP="$1" + local LAST_CHANGE_ID="$2" + local CHANGE_ID="$2" + for _ in $(seq 200); do + # get last 2 lines of snap changes (the last one is always empty), match + # auto-refresh change of the expected snap; only proceed if the + # change has greater change id than the previously matched auto-refresh + # (this way we can match consecutive auto-refreshes for same snap). + if CHANGES=$(snap changes | tail -2 | grep "Done.*Auto-refresh snap \"$EXPECTED_SNAP\""); then + CHANGE_ID=$(echo "$CHANGES" | awk '{print $1}') + if [ "$CHANGE_ID" -gt "$LAST_CHANGE_ID" ]; then + break + fi + fi + snap debug ensure-state-soon + sleep 1 + done + if [ "$LAST_CHANGE_ID" -eq "$CHANGE_ID" ]; then + echo "Expected a new auto-refresh change for $EXPECTED_SNAP with id greater than $LAST_CHANGE_ID, but it didn't happen" + exit 1 + fi + echo "$CHANGE_ID" + } + + force_channel_change() { + local SNAP="$1" + local CHANNEL="$2" + echo "Modify snap $SNAP to track the $CHANNEL channel" + jq ".data.snaps[\"$SNAP\"].channel = \"$CHANNEL\"" /var/lib/snapd/state.json > /var/lib/snapd/state.json.new + mv /var/lib/snapd/state.json.new /var/lib/snapd/state.json + } + + LAST_REFRESH_CHANGE_ID=1 + + echo "Install test snaps" + snap install "$SNAP_NAME" + snap install "$CONTENT_SNAP_NAME" + + snap connect "$SNAP_NAME:content" "$CONTENT_SNAP_NAME:content" + + # sanity check + snap list | MATCH "$SNAP_NAME +1\.0\.0" + snap list | MATCH "$CONTENT_SNAP_NAME +1\.0\.0" + + snap set core refresh.schedule="0:00-23:59" + + force_channel_change "$CONTENT_SNAP_NAME" beta + + # force auto-refresh a few times, we expect the gate-auto-refresh + # hook of test-snapd-refresh-control to be executed because of the refresh + # of content provider snap. The refresh is expected to be held every time. + for _ in $(seq 1 3); do + systemctl stop snapd.{service,socket} + + # Request the snap to hold the refresh (itself and its content provider). + echo "--hold" > "$CONTROL_FILE" + + echo "Trigger auto-refresh of test-snapd-refresh-control-provider but hold it via test-snapd-refresh-control's hook" + force_autorefresh + systemctl start snapd.{service,socket} + LAST_REFRESH_CHANGE_ID=$(wait_for_autorefresh "$CONTENT_SNAP_NAME" "$LAST_REFRESH_CHANGE_ID") + + snap change --last=auto-refresh | MATCH "Run auto-refresh for ready snaps" + snap change --last=auto-refresh | MATCH "Run hook gate-auto-refresh of snap \"$SNAP_NAME\"" + + echo "Check that the --pending information indicates restart due to the content slot" + MATCH "restart: +true" < "$DEBUG_LOG_FILE" + MATCH "base: +false" < "$DEBUG_LOG_FILE" + MATCH "channel: +latest/stable" < "$DEBUG_LOG_FILE" + # test-snapd-refresh-control doesn't have update, so pending/version are not + # available. + MATCH "pending: none" < "$DEBUG_LOG_FILE" + NOMATCH "version:" < "$DEBUG_LOG_FILE" + + echo "Ensure our content snap was held and is still at version 1" + snap list | MATCH "$CONTENT_SNAP_NAME +1\.0\.0" + # sanity check for the gating snap. + snap list | MATCH "$SNAP_NAME +1\.0\.0" + done + + systemctl stop snapd.{service,socket} + + # force auto-refresh again but this time we expect content provider snap to be + # refreshed because the gating hook of test-snapd-refresh-control calls --proceed. + echo "--proceed" > "$CONTROL_FILE" + + force_autorefresh + systemctl start snapd.{service,socket} + LAST_REFRESH_CHANGE_ID=$(wait_for_autorefresh "$CONTENT_SNAP_NAME" "$LAST_REFRESH_CHANGE_ID") + + snap change --last=auto-refresh | MATCH "Run auto-refresh for ready snaps" + snap change --last=auto-refresh | MATCH "Run hook gate-auto-refresh of snap \"$SNAP_NAME\"" + + echo "Check that the --pending information indicates test-snapd-refresh-control is affected by the content snap" + MATCH "restart: +true" < "$DEBUG_LOG_FILE" + + echo "Ensure our content snap was refreshed" + snap list | MATCH "$CONTENT_SNAP_NAME +2\.0\.0" + # sanity check for the gating snap. + snap list | MATCH "$SNAP_NAME +1\.0\.0" + + systemctl stop snapd.{service,socket} + + # test the scenario where the test-snapd-refresh-control refresh is attempted + # and it holds itself. + echo "Trigger auto-refresh of test-snapd-refresh-control and hold it from its hook" + echo "--hold" > "$CONTROL_FILE" + force_channel_change "$SNAP_NAME" beta + force_autorefresh + + systemctl start snapd.{service,socket} + LAST_REFRESH_CHANGE_ID=$(wait_for_autorefresh "$SNAP_NAME" "$LAST_REFRESH_CHANGE_ID") + + echo "Check that the --pending information contains test-snapd-refresh-control refresh info" + MATCH "pending: +ready" < "$DEBUG_LOG_FILE" + MATCH "channel: +beta" < "$DEBUG_LOG_FILE" + MATCH "version: +2\.0" < "$DEBUG_LOG_FILE" + MATCH "base: +false" < "$DEBUG_LOG_FILE" + MATCH "restart: +false" < "$DEBUG_LOG_FILE" + + echo "Ensure our snap was held" + snap list | MATCH "$SNAP_NAME +1\.0\.0" + + systemctl stop snapd.{service,socket} + + # test the scenario where the test-snapd-refresh-control refresh proceeds. + echo "Trigger auto-refresh of test-snapd-refresh-control and proceed from its hook" + echo "--proceed" > "$CONTROL_FILE" + force_autorefresh + + systemctl start snapd.{service,socket} + LAST_REFRESH_CHANGE_ID=$(wait_for_autorefresh "$SNAP_NAME" "$LAST_REFRESH_CHANGE_ID") + + echo "Ensure our snap was updated" + snap list | MATCH "$SNAP_NAME +2\.0\.0" + + # TODO: edge channel, proceed via default behavior. error behavior (hold). diff --git a/tests/main/desktop-portal-filechooser/task.yaml b/tests/main/desktop-portal-filechooser/task.yaml index 22f32c8c1e..bf6ca7c526 100644 --- a/tests/main/desktop-portal-filechooser/task.yaml +++ b/tests/main/desktop-portal-filechooser/task.yaml @@ -17,7 +17,7 @@ details: | # Only enable the test on systems we know portals to function on. # Expand as needed. # ubuntu-18.04-*: Ships xdg-desktop-portal 0.11 -systems: [ubuntu-18.04-*, ubuntu-2*] +systems: [ubuntu-18.04-64, ubuntu-2*] prepare: | #shellcheck source=tests/lib/desktop-portal.sh diff --git a/tests/main/desktop-portal-open-file/task.yaml b/tests/main/desktop-portal-open-file/task.yaml index 3caf92e3f7..cc207a63a2 100644 --- a/tests/main/desktop-portal-open-file/task.yaml +++ b/tests/main/desktop-portal-open-file/task.yaml @@ -10,7 +10,7 @@ details: | # Only enable the test on systems we know portals to function on. # Expand as needed. -systems: [ubuntu-18.04-*, ubuntu-2*] +systems: [ubuntu-18.04-64, ubuntu-2*] environment: EDITOR_HISTORY: /tmp/editor-history.txt diff --git a/tests/main/desktop-portal-open-uri/task.yaml b/tests/main/desktop-portal-open-uri/task.yaml index 479d1da649..d9e5a14635 100644 --- a/tests/main/desktop-portal-open-uri/task.yaml +++ b/tests/main/desktop-portal-open-uri/task.yaml @@ -7,7 +7,7 @@ details: | # Only enable the test on systems we know portals to function on. # Expand as needed. -systems: [ubuntu-18.04-*, ubuntu-2*] +systems: [ubuntu-18.04-64, ubuntu-2*] environment: BROWSER_HISTORY: /tmp/browser-history.txt diff --git a/tests/main/desktop-portal-screenshot/task.yaml b/tests/main/desktop-portal-screenshot/task.yaml index a329544de1..388e7d0281 100644 --- a/tests/main/desktop-portal-screenshot/task.yaml +++ b/tests/main/desktop-portal-screenshot/task.yaml @@ -21,7 +21,7 @@ details: | # Only enable the test on systems we know portals to function on. # Expand as needed. -systems: [ubuntu-18.04-*, ubuntu-2*] +systems: [ubuntu-18.04-64, ubuntu-2*] prepare: | #shellcheck source=tests/lib/desktop-portal.sh diff --git a/tests/main/preseed-lxd/task.yaml b/tests/main/preseed-lxd/task.yaml index d1d5eebdc9..c3c3aa4118 100644 --- a/tests/main/preseed-lxd/task.yaml +++ b/tests/main/preseed-lxd/task.yaml @@ -5,9 +5,9 @@ details: | command works in lxc container and that the resulting image can be run in a container and seeding finishes successfully. -# this test works only on 18.04 because it requires lxd from deb (lxd snap +# this test works only on 18.04-64 because it requires lxd from deb (lxd snap # as it wouldn't allow mount) and tries to replicate launchpad builder setup. -systems: [ubuntu-18.04-*] +systems: [ubuntu-18.04-64] environment: IMAGE_MOUNTPOINT: /mnt/cloudimg |
