diff options
44 files changed, 2422 insertions, 709 deletions
diff --git a/boot/boot.go b/boot/boot.go index b580dcd1cd..19b1b23a5f 100644 --- a/boot/boot.go +++ b/boot/boot.go @@ -135,7 +135,7 @@ func applicable(s snap.PlaceInfo, t snap.Type, model Model, onClassic bool) bool // InUse checks if the given name/revision is used in the // boot environment func InUse(name string, rev snap.Revision) bool { - bootloader, err := bootloader.Find() + bootloader, err := bootloader.Find("", nil) if err != nil { logger.Noticef("cannot get boot settings: %s", err) return false @@ -182,7 +182,7 @@ func GetCurrentBoot(t snap.Type) (*NameAndRevision, error) { return nil, fmt.Errorf("internal error: cannot find boot revision for snap type %q", t) } - bloader, err := bootloader.Find() + bloader, err := bootloader.Find("", nil) if err != nil { return nil, fmt.Errorf("cannot get boot settings: %s", err) } @@ -244,7 +244,7 @@ func nameAndRevnoFromSnap(sn string) (*NameAndRevision, error) { // will set snap_mode="" and the system will boot with the known good // values from snap_{core,kernel} func MarkBootSuccessful() error { - bl, err := bootloader.Find() + bl, err := bootloader.Find("", nil) if err != nil { return fmt.Errorf("cannot mark boot successful: %s", err) } diff --git a/boot/kernel_os.go b/boot/kernel_os.go index 324cf052d0..41d552e80a 100644 --- a/boot/kernel_os.go +++ b/boot/kernel_os.go @@ -39,7 +39,7 @@ var _ BootParticipant = (*coreBootParticipant)(nil) func (*coreBootParticipant) IsTrivial() bool { return false } func (bs *coreBootParticipant) SetNextBoot() error { - bootloader, err := bootloader.Find() + bootloader, err := bootloader.Find("", nil) if err != nil { return fmt.Errorf("cannot set next boot: %s", err) } @@ -83,7 +83,7 @@ func (bs *coreBootParticipant) SetNextBoot() error { } func (bs *coreBootParticipant) ChangeRequiresReboot() bool { - bootloader, err := bootloader.Find() + bootloader, err := bootloader.Find("", nil) if err != nil { logger.Noticef("cannot get boot settings: %s", err) return false @@ -124,7 +124,7 @@ func (*coreKernel) IsTrivial() bool { return false } func (k *coreKernel) RemoveKernelAssets() error { // XXX: shouldn't we check the snap type? - bootloader, err := bootloader.Find() + bootloader, err := bootloader.Find("", nil) if err != nil { return fmt.Errorf("cannot remove kernel assets: %s", err) } @@ -134,7 +134,7 @@ func (k *coreKernel) RemoveKernelAssets() error { } func (k *coreKernel) ExtractKernelAssets(snapf snap.Container) error { - bootloader, err := bootloader.Find() + bootloader, err := bootloader.Find("", nil) if err != nil { return fmt.Errorf("cannot extract kernel assets: %s", err) } diff --git a/boot/kernel_os_test.go b/boot/kernel_os_test.go index 25d15196f2..05160a405c 100644 --- a/boot/kernel_os_test.go +++ b/boot/kernel_os_test.go @@ -29,6 +29,7 @@ import ( "github.com/snapcore/snapd/boot" "github.com/snapcore/snapd/bootloader" "github.com/snapcore/snapd/bootloader/bootloadertest" + "github.com/snapcore/snapd/dirs" "github.com/snapcore/snapd/logger" "github.com/snapcore/snapd/osutil" "github.com/snapcore/snapd/snap" @@ -223,10 +224,10 @@ func (s *ubootBootSetSuite) forceUbootBootloader(c *C) bootloader.Bootloader { mockGadgetDir := c.MkDir() err := ioutil.WriteFile(filepath.Join(mockGadgetDir, "uboot.conf"), nil, 0644) c.Assert(err, IsNil) - err = bootloader.InstallBootConfig(mockGadgetDir) + err = bootloader.InstallBootConfig(mockGadgetDir, dirs.GlobalRootDir) c.Assert(err, IsNil) - bloader, err := bootloader.Find() + bloader, err := bootloader.Find("", nil) c.Assert(err, IsNil) c.Check(bloader, NotNil) bootloader.Force(bloader) @@ -302,10 +303,10 @@ func (s *grubBootSetSuite) forceGrubBootloader(c *C) bootloader.Bootloader { mockGadgetDir := c.MkDir() err := ioutil.WriteFile(filepath.Join(mockGadgetDir, "grub.conf"), nil, 0644) c.Assert(err, IsNil) - err = bootloader.InstallBootConfig(mockGadgetDir) + err = bootloader.InstallBootConfig(mockGadgetDir, dirs.GlobalRootDir) c.Assert(err, IsNil) - bloader, err := bootloader.Find() + bloader, err := bootloader.Find("", nil) c.Assert(err, IsNil) c.Check(bloader, NotNil) bloader.SetBootVars(map[string]string{ diff --git a/bootloader/androidboot.go b/bootloader/androidboot.go index 952644618a..9ab8ddd91a 100644 --- a/bootloader/androidboot.go +++ b/bootloader/androidboot.go @@ -24,16 +24,17 @@ import ( "path/filepath" "github.com/snapcore/snapd/bootloader/androidbootenv" - "github.com/snapcore/snapd/dirs" "github.com/snapcore/snapd/osutil" "github.com/snapcore/snapd/snap" ) -type androidboot struct{} +type androidboot struct { + rootdir string +} // newAndroidboot creates a new Androidboot bootloader object -func newAndroidBoot() Bootloader { - a := &androidboot{} +func newAndroidBoot(rootdir string) Bootloader { + a := &androidboot{rootdir: rootdir} if !osutil.FileExists(a.ConfigFile()) { return nil } @@ -44,8 +45,15 @@ func (a *androidboot) Name() string { return "androidboot" } +func (a *androidboot) setRootDir(rootdir string) { + a.rootdir = rootdir +} + func (a *androidboot) dir() string { - return filepath.Join(dirs.GlobalRootDir, "/boot/androidboot") + if a.rootdir == "" { + panic("internal error: unset rootdir") + } + return filepath.Join(a.rootdir, "/boot/androidboot") } func (a *androidboot) ConfigFile() string { diff --git a/bootloader/androidboot_test.go b/bootloader/androidboot_test.go index f983d541bb..8ebfb959c3 100644 --- a/bootloader/androidboot_test.go +++ b/bootloader/androidboot_test.go @@ -25,7 +25,6 @@ import ( . "gopkg.in/check.v1" "github.com/snapcore/snapd/bootloader" - "github.com/snapcore/snapd/dirs" "github.com/snapcore/snapd/osutil" "github.com/snapcore/snapd/snap" "github.com/snapcore/snapd/snap/snaptest" @@ -41,22 +40,21 @@ func (s *androidBootTestSuite) SetUpTest(c *C) { s.baseBootenvTestSuite.SetUpTest(c) // the file needs to exist for androidboot object to be created - bootloader.MockAndroidBootFile(c, 0644) + bootloader.MockAndroidBootFile(c, s.rootdir, 0644) } func (s *androidBootTestSuite) TestNewAndroidbootNoAndroidbootReturnsNil(c *C) { - dirs.GlobalRootDir = "/something/not/there" - a := bootloader.NewAndroidBoot() + a := bootloader.NewAndroidBoot("/something/not/there") c.Assert(a, IsNil) } func (s *androidBootTestSuite) TestNewAndroidboot(c *C) { - a := bootloader.NewAndroidBoot() + a := bootloader.NewAndroidBoot(s.rootdir) c.Assert(a, NotNil) } func (s *androidBootTestSuite) TestSetGetBootVar(c *C) { - a := bootloader.NewAndroidBoot() + a := bootloader.NewAndroidBoot(s.rootdir) bootVars := map[string]string{"snap_mode": "try"} a.SetBootVars(bootVars) @@ -67,7 +65,7 @@ func (s *androidBootTestSuite) TestSetGetBootVar(c *C) { } func (s *androidBootTestSuite) TestExtractKernelAssetsNoUnpacksKernel(c *C) { - a := bootloader.NewAndroidBoot() + a := bootloader.NewAndroidBoot(s.rootdir) c.Assert(a, NotNil) @@ -91,6 +89,6 @@ func (s *androidBootTestSuite) TestExtractKernelAssetsNoUnpacksKernel(c *C) { c.Assert(err, IsNil) // kernel is *not* here - kernimg := filepath.Join(dirs.GlobalRootDir, "boot", "androidboot", "ubuntu-kernel_42.snap", "kernel.img") + kernimg := filepath.Join(s.rootdir, "boot", "androidboot", "ubuntu-kernel_42.snap", "kernel.img") c.Assert(osutil.FileExists(kernimg), Equals, false) } diff --git a/bootloader/bootloader.go b/bootloader/bootloader.go index 197db10105..c44f9a39ff 100644 --- a/bootloader/bootloader.go +++ b/bootloader/bootloader.go @@ -25,6 +25,7 @@ import ( "os" "path/filepath" + "github.com/snapcore/snapd/dirs" "github.com/snapcore/snapd/osutil" "github.com/snapcore/snapd/snap" ) @@ -56,16 +57,23 @@ type Bootloader interface { RemoveKernelAssets(s snap.PlaceInfo) error } +type installableBootloader interface { + Bootloader + setRootDir(string) +} + // InstallBootConfig installs the bootloader config from the gadget // snap dir into the right place. -func InstallBootConfig(gadgetDir string) error { - for _, bl := range []Bootloader{&grub{}, &uboot{}, &androidboot{}} { +func InstallBootConfig(gadgetDir, rootDir string) error { + for _, bl := range []installableBootloader{&grub{}, &uboot{}, &androidboot{}} { // the bootloader config file has to be root of the gadget snap gadgetFile := filepath.Join(gadgetDir, bl.Name()+".conf") if !osutil.FileExists(gadgetFile) { continue } + bl.setRootDir(rootDir) + systemFile := bl.ConfigFile() if err := os.MkdirAll(filepath.Dir(systemFile), 0755); err != nil { return err @@ -81,25 +89,37 @@ var ( forcedError error ) -// Find returns the bootloader for the given system -// or an error if no bootloader is found -func Find() (Bootloader, error) { +// Options carries bootloader options. +type Options struct { + // PrepareImageTime indicates whether the booloader is being + // used at prepare-image time, that means not on a runtime + // system. + PrepareImageTime bool +} + +// Find returns the bootloader for the system +// or an error if no bootloader is found. +func Find(rootdir string, _ *Options) (Bootloader, error) { if forcedBootloader != nil || forcedError != nil { return forcedBootloader, forcedError } + if rootdir == "" { + rootdir = dirs.GlobalRootDir + } + // try uboot - if uboot := newUboot(); uboot != nil { + if uboot := newUboot(rootdir); uboot != nil { return uboot, nil } // no, try grub - if grub := newGrub(); grub != nil { + if grub := newGrub(rootdir); grub != nil { return grub, nil } // no, try androidboot - if androidboot := newAndroidBoot(); androidboot != nil { + if androidboot := newAndroidBoot(rootdir); androidboot != nil { return androidboot, nil } diff --git a/bootloader/bootloader_test.go b/bootloader/bootloader_test.go index bc603465da..65bd7900bd 100644 --- a/bootloader/bootloader_test.go +++ b/bootloader/bootloader_test.go @@ -29,7 +29,7 @@ import ( "github.com/snapcore/snapd/bootloader" "github.com/snapcore/snapd/bootloader/bootloadertest" - "github.com/snapcore/snapd/dirs" + //"github.com/snapcore/snapd/dirs" "github.com/snapcore/snapd/osutil" "github.com/snapcore/snapd/snap" "github.com/snapcore/snapd/testutil" @@ -47,13 +47,14 @@ vendor: Someone type baseBootenvTestSuite struct { testutil.BaseTest + + rootdir string } func (s *baseBootenvTestSuite) SetUpTest(c *C) { s.BaseTest.SetUpTest(c) s.AddCleanup(snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {})) - dirs.SetRootDir(c.MkDir()) - s.AddCleanup(func() { dirs.SetRootDir("") }) + s.rootdir = c.MkDir() } type bootenvTestSuite struct { @@ -74,7 +75,7 @@ func (s *bootenvTestSuite) TestForceBootloader(c *C) { bootloader.Force(s.b) defer bootloader.Force(nil) - got, err := bootloader.Find() + got, err := bootloader.Find("", nil) c.Assert(err, IsNil) c.Check(got, Equals, s.b) } @@ -84,13 +85,13 @@ func (s *bootenvTestSuite) TestForceBootloaderError(c *C) { bootloader.ForceError(myErr) defer bootloader.ForceError(nil) - got, err := bootloader.Find() + got, err := bootloader.Find("", nil) c.Assert(err, Equals, myErr) c.Check(got, IsNil) } func (s *bootenvTestSuite) TestInstallBootloaderConfigNoConfig(c *C) { - err := bootloader.InstallBootConfig(c.MkDir()) + err := bootloader.InstallBootConfig(c.MkDir(), s.rootdir) c.Assert(err, ErrorMatches, `cannot find boot config in.*`) } @@ -103,9 +104,9 @@ func (s *bootenvTestSuite) TestInstallBootloaderConfig(c *C) { mockGadgetDir := c.MkDir() err := ioutil.WriteFile(filepath.Join(mockGadgetDir, t.gadgetFile), nil, 0644) c.Assert(err, IsNil) - err = bootloader.InstallBootConfig(mockGadgetDir) + err = bootloader.InstallBootConfig(mockGadgetDir, s.rootdir) c.Assert(err, IsNil) - fn := filepath.Join(dirs.GlobalRootDir, t.systemFile) + fn := filepath.Join(s.rootdir, t.systemFile) c.Assert(osutil.FileExists(fn), Equals, true) } } diff --git a/bootloader/export_test.go b/bootloader/export_test.go index 67dbd2ef53..2433a359b9 100644 --- a/bootloader/export_test.go +++ b/bootloader/export_test.go @@ -29,24 +29,24 @@ import ( ) // creates a new Androidboot bootloader object -func NewAndroidBoot() Bootloader { - return newAndroidBoot() +func NewAndroidBoot(rootdir string) Bootloader { + return newAndroidBoot(rootdir) } -func MockAndroidBootFile(c *C, mode os.FileMode) { - f := &androidboot{} +func MockAndroidBootFile(c *C, rootdir string, mode os.FileMode) { + f := &androidboot{rootdir: rootdir} err := os.MkdirAll(f.dir(), 0755) c.Assert(err, IsNil) err = ioutil.WriteFile(f.ConfigFile(), nil, mode) c.Assert(err, IsNil) } -func NewUboot() Bootloader { - return newUboot() +func NewUboot(rootdir string) Bootloader { + return newUboot(rootdir) } -func MockUbootFiles(c *C) { - u := &uboot{} +func MockUbootFiles(c *C, rootdir string) { + u := &uboot{rootdir: rootdir} err := os.MkdirAll(u.dir(), 0755) c.Assert(err, IsNil) @@ -57,12 +57,12 @@ func MockUbootFiles(c *C) { c.Assert(err, IsNil) } -func NewGrub() Bootloader { - return newGrub() +func NewGrub(rootdir string) Bootloader { + return newGrub(rootdir) } -func MockGrubFiles(c *C) { - g := &grub{} +func MockGrubFiles(c *C, rootdir string) { + g := &grub{rootdir: rootdir} err := os.MkdirAll(g.dir(), 0755) c.Assert(err, IsNil) err = ioutil.WriteFile(g.ConfigFile(), nil, 0644) diff --git a/bootloader/grub.go b/bootloader/grub.go index 2364b61ae4..fe7999b152 100644 --- a/bootloader/grub.go +++ b/bootloader/grub.go @@ -24,16 +24,17 @@ import ( "path/filepath" "github.com/snapcore/snapd/bootloader/grubenv" - "github.com/snapcore/snapd/dirs" "github.com/snapcore/snapd/osutil" "github.com/snapcore/snapd/snap" ) -type grub struct{} +type grub struct { + rootdir string +} // newGrub create a new Grub bootloader object -func newGrub() Bootloader { - g := &grub{} +func newGrub(rootdir string) Bootloader { + g := &grub{rootdir: rootdir} if !osutil.FileExists(g.ConfigFile()) { return nil } @@ -45,8 +46,15 @@ func (g *grub) Name() string { return "grub" } +func (g *grub) setRootDir(rootdir string) { + g.rootdir = rootdir +} + func (g *grub) dir() string { - return filepath.Join(dirs.GlobalRootDir, "/boot/grub") + if g.rootdir == "" { + panic("internal error: unset rootdir") + } + return filepath.Join(g.rootdir, "/boot/grub") } func (g *grub) ConfigFile() string { diff --git a/bootloader/grub_test.go b/bootloader/grub_test.go index 96a207f2a1..562affdd02 100644 --- a/bootloader/grub_test.go +++ b/bootloader/grub_test.go @@ -44,9 +44,9 @@ var _ = Suite(&grubTestSuite{}) func (s *grubTestSuite) SetUpTest(c *C) { s.baseBootenvTestSuite.SetUpTest(c) - bootloader.MockGrubFiles(c) + bootloader.MockGrubFiles(c, s.rootdir) - s.bootdir = filepath.Join(dirs.GlobalRootDir, "boot") + s.bootdir = filepath.Join(s.rootdir, "boot") } // grubEditenvCmd finds the right grub{,2}-editenv command @@ -59,25 +59,25 @@ func grubEditenvCmd() string { return "" } -func grubEnvPath() string { - return filepath.Join(dirs.GlobalRootDir, "boot/grub/grubenv") +func grubEnvPath(rootdir string) string { + return filepath.Join(rootdir, "boot/grub/grubenv") } -func grubEditenvSet(c *C, key, value string) { +func (s *grubTestSuite) grubEditenvSet(c *C, key, value string) { if grubEditenvCmd() == "" { c.Skip("grub{,2}-editenv is not available") } - err := exec.Command(grubEditenvCmd(), grubEnvPath(), "set", fmt.Sprintf("%s=%s", key, value)).Run() + err := exec.Command(grubEditenvCmd(), grubEnvPath(s.rootdir), "set", fmt.Sprintf("%s=%s", key, value)).Run() c.Assert(err, IsNil) } -func grubEditenvGet(c *C, key string) string { +func (s *grubTestSuite) grubEditenvGet(c *C, key string) string { if grubEditenvCmd() == "" { c.Skip("grub{,2}-editenv is not available") } - output, err := exec.Command(grubEditenvCmd(), grubEnvPath(), "list").CombinedOutput() + output, err := exec.Command(grubEditenvCmd(), grubEnvPath(s.rootdir), "list").CombinedOutput() c.Assert(err, IsNil) cfg := goconfigparser.New() cfg.AllowNoSectionHeader = true @@ -89,20 +89,18 @@ func grubEditenvGet(c *C, key string) string { } func (s *grubTestSuite) makeFakeGrubEnv(c *C) { - grubEditenvSet(c, "k", "v") + s.grubEditenvSet(c, "k", "v") } func (s *grubTestSuite) TestNewGrubNoGrubReturnsNil(c *C) { - dirs.GlobalRootDir = "/something/not/there" - - g := bootloader.NewGrub() + g := bootloader.NewGrub("/something/not/there") c.Assert(g, IsNil) } func (s *grubTestSuite) TestNewGrub(c *C) { s.makeFakeGrubEnv(c) - g := bootloader.NewGrub() + g := bootloader.NewGrub(s.rootdir) c.Assert(g, NotNil) c.Assert(g.Name(), Equals, "grub") } @@ -110,16 +108,27 @@ func (s *grubTestSuite) TestNewGrub(c *C) { func (s *grubTestSuite) TestGetBootloaderWithGrub(c *C) { s.makeFakeGrubEnv(c) - bootloader, err := bootloader.Find() + bootloader, err := bootloader.Find(s.rootdir, nil) + c.Assert(err, IsNil) + c.Assert(bootloader.Name(), Equals, "grub") +} + +func (s *grubTestSuite) TestGetBootloaderWithGrubWithDefaultRoot(c *C) { + s.makeFakeGrubEnv(c) + + dirs.SetRootDir(s.rootdir) + defer func() { dirs.SetRootDir("") }() + + bootloader, err := bootloader.Find("", nil) c.Assert(err, IsNil) c.Assert(bootloader.Name(), Equals, "grub") } func (s *grubTestSuite) TestGetBootVer(c *C) { s.makeFakeGrubEnv(c) - grubEditenvSet(c, "snap_mode", "regular") + s.grubEditenvSet(c, "snap_mode", "regular") - g := bootloader.NewGrub() + g := bootloader.NewGrub(s.rootdir) v, err := g.GetBootVars("snap_mode") c.Assert(err, IsNil) c.Check(v, HasLen, 1) @@ -129,21 +138,21 @@ func (s *grubTestSuite) TestGetBootVer(c *C) { func (s *grubTestSuite) TestSetBootVer(c *C) { s.makeFakeGrubEnv(c) - g := bootloader.NewGrub() + g := bootloader.NewGrub(s.rootdir) err := g.SetBootVars(map[string]string{ "k1": "v1", "k2": "v2", }) c.Assert(err, IsNil) - c.Check(grubEditenvGet(c, "k1"), Equals, "v1") - c.Check(grubEditenvGet(c, "k2"), Equals, "v2") + c.Check(s.grubEditenvGet(c, "k1"), Equals, "v1") + c.Check(s.grubEditenvGet(c, "k2"), Equals, "v2") } func (s *grubTestSuite) TestExtractKernelAssetsNoUnpacksKernelForGrub(c *C) { s.makeFakeGrubEnv(c) - g := bootloader.NewGrub() + g := bootloader.NewGrub(s.rootdir) files := [][]string{ {"kernel.img", "I'm a kernel"}, @@ -172,7 +181,7 @@ func (s *grubTestSuite) TestExtractKernelAssetsNoUnpacksKernelForGrub(c *C) { func (s *grubTestSuite) TestExtractKernelForceWorks(c *C) { s.makeFakeGrubEnv(c) - g := bootloader.NewGrub() + g := bootloader.NewGrub(s.rootdir) c.Assert(g, NotNil) files := [][]string{ diff --git a/bootloader/uboot.go b/bootloader/uboot.go index f460b47395..0a475fcfdb 100644 --- a/bootloader/uboot.go +++ b/bootloader/uboot.go @@ -23,16 +23,17 @@ import ( "path/filepath" "github.com/snapcore/snapd/bootloader/ubootenv" - "github.com/snapcore/snapd/dirs" "github.com/snapcore/snapd/osutil" "github.com/snapcore/snapd/snap" ) -type uboot struct{} +type uboot struct { + rootdir string +} // newUboot create a new Uboot bootloader object -func newUboot() Bootloader { - u := &uboot{} +func newUboot(rootdir string) Bootloader { + u := &uboot{rootdir: rootdir} if !osutil.FileExists(u.envFile()) { return nil } @@ -44,8 +45,15 @@ func (u *uboot) Name() string { return "uboot" } +func (u *uboot) setRootDir(rootdir string) { + u.rootdir = rootdir +} + func (u *uboot) dir() string { - return filepath.Join(dirs.GlobalRootDir, "/boot/uboot") + if u.rootdir == "" { + panic("internal error: unset rootdir") + } + return filepath.Join(u.rootdir, "/boot/uboot") } func (u *uboot) ConfigFile() string { diff --git a/bootloader/uboot_test.go b/bootloader/uboot_test.go index a85f487cb6..8276a231ae 100644 --- a/bootloader/uboot_test.go +++ b/bootloader/uboot_test.go @@ -28,7 +28,6 @@ import ( "github.com/snapcore/snapd/bootloader" "github.com/snapcore/snapd/bootloader/ubootenv" - "github.com/snapcore/snapd/dirs" "github.com/snapcore/snapd/osutil" "github.com/snapcore/snapd/snap" "github.com/snapcore/snapd/snap/snaptest" @@ -42,20 +41,20 @@ type ubootTestSuite struct { var _ = Suite(&ubootTestSuite{}) func (s *ubootTestSuite) TestNewUbootNoUbootReturnsNil(c *C) { - u := bootloader.NewUboot() + u := bootloader.NewUboot(s.rootdir) c.Assert(u, IsNil) } func (s *ubootTestSuite) TestNewUboot(c *C) { - bootloader.MockUbootFiles(c) - u := bootloader.NewUboot() + bootloader.MockUbootFiles(c, s.rootdir) + u := bootloader.NewUboot(s.rootdir) c.Assert(u, NotNil) c.Assert(u.Name(), Equals, "uboot") } func (s *ubootTestSuite) TestUbootGetEnvVar(c *C) { - bootloader.MockUbootFiles(c) - u := bootloader.NewUboot() + bootloader.MockUbootFiles(c, s.rootdir) + u := bootloader.NewUboot(s.rootdir) c.Assert(u, NotNil) err := u.SetBootVars(map[string]string{ "snap_mode": "", @@ -72,16 +71,16 @@ func (s *ubootTestSuite) TestUbootGetEnvVar(c *C) { } func (s *ubootTestSuite) TestGetBootloaderWithUboot(c *C) { - bootloader.MockUbootFiles(c) + bootloader.MockUbootFiles(c, s.rootdir) - bootloader, err := bootloader.Find() + bootloader, err := bootloader.Find(s.rootdir, nil) c.Assert(err, IsNil) c.Assert(bootloader.Name(), Equals, "uboot") } func (s *ubootTestSuite) TestUbootSetEnvNoUselessWrites(c *C) { - bootloader.MockUbootFiles(c) - u := bootloader.NewUboot() + bootloader.MockUbootFiles(c, s.rootdir) + u := bootloader.NewUboot(s.rootdir) c.Assert(u, NotNil) envFile := u.ConfigFile() @@ -110,8 +109,8 @@ func (s *ubootTestSuite) TestUbootSetEnvNoUselessWrites(c *C) { } func (s *ubootTestSuite) TestUbootSetBootVarFwEnv(c *C) { - bootloader.MockUbootFiles(c) - u := bootloader.NewUboot() + bootloader.MockUbootFiles(c, s.rootdir) + u := bootloader.NewUboot(s.rootdir) err := u.SetBootVars(map[string]string{"key": "value"}) c.Assert(err, IsNil) @@ -122,8 +121,8 @@ func (s *ubootTestSuite) TestUbootSetBootVarFwEnv(c *C) { } func (s *ubootTestSuite) TestUbootGetBootVarFwEnv(c *C) { - bootloader.MockUbootFiles(c) - u := bootloader.NewUboot() + bootloader.MockUbootFiles(c, s.rootdir) + u := bootloader.NewUboot(s.rootdir) err := u.SetBootVars(map[string]string{"key2": "value2"}) c.Assert(err, IsNil) @@ -134,8 +133,8 @@ func (s *ubootTestSuite) TestUbootGetBootVarFwEnv(c *C) { } func (s *ubootTestSuite) TestExtractKernelAssetsAndRemove(c *C) { - bootloader.MockUbootFiles(c) - u := bootloader.NewUboot() + bootloader.MockUbootFiles(c, s.rootdir) + u := bootloader.NewUboot(s.rootdir) files := [][]string{ {"kernel.img", "I'm a kernel"}, @@ -160,7 +159,7 @@ func (s *ubootTestSuite) TestExtractKernelAssetsAndRemove(c *C) { c.Assert(err, IsNil) // this is where the kernel/initrd is unpacked - kernelAssetsDir := filepath.Join(dirs.GlobalRootDir, "boot", "uboot", "ubuntu-kernel_42.snap") + kernelAssetsDir := filepath.Join(s.rootdir, "boot", "uboot", "ubuntu-kernel_42.snap") for _, def := range files { if def[0] == "meta/kernel.yaml" { diff --git a/cmd/snap-confine/mount-support.c b/cmd/snap-confine/mount-support.c index 5a58323e8e..411fbd4598 100644 --- a/cmd/snap-confine/mount-support.c +++ b/cmd/snap-confine/mount-support.c @@ -406,10 +406,14 @@ static void sc_bootstrap_mount_namespace(const struct sc_mount_config *config) // the this directory on the host filesystem may not match the location in // the desired root filesystem. In the "core" and "ubuntu-core" snaps the // directory is always /snap. On the host it is a build-time configuration - // option stored in SNAP_MOUNT_DIR. - sc_must_snprintf(dst, sizeof dst, "%s/snap", scratch_dir); - sc_do_mount(SNAP_MOUNT_DIR, dst, NULL, MS_BIND | MS_REC, NULL); - sc_do_mount("none", dst, NULL, MS_REC | MS_SLAVE, NULL); + // option stored in SNAP_MOUNT_DIR. In legacy mode (or in other words, not + // in normal mode), we don't need to do this because /snap is fixed and + // already contains the correct view of the mounted snaps. + if (config->normal_mode) { + sc_must_snprintf(dst, sizeof dst, "%s/snap", scratch_dir); + sc_do_mount(SNAP_MOUNT_DIR, dst, NULL, MS_BIND | MS_REC, NULL); + sc_do_mount("none", dst, NULL, MS_REC | MS_SLAVE, NULL); + } // Create the hostfs directory if one is missing. This directory is a part // of packaging now so perhaps this code can be removed later. if (access(SC_HOSTFS_DIR, F_OK) != 0) { diff --git a/cmd/snap-update-ns/change.go b/cmd/snap-update-ns/change.go index 7fd76aa4a2..faddf388be 100644 --- a/cmd/snap-update-ns/change.go +++ b/cmd/snap-update-ns/change.go @@ -330,10 +330,20 @@ func (c *Change) lowLevelPerform(as *Assumptions) error { flags := umountNoFollow if c.Entry.XSnapdDetach() { flags |= syscall.MNT_DETACH + // If we are detaching something then before performing the actual detach + // switch the entire hierarchy to private event propagation (that is, + // none). This works around a bit of peculiar kernel behavior when the + // kernel reports EBUSY during a detach operation, because the changes + // propagate in a way that conflicts with itself. This is also documented + // in umount(2). + err = sysMount("none", c.Entry.Dir, "", syscall.MS_REC|syscall.MS_PRIVATE, "") + logger.Debugf("mount --make-rprivate %q (error: %v)", c.Entry.Dir, err) } // Perform the raw unmount operation. - err = sysUnmount(c.Entry.Dir, flags) + if err == nil { + err = sysUnmount(c.Entry.Dir, flags) + } if err == nil { as.AddChange(c) } diff --git a/cmd/snap-update-ns/change_test.go b/cmd/snap-update-ns/change_test.go index bf97814afe..3c4a0623b0 100644 --- a/cmd/snap-update-ns/change_test.go +++ b/cmd/snap-update-ns/change_test.go @@ -642,6 +642,7 @@ func (s *changeSuite) TestPerformFilesystemMountWithoutMountPointAndReadOnlyBase {C: `lstat "/rofs"`, R: testutil.FileInfoDir}, {C: `mount "tmpfs" "/rofs" "tmpfs" 0 "mode=0755,uid=0,gid=0"`}, + {C: `mount "none" "/tmp/.snap/rofs" "" MS_REC|MS_PRIVATE ""`}, {C: `unmount "/tmp/.snap/rofs" UMOUNT_NOFOLLOW|MNT_DETACH`}, // Perform clean up after the unmount operation. @@ -805,6 +806,7 @@ func (s *changeSuite) TestPerformFilesystemDetch(c *C) { synth, err := chg.Perform(s.as) c.Assert(err, IsNil) c.Assert(s.sys.RCalls(), testutil.SyscallsEqual, []testutil.CallResultError{ + {C: `mount "none" "/target" "" MS_REC|MS_PRIVATE ""`}, {C: `unmount "/target" UMOUNT_NOFOLLOW|MNT_DETACH`}, // Perform clean up after the unmount operation. @@ -1151,6 +1153,7 @@ func (s *changeSuite) TestPerformDirectoryBindMountWithoutMountPointAndReadOnlyB {C: `lstat "/rofs"`, R: testutil.FileInfoDir}, {C: `mount "tmpfs" "/rofs" "tmpfs" 0 "mode=0755,uid=0,gid=0"`}, + {C: `mount "none" "/tmp/.snap/rofs" "" MS_REC|MS_PRIVATE ""`}, {C: `unmount "/tmp/.snap/rofs" UMOUNT_NOFOLLOW|MNT_DETACH`}, // Perform clean up after the unmount operation. @@ -1298,6 +1301,7 @@ func (s *changeSuite) TestPerformDirectoryBindMountWithoutMountSourceAndReadOnly {C: `close 4`}, {C: `lstat "/rofs"`, R: testutil.FileInfoDir}, {C: `mount "tmpfs" "/rofs" "tmpfs" 0 "mode=0755,uid=0,gid=0"`}, + {C: `mount "none" "/tmp/.snap/rofs" "" MS_REC|MS_PRIVATE ""`}, {C: `unmount "/tmp/.snap/rofs" UMOUNT_NOFOLLOW|MNT_DETACH`}, // Perform clean up after the unmount operation. @@ -1690,6 +1694,7 @@ func (s *changeSuite) TestPerformFileBindMountWithoutMountPointAndReadOnlyBase(c {C: `lstat "/rofs"`, R: testutil.FileInfoDir}, {C: `mount "tmpfs" "/rofs" "tmpfs" 0 "mode=0755,uid=0,gid=0"`}, + {C: `mount "none" "/tmp/.snap/rofs" "" MS_REC|MS_PRIVATE ""`}, {C: `unmount "/tmp/.snap/rofs" UMOUNT_NOFOLLOW|MNT_DETACH`}, // Perform clean up after the unmount operation. @@ -2082,6 +2087,7 @@ func (s *changeSuite) TestPerformCreateSymlinkWithoutBaseDirAndReadOnlyBase(c *C {C: `lstat "/rofs"`, R: testutil.FileInfoDir}, {C: `mount "tmpfs" "/rofs" "tmpfs" 0 "mode=0755,uid=0,gid=0"`}, + {C: `mount "none" "/tmp/.snap/rofs" "" MS_REC|MS_PRIVATE ""`}, {C: `unmount "/tmp/.snap/rofs" UMOUNT_NOFOLLOW|MNT_DETACH`}, // Perform clean up after the unmount operation. @@ -2340,6 +2346,7 @@ func (s *changeSuite) TestPerformCreateSymlinkWithAvoidedTrespassing(c *C) { {C: `close 7`}, // We're done restoring now. + {C: `mount "none" "/tmp/.snap/etc" "" MS_REC|MS_PRIVATE ""`}, {C: `unmount "/tmp/.snap/etc" UMOUNT_NOFOLLOW|MNT_DETACH`}, // Perform clean up after the unmount operation. @@ -2424,3 +2431,80 @@ func (s *changeSuite) TestPerformedChangesAreTracked(c *C) { {Action: update.Keep, Entry: osutil.MountEntry{Name: "tmpfs", Dir: "/target", Type: "tmpfs"}}, }) } + +func (s *changeSuite) TestComplexPropagatingChanges(c *C) { + // This problem is more subtle. It is a variant of the regression test + // implemented in tests/regression/lp-1831010. Here, we have four directories: + // + // - $SNAP/a + // - $SNAP/b + // - $SNAP/b/c + // - $SNAP/d + // + // but snapd's mount profile contains only two entries: + // + // 1) recursive-bind $SNAP/a -> $SNAP/b/c (ie, mount --rbind $SNAP/a $SNAP/b/c) + // 2) recursive-bind $SNAP/b -> $SNAP/d (ie, mount --rbind $SNAP/b $SNAP/d) + // + // Both mount operations are performed under a substrate that is MS_SHARED. + // Therefore, due to the rules that decide upon propagation of bind mounts + // the propagation of the new mount entries is also shared. This is + // documented in section 5b of + // https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt. + // + // Interactive experimentation shows that the following three mount points exist + // after this operation, as illustrated by findmnt: + // + // TARGET SOURCE FSTYPE OPTIONS + // ... + // └─/snap/test-snapd-layout/x1 /dev/loop1 squashfs ro,nodev,relatime + // ├─/snap/test-snapd-layout/x1/b/c /dev/loop1[/a] squashfs ro,nodev,relatime + // └─/snap/test-snapd-layout/x1/d /dev/loop1[/b] squashfs ro,nodev,relatime + // └─/snap/test-snapd-layout/x1/d/c /dev/loop1[/a] squashfs ro,nodev,relatime + // + // Note that after the first mount operation only one mount point is created, namely + // $SNAP/a -> $SNAP/b/c. The second recursive bind mount not only creates + // $SNAP/b -> $SNAP/d, but also replicates $SNAP/a -> $SNAP/b/c as + // $SNAP/a -> $SNAP/d/c. + // + // The test will simulate a refresh of the snap from revision x1 to revision + // x2. When this happens the mount profile associated with x1 must be undone + // and the mount profile associated with x2 must be constructed. Because + // ordering matters, let's first consider the order of construction of x1 + // itself. Starting from nothing, apply x1 as follows: + x1 := &osutil.MountProfile{ + Entries: []osutil.MountEntry{ + {Name: "/snap/app/x1/a", Dir: "/snap/app/x1/b/c", Type: "none", Options: []string{"rbind", "rw", "x-snapd.origin=layout"}}, + {Name: "/snap/app/x1/b", Dir: "/snap/app/x1/d", Type: "none", Options: []string{"rbind", "rw", "x-snapd.origin=layout"}}, + }, + } + changes := update.NeededChanges(&osutil.MountProfile{}, x1) + c.Assert(changes, DeepEquals, []*update.Change{ + {Action: update.Mount, Entry: osutil.MountEntry{Name: "/snap/app/x1/a", Dir: "/snap/app/x1/b/c", Type: "none", Options: []string{"rbind", "rw", "x-snapd.origin=layout"}}}, + {Action: update.Mount, Entry: osutil.MountEntry{Name: "/snap/app/x1/b", Dir: "/snap/app/x1/d", Type: "none", Options: []string{"rbind", "rw", "x-snapd.origin=layout"}}}, + }) + // We can see that x1 is constructed in alphabetical order, first recursively + // bind mount at $SNAP/a the directory $SNAP/b/c, second recursively bind + // mount at $SNAP/b the directory $SNAP/d. + x2 := &osutil.MountProfile{ + Entries: []osutil.MountEntry{ + {Name: "/snap/app/x2/a", Dir: "/snap/app/x2/b/c", Type: "none", Options: []string{"rbind", "rw", "x-snapd.origin=layout"}}, + {Name: "/snap/app/x2/b", Dir: "/snap/app/x2/d", Type: "none", Options: []string{"rbind", "rw", "x-snapd.origin=layout"}}, + }, + } + // When we are asked to refresh to revision x2, using the same layout, we + // simply undo x1 and then create x2, which apart from the difference in + // revision name, is exactly the same. The undo code, however, does not take + // the replicated mount point under consideration and therefore attempts to + // detach "x1/d", which normally fails with EBUSY. To counter this, the + // unmount operation first switches the mount point to recursive private + // propagation, before actually unmounting it. This ensures that propagation + // doesn't self-conflict, simply because there isn't any left. + changes = update.NeededChanges(x1, x2) + c.Assert(changes, DeepEquals, []*update.Change{ + {Action: update.Unmount, Entry: osutil.MountEntry{Name: "/snap/app/x1/b", Dir: "/snap/app/x1/d", Type: "none", Options: []string{"rbind", "rw", "x-snapd.origin=layout", "x-snapd.detach"}}}, + {Action: update.Unmount, Entry: osutil.MountEntry{Name: "/snap/app/x1/a", Dir: "/snap/app/x1/b/c", Type: "none", Options: []string{"rbind", "rw", "x-snapd.origin=layout", "x-snapd.detach"}}}, + {Action: update.Mount, Entry: osutil.MountEntry{Name: "/snap/app/x2/a", Dir: "/snap/app/x2/b/c", Type: "none", Options: []string{"rbind", "rw", "x-snapd.origin=layout"}}}, + {Action: update.Mount, Entry: osutil.MountEntry{Name: "/snap/app/x2/b", Dir: "/snap/app/x2/d", Type: "none", Options: []string{"rbind", "rw", "x-snapd.origin=layout"}}}, + }) +} diff --git a/image/image.go b/image/image.go index 2a4e4ccadd..4da7983689 100644 --- a/image/image.go +++ b/image/image.go @@ -32,7 +32,6 @@ import ( "github.com/snapcore/snapd/asserts" "github.com/snapcore/snapd/asserts/snapasserts" "github.com/snapcore/snapd/asserts/sysdb" - "github.com/snapcore/snapd/boot" "github.com/snapcore/snapd/bootloader" "github.com/snapcore/snapd/dirs" "github.com/snapcore/snapd/osutil" @@ -587,8 +586,10 @@ func setupSeed(tsto *ToolingStore, model *asserts.Model, opts *Options, local *l } if !opts.Classic { + // TODO: make this functionality part of the boot package? + // now do the bootloader stuff - if err := bootloader.InstallBootConfig(opts.GadgetUnpackDir); err != nil { + if err := bootloader.InstallBootConfig(opts.GadgetUnpackDir, dirs.GlobalRootDir); err != nil { return err } @@ -606,7 +607,7 @@ func setupSeed(tsto *ToolingStore, model *asserts.Model, opts *Options, local *l } type seedEntry struct { - snap *seed.Snap + snap *seed.Snap16 snapType snap.Type } @@ -737,7 +738,7 @@ func (s *imageSeed) add(snapName string) error { } s.entries = append(s.entries, seedEntry{ - snap: &seed.Snap{ + snap: &seed.Snap16{ Name: info.InstanceName(), SnapID: info.SnapID, // cross-ref Channel: snapChannel, @@ -791,12 +792,12 @@ func (s *imageSeed) checkBase(info *snap.Info) error { return fmt.Errorf("cannot add snap %q without also adding its base %q explicitly", info.InstanceName(), info.Base) } -func (s *imageSeed) seedYaml() *seed.Seed { - var seedYaml seed.Seed +func (s *imageSeed) seedYaml() *seed.Seed16 { + var seedYaml seed.Seed16 sort.Stable(s.entries) - seedYaml.Snaps = make([]*seed.Snap, len(s.entries)) + seedYaml.Snaps = make([]*seed.Snap16, len(s.entries)) for i, e := range s.entries { seedYaml.Snaps[i] = e.snap } @@ -812,7 +813,9 @@ func setBootvars(downloadedSnapsInfoForBootConfig map[string]*snap.Info, model * // Set bootvars for kernel/core snaps so the system boots and // does the first-time initialization. There is also no // mounted kernel/core/base snap, but just the blobs. - bloader, err := bootloader.Find() + bloader, err := bootloader.Find("", &bootloader.Options{ + PrepareImageTime: true, + }) if err != nil { return fmt.Errorf("cannot set kernel/core boot variables: %s", err) } @@ -849,7 +852,7 @@ func setBootvars(downloadedSnapsInfoForBootConfig map[string]*snap.Info, model * bootvar = "snap_core" case snap.TypeKernel: bootvar = "snap_kernel" - if err := extractKernelAssets(fn, info, model); err != nil { + if err := extractKernelAssets(bloader, fn, info, model); err != nil { return err } } @@ -866,15 +869,13 @@ func setBootvars(downloadedSnapsInfoForBootConfig map[string]*snap.Info, model * return nil } -func extractKernelAssets(snapPath string, info *snap.Info, model *asserts.Model) error { +func extractKernelAssets(bootloader bootloader.Bootloader, snapPath string, info *snap.Info, model *asserts.Model) error { snapf, err := snap.Open(snapPath) if err != nil { return err } - // image always runs in not-on-classic mode - kernel := boot.Kernel(info, info.GetType(), model, false) - return kernel.ExtractKernelAssets(snapf) + return bootloader.ExtractKernelAssets(info, snapf) } func copyLocalSnapFile(snapPath, targetDir string, info *snap.Info) (dstPath string, err error) { diff --git a/image/image_test.go b/image/image_test.go index e1136b7515..a421c9dae8 100644 --- a/image/image_test.go +++ b/image/image_test.go @@ -610,7 +610,7 @@ func (s *imageSuite) TestSetupSeed(c *C) { p := filepath.Join(seedsnapsdir, fn) c.Check(osutil.FileExists(p), Equals, true) - c.Check(seedYaml.Snaps[i], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[i], DeepEquals, &seed.Snap16{ Name: name, SnapID: s.AssertedSnapID(name), File: fn, @@ -718,7 +718,7 @@ func (s *imageSuite) TestSetupSeedLocalCoreBrandKernel(c *C) { p := filepath.Join(rootdir, "var/lib/snapd/seed/snaps", fn) c.Check(osutil.FileExists(p), Equals, true) - c.Check(seedYaml.Snaps[i], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[i], DeepEquals, &seed.Snap16{ Name: info.InstanceName(), SnapID: info.SnapID, File: fn, @@ -793,25 +793,25 @@ func (s *imageSuite) TestSetupSeedDevmodeSnap(c *C) { c.Assert(err, IsNil) c.Check(seedYaml.Snaps, HasLen, 5) - c.Check(seedYaml.Snaps[0], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[0], DeepEquals, &seed.Snap16{ Name: "core", SnapID: s.AssertedSnapID("core"), File: "core_3.snap", Channel: "beta", }) - c.Check(seedYaml.Snaps[1], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[1], DeepEquals, &seed.Snap16{ Name: "pc-kernel", SnapID: s.AssertedSnapID("pc-kernel"), File: "pc-kernel_2.snap", Channel: "beta", }) - c.Check(seedYaml.Snaps[2], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[2], DeepEquals, &seed.Snap16{ Name: "pc", SnapID: s.AssertedSnapID("pc"), File: "pc_1.snap", Channel: "beta", }) - c.Check(seedYaml.Snaps[3], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[3], DeepEquals, &seed.Snap16{ Name: "required-snap1", SnapID: s.AssertedSnapID("required-snap1"), File: "required-snap1_3.snap", @@ -819,7 +819,7 @@ func (s *imageSuite) TestSetupSeedDevmodeSnap(c *C) { Channel: "beta", }) // ensure local snaps are put last in seed.yaml - c.Check(seedYaml.Snaps[4], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[4], DeepEquals, &seed.Snap16{ Name: "devmode-snap", DevMode: true, Unasserted: true, @@ -841,7 +841,7 @@ func (s *imageSuite) TestSetupSeedDevmodeSnap(c *C) { // ensure local snaps are put last in seed.yaml last := len(seedYaml.Snaps) - 1 - c.Check(seedYaml.Snaps[last], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[last], DeepEquals, &seed.Snap16{ Name: "devmode-snap", File: fn, DevMode: true, @@ -936,7 +936,7 @@ func (s *imageSuite) TestSetupSeedWithBase(c *C) { p := filepath.Join(rootdir, "var/lib/snapd/seed/snaps", fn) c.Check(osutil.FileExists(p), Equals, true) - c.Check(seedYaml.Snaps[i], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[i], DeepEquals, &seed.Snap16{ Name: info.InstanceName(), SnapID: info.SnapID, File: fn, @@ -1020,7 +1020,7 @@ func (s *imageSuite) TestSetupSeedWithBaseLegacySnap(c *C) { p := filepath.Join(rootdir, "var/lib/snapd/seed/snaps", fn) c.Check(osutil.FileExists(p), Equals, true) - c.Check(seedYaml.Snaps[i], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[i], DeepEquals, &seed.Snap16{ Name: info.InstanceName(), SnapID: info.SnapID, File: fn, @@ -1190,7 +1190,7 @@ func (s *imageSuite) TestSetupSeedLocalSnapsWithStoreAsserts(c *C) { p := filepath.Join(rootdir, "var/lib/snapd/seed/snaps", fn) c.Check(osutil.FileExists(p), Equals, true, Commentf("cannot find %s", p)) - c.Check(seedYaml.Snaps[i], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[i], DeepEquals, &seed.Snap16{ Name: info.InstanceName(), SnapID: info.SnapID, File: fn, @@ -1299,7 +1299,7 @@ func (s *imageSuite) TestSetupSeedLocalSnapsWithChannels(c *C) { p := filepath.Join(rootdir, "var/lib/snapd/seed/snaps", fn) c.Check(osutil.FileExists(p), Equals, true, Commentf("cannot find %s", p)) - c.Check(seedYaml.Snaps[i], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[i], DeepEquals, &seed.Snap16{ Name: info.InstanceName(), SnapID: info.SnapID, Channel: info.Channel, @@ -1454,18 +1454,18 @@ func (s *imageSuite) TestSetupSeedWithKernelAndGadgetTrack(c *C) { c.Assert(err, IsNil) c.Check(seedYaml.Snaps, HasLen, 3) - c.Check(seedYaml.Snaps[0], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[0], DeepEquals, &seed.Snap16{ Name: "core", SnapID: s.AssertedSnapID("core"), File: "core_3.snap", }) - c.Check(seedYaml.Snaps[1], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[1], DeepEquals, &seed.Snap16{ Name: "pc-kernel", SnapID: s.AssertedSnapID("pc-kernel"), File: "pc-kernel_2.snap", Channel: "18/stable", }) - c.Check(seedYaml.Snaps[2], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[2], DeepEquals, &seed.Snap16{ Name: "pc", SnapID: s.AssertedSnapID("pc"), File: "pc_1.snap", @@ -1508,19 +1508,19 @@ func (s *imageSuite) TestSetupSeedWithKernelTrackWithDefaultChannel(c *C) { c.Assert(err, IsNil) c.Check(seedYaml.Snaps, HasLen, 3) - c.Check(seedYaml.Snaps[0], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[0], DeepEquals, &seed.Snap16{ Name: "core", SnapID: s.AssertedSnapID("core"), File: "core_3.snap", Channel: "edge", }) - c.Check(seedYaml.Snaps[1], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[1], DeepEquals, &seed.Snap16{ Name: "pc-kernel", SnapID: s.AssertedSnapID("pc-kernel"), File: "pc-kernel_2.snap", Channel: "18/edge", }) - c.Check(seedYaml.Snaps[2], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[2], DeepEquals, &seed.Snap16{ Name: "pc", SnapID: s.AssertedSnapID("pc"), File: "pc_1.snap", @@ -1568,13 +1568,13 @@ func (s *imageSuite) TestSetupSeedWithKernelTrackOnLocalSnap(c *C) { c.Assert(err, IsNil) c.Check(seedYaml.Snaps, HasLen, 3) - c.Check(seedYaml.Snaps[0], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[0], DeepEquals, &seed.Snap16{ Name: "core", SnapID: s.AssertedSnapID("core"), File: "core_3.snap", Channel: "beta", }) - c.Check(seedYaml.Snaps[1], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[1], DeepEquals, &seed.Snap16{ Name: "pc-kernel", SnapID: s.AssertedSnapID("pc-kernel"), File: "pc-kernel_2.snap", @@ -1622,32 +1622,32 @@ func (s *imageSuite) TestSetupSeedWithBaseAndLocalLegacyCoreOrdering(c *C) { c.Assert(err, IsNil) c.Check(seedYaml.Snaps, HasLen, 6) - c.Check(seedYaml.Snaps[0], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[0], DeepEquals, &seed.Snap16{ Name: "snapd", SnapID: s.AssertedSnapID("snapd"), File: "snapd_18.snap", }) - c.Check(seedYaml.Snaps[1], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[1], DeepEquals, &seed.Snap16{ Name: "core", Unasserted: true, File: "core_x1.snap", }) - c.Check(seedYaml.Snaps[2], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[2], DeepEquals, &seed.Snap16{ Name: "pc-kernel", SnapID: s.AssertedSnapID("pc-kernel"), File: "pc-kernel_2.snap", }) - c.Check(seedYaml.Snaps[3], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[3], DeepEquals, &seed.Snap16{ Name: "core18", SnapID: s.AssertedSnapID("core18"), File: "core18_18.snap", }) - c.Check(seedYaml.Snaps[4], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[4], DeepEquals, &seed.Snap16{ Name: "pc18", SnapID: s.AssertedSnapID("pc18"), File: "pc18_4.snap", }) - c.Check(seedYaml.Snaps[5], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[5], DeepEquals, &seed.Snap16{ Name: "required-snap1", SnapID: s.AssertedSnapID("required-snap1"), File: "required-snap1_3.snap", @@ -1692,32 +1692,32 @@ func (s *imageSuite) TestSetupSeedWithBaseAndLegacyCoreOrdering(c *C) { c.Assert(err, IsNil) c.Check(seedYaml.Snaps, HasLen, 6) - c.Check(seedYaml.Snaps[0], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[0], DeepEquals, &seed.Snap16{ Name: "snapd", SnapID: s.AssertedSnapID("snapd"), File: "snapd_18.snap", }) - c.Check(seedYaml.Snaps[1], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[1], DeepEquals, &seed.Snap16{ Name: "core", SnapID: s.AssertedSnapID("core"), File: "core_3.snap", }) - c.Check(seedYaml.Snaps[2], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[2], DeepEquals, &seed.Snap16{ Name: "pc-kernel", SnapID: s.AssertedSnapID("pc-kernel"), File: "pc-kernel_2.snap", }) - c.Check(seedYaml.Snaps[3], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[3], DeepEquals, &seed.Snap16{ Name: "core18", SnapID: s.AssertedSnapID("core18"), File: "core18_18.snap", }) - c.Check(seedYaml.Snaps[4], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[4], DeepEquals, &seed.Snap16{ Name: "pc18", SnapID: s.AssertedSnapID("pc18"), File: "pc18_4.snap", }) - c.Check(seedYaml.Snaps[5], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[5], DeepEquals, &seed.Snap16{ Name: "required-snap1", SnapID: s.AssertedSnapID("required-snap1"), File: "required-snap1_3.snap", @@ -2020,7 +2020,7 @@ func (s *imageSuite) TestSetupSeedClassic(c *C) { p := filepath.Join(rootdir, "var/lib/snapd/seed/snaps", fn) c.Check(osutil.FileExists(p), Equals, true) - c.Check(seedYaml.Snaps[i], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[i], DeepEquals, &seed.Snap16{ Name: info.InstanceName(), SnapID: info.SnapID, File: fn, @@ -2082,7 +2082,7 @@ func (s *imageSuite) TestSetupSeedClassicWithLocalClassicSnap(c *C) { p := filepath.Join(rootdir, "var/lib/snapd/seed/snaps", "core_3.snap") c.Check(osutil.FileExists(p), Equals, true) - c.Check(seedYaml.Snaps[0], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[0], DeepEquals, &seed.Snap16{ Name: "core", SnapID: s.AssertedSnapID("core"), File: "core_3.snap", @@ -2090,7 +2090,7 @@ func (s *imageSuite) TestSetupSeedClassicWithLocalClassicSnap(c *C) { p = filepath.Join(rootdir, "var/lib/snapd/seed/snaps", "classic-snap_x1.snap") c.Check(osutil.FileExists(p), Equals, true) - c.Check(seedYaml.Snaps[1], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[1], DeepEquals, &seed.Snap16{ Name: "classic-snap", File: "classic-snap_x1.snap", Classic: true, @@ -2152,7 +2152,7 @@ func (s *imageSuite) TestSetupSeedClassicSnapdOnly(c *C) { p := filepath.Join(rootdir, "var/lib/snapd/seed/snaps", fn) c.Check(osutil.FileExists(p), Equals, true) - c.Check(seedYaml.Snaps[i], DeepEquals, &seed.Snap{ + c.Check(seedYaml.Snaps[i], DeepEquals, &seed.Snap16{ Name: info.InstanceName(), SnapID: info.SnapID, File: fn, diff --git a/interfaces/apparmor/spec.go b/interfaces/apparmor/spec.go index d813f9484d..ffbe5bd425 100644 --- a/interfaces/apparmor/spec.go +++ b/interfaces/apparmor/spec.go @@ -156,6 +156,7 @@ func (spec *Specification) AddLayout(si *snap.Info) { bind := si.ExpandSnapVariables(l.Bind) // Allow bind mounting the layout element. fmt.Fprintf(&buf, " mount options=(rbind, rw) %s/ -> %s/,\n", bind, path) + fmt.Fprintf(&buf, " mount options=(rprivate) -> %s/,\n", path) fmt.Fprintf(&buf, " umount %s/,\n", path) // Allow constructing writable mimic in both bind-mount source and mount point. WritableProfile(&buf, path, 2) // At least / and /some-top-level-directory @@ -164,12 +165,14 @@ func (spec *Specification) AddLayout(si *snap.Info) { bindFile := si.ExpandSnapVariables(l.BindFile) // Allow bind mounting the layout element. fmt.Fprintf(&buf, " mount options=(bind, rw) %s -> %s,\n", bindFile, path) + fmt.Fprintf(&buf, " mount options=(rprivate) -> %s,\n", path) fmt.Fprintf(&buf, " umount %s,\n", path) // Allow constructing writable mimic in both bind-mount source and mount point. WritableFileProfile(&buf, path, 2) // At least / and /some-top-level-directory WritableFileProfile(&buf, bindFile, 4) // At least /, /snap/, /snap/$SNAP_NAME and /snap/$SNAP_NAME/$SNAP_REVISION case l.Type == "tmpfs": fmt.Fprintf(&buf, " mount fstype=tmpfs tmpfs -> %s/,\n", path) + fmt.Fprintf(&buf, " mount options=(rprivate) -> %s/,\n", path) fmt.Fprintf(&buf, " umount %s/,\n", path) // Allow constructing writable mimic to mount point. WritableProfile(&buf, path, 2) // At least / and /some-top-level-directory @@ -264,10 +267,14 @@ func WritableMimicProfile(buf *bytes.Buffer, path string, assumedPrefixDepth int fmt.Fprintf(buf, " mount options=(bind, rw) %s* -> %s*,\n", mimicAuxPath, mimicPath) fmt.Fprintf(buf, " # Allow unmounting the auxiliary directory.\n"+ " # TODO: use fstype=tmpfs here for more strictness (LP: #1613403)\n") + fmt.Fprintf(buf, " mount options=(rprivate) -> %s,\n", mimicAuxPath) fmt.Fprintf(buf, " umount %s,\n", mimicAuxPath) fmt.Fprintf(buf, " # Allow unmounting the destination directory as well as anything\n"+ " # inside. This lets us perform the undo plan in case the writable\n"+ " # mimic fails.\n") + fmt.Fprintf(buf, " mount options=(rprivate) -> %s,\n", mimicPath) + fmt.Fprintf(buf, " mount options=(rprivate) -> %s*,\n", mimicPath) + fmt.Fprintf(buf, " mount options=(rprivate) -> %s*/,\n", mimicPath) fmt.Fprintf(buf, " umount %s,\n", mimicPath) fmt.Fprintf(buf, " umount %s*,\n", mimicPath) fmt.Fprintf(buf, " umount %s*/,\n", mimicPath) diff --git a/interfaces/apparmor/spec_test.go b/interfaces/apparmor/spec_test.go index cbba954ae4..aa8727b93a 100644 --- a/interfaces/apparmor/spec_test.go +++ b/interfaces/apparmor/spec_test.go @@ -183,6 +183,7 @@ func (s *specSuite) TestApparmorSnippetsFromLayout(c *C) { profile0 := ` # Layout /etc/foo.conf: bind-file $SNAP/foo.conf mount options=(bind, rw) /snap/vanguard/42/foo.conf -> /etc/foo.conf, + mount options=(rprivate) -> /etc/foo.conf, umount /etc/foo.conf, # Writable mimic /etc # .. permissions for traversing the prefix that is assumed to exist @@ -205,10 +206,14 @@ func (s *specSuite) TestApparmorSnippetsFromLayout(c *C) { mount options=(bind, rw) /tmp/.snap/etc/* -> /etc/*, # Allow unmounting the auxiliary directory. # TODO: use fstype=tmpfs here for more strictness (LP: #1613403) + mount options=(rprivate) -> /tmp/.snap/etc/, umount /tmp/.snap/etc/, # Allow unmounting the destination directory as well as anything # inside. This lets us perform the undo plan in case the writable # mimic fails. + mount options=(rprivate) -> /etc/, + mount options=(rprivate) -> /etc/*, + mount options=(rprivate) -> /etc/*/, umount /etc/, umount /etc/*, umount /etc/*/, @@ -235,10 +240,14 @@ func (s *specSuite) TestApparmorSnippetsFromLayout(c *C) { mount options=(bind, rw) /tmp/.snap/snap/vanguard/42/* -> /snap/vanguard/42/*, # Allow unmounting the auxiliary directory. # TODO: use fstype=tmpfs here for more strictness (LP: #1613403) + mount options=(rprivate) -> /tmp/.snap/snap/vanguard/42/, umount /tmp/.snap/snap/vanguard/42/, # Allow unmounting the destination directory as well as anything # inside. This lets us perform the undo plan in case the writable # mimic fails. + mount options=(rprivate) -> /snap/vanguard/42/, + mount options=(rprivate) -> /snap/vanguard/42/*, + mount options=(rprivate) -> /snap/vanguard/42/*/, umount /snap/vanguard/42/, umount /snap/vanguard/42/*, umount /snap/vanguard/42/*/, @@ -247,6 +256,7 @@ func (s *specSuite) TestApparmorSnippetsFromLayout(c *C) { profile1 := ` # Layout /usr/foo: bind $SNAP/usr/foo mount options=(rbind, rw) /snap/vanguard/42/usr/foo/ -> /usr/foo/, + mount options=(rprivate) -> /usr/foo/, umount /usr/foo/, # Writable mimic /usr # .. permissions for traversing the prefix that is assumed to exist @@ -269,10 +279,14 @@ func (s *specSuite) TestApparmorSnippetsFromLayout(c *C) { mount options=(bind, rw) /tmp/.snap/usr/* -> /usr/*, # Allow unmounting the auxiliary directory. # TODO: use fstype=tmpfs here for more strictness (LP: #1613403) + mount options=(rprivate) -> /tmp/.snap/usr/, umount /tmp/.snap/usr/, # Allow unmounting the destination directory as well as anything # inside. This lets us perform the undo plan in case the writable # mimic fails. + mount options=(rprivate) -> /usr/, + mount options=(rprivate) -> /usr/*, + mount options=(rprivate) -> /usr/*/, umount /usr/, umount /usr/*, umount /usr/*/, @@ -299,10 +313,14 @@ func (s *specSuite) TestApparmorSnippetsFromLayout(c *C) { mount options=(bind, rw) /tmp/.snap/snap/vanguard/42/* -> /snap/vanguard/42/*, # Allow unmounting the auxiliary directory. # TODO: use fstype=tmpfs here for more strictness (LP: #1613403) + mount options=(rprivate) -> /tmp/.snap/snap/vanguard/42/, umount /tmp/.snap/snap/vanguard/42/, # Allow unmounting the destination directory as well as anything # inside. This lets us perform the undo plan in case the writable # mimic fails. + mount options=(rprivate) -> /snap/vanguard/42/, + mount options=(rprivate) -> /snap/vanguard/42/*, + mount options=(rprivate) -> /snap/vanguard/42/*/, umount /snap/vanguard/42/, umount /snap/vanguard/42/*, umount /snap/vanguard/42/*/, @@ -324,10 +342,14 @@ func (s *specSuite) TestApparmorSnippetsFromLayout(c *C) { mount options=(bind, rw) /tmp/.snap/snap/vanguard/42/usr/* -> /snap/vanguard/42/usr/*, # Allow unmounting the auxiliary directory. # TODO: use fstype=tmpfs here for more strictness (LP: #1613403) + mount options=(rprivate) -> /tmp/.snap/snap/vanguard/42/usr/, umount /tmp/.snap/snap/vanguard/42/usr/, # Allow unmounting the destination directory as well as anything # inside. This lets us perform the undo plan in case the writable # mimic fails. + mount options=(rprivate) -> /snap/vanguard/42/usr/, + mount options=(rprivate) -> /snap/vanguard/42/usr/*, + mount options=(rprivate) -> /snap/vanguard/42/usr/*/, umount /snap/vanguard/42/usr/, umount /snap/vanguard/42/usr/*, umount /snap/vanguard/42/usr/*/, @@ -357,10 +379,14 @@ func (s *specSuite) TestApparmorSnippetsFromLayout(c *C) { mount options=(bind, rw) /tmp/.snap/var/* -> /var/*, # Allow unmounting the auxiliary directory. # TODO: use fstype=tmpfs here for more strictness (LP: #1613403) + mount options=(rprivate) -> /tmp/.snap/var/, umount /tmp/.snap/var/, # Allow unmounting the destination directory as well as anything # inside. This lets us perform the undo plan in case the writable # mimic fails. + mount options=(rprivate) -> /var/, + mount options=(rprivate) -> /var/*, + mount options=(rprivate) -> /var/*/, umount /var/, umount /var/*, umount /var/*/, @@ -382,10 +408,14 @@ func (s *specSuite) TestApparmorSnippetsFromLayout(c *C) { mount options=(bind, rw) /tmp/.snap/var/cache/* -> /var/cache/*, # Allow unmounting the auxiliary directory. # TODO: use fstype=tmpfs here for more strictness (LP: #1613403) + mount options=(rprivate) -> /tmp/.snap/var/cache/, umount /tmp/.snap/var/cache/, # Allow unmounting the destination directory as well as anything # inside. This lets us perform the undo plan in case the writable # mimic fails. + mount options=(rprivate) -> /var/cache/, + mount options=(rprivate) -> /var/cache/*, + mount options=(rprivate) -> /var/cache/*/, umount /var/cache/, umount /var/cache/*, umount /var/cache/*/, @@ -394,6 +424,7 @@ func (s *specSuite) TestApparmorSnippetsFromLayout(c *C) { profile3 := ` # Layout /var/tmp: type tmpfs, mode: 01777 mount fstype=tmpfs tmpfs -> /var/tmp/, + mount options=(rprivate) -> /var/tmp/, umount /var/tmp/, # Writable mimic /var # .. permissions for traversing the prefix that is assumed to exist @@ -416,10 +447,14 @@ func (s *specSuite) TestApparmorSnippetsFromLayout(c *C) { mount options=(bind, rw) /tmp/.snap/var/* -> /var/*, # Allow unmounting the auxiliary directory. # TODO: use fstype=tmpfs here for more strictness (LP: #1613403) + mount options=(rprivate) -> /tmp/.snap/var/, umount /tmp/.snap/var/, # Allow unmounting the destination directory as well as anything # inside. This lets us perform the undo plan in case the writable # mimic fails. + mount options=(rprivate) -> /var/, + mount options=(rprivate) -> /var/*, + mount options=(rprivate) -> /var/*/, umount /var/, umount /var/*, umount /var/*/, diff --git a/interfaces/apparmor/template.go b/interfaces/apparmor/template.go index 1d7c261dc5..d0e23f2177 100644 --- a/interfaces/apparmor/template.go +++ b/interfaces/apparmor/template.go @@ -758,6 +758,7 @@ profile snap-update-ns.###SNAP_INSTANCE_NAME### (attach_disconnected) { # Allow the content interface to bind fonts from the host filesystem mount options=(ro bind) /var/lib/snapd/hostfs/usr/share/fonts/ -> /snap/###SNAP_INSTANCE_NAME###/*/**, + mount options=(rw private) -> /snap/###SNAP_INSTANCE_NAME###/*/**, umount /snap/###SNAP_INSTANCE_NAME###/*/**, # set up user mount namespace diff --git a/interfaces/builtin/content.go b/interfaces/builtin/content.go index ad7564d904..286fad5ee6 100644 --- a/interfaces/builtin/content.go +++ b/interfaces/builtin/content.go @@ -229,6 +229,7 @@ func (iface *contentInterface) AppArmorConnectedPlug(spec *apparmor.Specificatio var buf bytes.Buffer fmt.Fprintf(&buf, " # Read-write content sharing %s -> %s (w#%d)\n", plug.Ref(), slot.Ref(), i) fmt.Fprintf(&buf, " mount options=(bind, rw) %s/ -> %s/,\n", source, target) + fmt.Fprintf(&buf, " mount options=(rprivate) -> %s/,\n", target) fmt.Fprintf(&buf, " umount %s/,\n", target) // TODO: The assumed prefix depth could be optimized to be more // precise since content sharing can only take place in a fixed @@ -256,6 +257,7 @@ func (iface *contentInterface) AppArmorConnectedPlug(spec *apparmor.Specificatio fmt.Fprintf(&buf, " # Read-only content sharing %s -> %s (r#%d)\n", plug.Ref(), slot.Ref(), i) fmt.Fprintf(&buf, " mount options=(bind) %s/ -> %s/,\n", source, target) fmt.Fprintf(&buf, " remount options=(bind, ro) %s/,\n", target) + fmt.Fprintf(&buf, " mount options=(rprivate) -> %s/,\n", target) fmt.Fprintf(&buf, " umount %s/,\n", target) // Look at the TODO comment above. apparmor.WritableProfile(&buf, source, 1) diff --git a/interfaces/builtin/content_test.go b/interfaces/builtin/content_test.go index 800a7eafdb..8cefef70c1 100644 --- a/interfaces/builtin/content_test.go +++ b/interfaces/builtin/content_test.go @@ -318,6 +318,7 @@ slots: profile0 := ` # Read-only content sharing consumer:content -> producer:content (r#0) mount options=(bind) /snap/producer/5/export/ -> /snap/consumer/7/import/, remount options=(bind, ro) /snap/consumer/7/import/, + mount options=(rprivate) -> /snap/consumer/7/import/, umount /snap/consumer/7/import/, # Writable mimic /snap/producer/5 # .. permissions for traversing the prefix that is assumed to exist @@ -339,10 +340,14 @@ slots: mount options=(bind, rw) /tmp/.snap/* -> /*, # Allow unmounting the auxiliary directory. # TODO: use fstype=tmpfs here for more strictness (LP: #1613403) + mount options=(rprivate) -> /tmp/.snap/, umount /tmp/.snap/, # Allow unmounting the destination directory as well as anything # inside. This lets us perform the undo plan in case the writable # mimic fails. + mount options=(rprivate) -> /, + mount options=(rprivate) -> /*, + mount options=(rprivate) -> /*/, umount /, umount /*, umount /*/, @@ -364,10 +369,14 @@ slots: mount options=(bind, rw) /tmp/.snap/snap/* -> /snap/*, # Allow unmounting the auxiliary directory. # TODO: use fstype=tmpfs here for more strictness (LP: #1613403) + mount options=(rprivate) -> /tmp/.snap/snap/, umount /tmp/.snap/snap/, # Allow unmounting the destination directory as well as anything # inside. This lets us perform the undo plan in case the writable # mimic fails. + mount options=(rprivate) -> /snap/, + mount options=(rprivate) -> /snap/*, + mount options=(rprivate) -> /snap/*/, umount /snap/, umount /snap/*, umount /snap/*/, @@ -389,10 +398,14 @@ slots: mount options=(bind, rw) /tmp/.snap/snap/producer/* -> /snap/producer/*, # Allow unmounting the auxiliary directory. # TODO: use fstype=tmpfs here for more strictness (LP: #1613403) + mount options=(rprivate) -> /tmp/.snap/snap/producer/, umount /tmp/.snap/snap/producer/, # Allow unmounting the destination directory as well as anything # inside. This lets us perform the undo plan in case the writable # mimic fails. + mount options=(rprivate) -> /snap/producer/, + mount options=(rprivate) -> /snap/producer/*, + mount options=(rprivate) -> /snap/producer/*/, umount /snap/producer/, umount /snap/producer/*, umount /snap/producer/*/, @@ -414,10 +427,14 @@ slots: mount options=(bind, rw) /tmp/.snap/snap/producer/5/* -> /snap/producer/5/*, # Allow unmounting the auxiliary directory. # TODO: use fstype=tmpfs here for more strictness (LP: #1613403) + mount options=(rprivate) -> /tmp/.snap/snap/producer/5/, umount /tmp/.snap/snap/producer/5/, # Allow unmounting the destination directory as well as anything # inside. This lets us perform the undo plan in case the writable # mimic fails. + mount options=(rprivate) -> /snap/producer/5/, + mount options=(rprivate) -> /snap/producer/5/*, + mount options=(rprivate) -> /snap/producer/5/*/, umount /snap/producer/5/, umount /snap/producer/5/*, umount /snap/producer/5/*/, @@ -441,10 +458,14 @@ slots: mount options=(bind, rw) /tmp/.snap/* -> /*, # Allow unmounting the auxiliary directory. # TODO: use fstype=tmpfs here for more strictness (LP: #1613403) + mount options=(rprivate) -> /tmp/.snap/, umount /tmp/.snap/, # Allow unmounting the destination directory as well as anything # inside. This lets us perform the undo plan in case the writable # mimic fails. + mount options=(rprivate) -> /, + mount options=(rprivate) -> /*, + mount options=(rprivate) -> /*/, umount /, umount /*, umount /*/, @@ -466,10 +487,14 @@ slots: mount options=(bind, rw) /tmp/.snap/snap/* -> /snap/*, # Allow unmounting the auxiliary directory. # TODO: use fstype=tmpfs here for more strictness (LP: #1613403) + mount options=(rprivate) -> /tmp/.snap/snap/, umount /tmp/.snap/snap/, # Allow unmounting the destination directory as well as anything # inside. This lets us perform the undo plan in case the writable # mimic fails. + mount options=(rprivate) -> /snap/, + mount options=(rprivate) -> /snap/*, + mount options=(rprivate) -> /snap/*/, umount /snap/, umount /snap/*, umount /snap/*/, @@ -491,10 +516,14 @@ slots: mount options=(bind, rw) /tmp/.snap/snap/consumer/* -> /snap/consumer/*, # Allow unmounting the auxiliary directory. # TODO: use fstype=tmpfs here for more strictness (LP: #1613403) + mount options=(rprivate) -> /tmp/.snap/snap/consumer/, umount /tmp/.snap/snap/consumer/, # Allow unmounting the destination directory as well as anything # inside. This lets us perform the undo plan in case the writable # mimic fails. + mount options=(rprivate) -> /snap/consumer/, + mount options=(rprivate) -> /snap/consumer/*, + mount options=(rprivate) -> /snap/consumer/*/, umount /snap/consumer/, umount /snap/consumer/*, umount /snap/consumer/*/, @@ -516,10 +545,14 @@ slots: mount options=(bind, rw) /tmp/.snap/snap/consumer/7/* -> /snap/consumer/7/*, # Allow unmounting the auxiliary directory. # TODO: use fstype=tmpfs here for more strictness (LP: #1613403) + mount options=(rprivate) -> /tmp/.snap/snap/consumer/7/, umount /tmp/.snap/snap/consumer/7/, # Allow unmounting the destination directory as well as anything # inside. This lets us perform the undo plan in case the writable # mimic fails. + mount options=(rprivate) -> /snap/consumer/7/, + mount options=(rprivate) -> /snap/consumer/7/*, + mount options=(rprivate) -> /snap/consumer/7/*/, umount /snap/consumer/7/, umount /snap/consumer/7/*, umount /snap/consumer/7/*/, @@ -577,6 +610,7 @@ slots: updateNS := apparmorSpec.UpdateNS() profile0 := ` # Read-write content sharing consumer:content -> producer:content (w#0) mount options=(bind, rw) /var/snap/producer/5/export/ -> /var/snap/consumer/7/import/, + mount options=(rprivate) -> /var/snap/consumer/7/import/, umount /var/snap/consumer/7/import/, # Writable directory /var/snap/producer/5/export /var/snap/producer/5/export/ rw, @@ -640,6 +674,7 @@ slots: updateNS := apparmorSpec.UpdateNS() profile0 := ` # Read-write content sharing consumer:content -> producer:content (w#0) mount options=(bind, rw) /var/snap/producer/common/export/ -> /var/snap/consumer/common/import/, + mount options=(rprivate) -> /var/snap/consumer/common/import/, umount /var/snap/consumer/common/import/, # Writable directory /var/snap/producer/common/export /var/snap/producer/common/export/ rw, @@ -738,6 +773,7 @@ slots: updateNS := apparmorSpec.UpdateNS() profile0 := ` # Read-write content sharing consumer:content -> producer:content (w#0) mount options=(bind, rw) /var/snap/producer/common/write-common/ -> /var/snap/consumer/common/import/write-common/, + mount options=(rprivate) -> /var/snap/consumer/common/import/write-common/, umount /var/snap/consumer/common/import/write-common/, # Writable directory /var/snap/producer/common/write-common /var/snap/producer/common/write-common/ rw, @@ -753,6 +789,7 @@ slots: profile1 := ` # Read-write content sharing consumer:content -> producer:content (w#1) mount options=(bind, rw) /var/snap/producer/2/write-data/ -> /var/snap/consumer/common/import/write-data/, + mount options=(rprivate) -> /var/snap/consumer/common/import/write-data/, umount /var/snap/consumer/common/import/write-data/, # Writable directory /var/snap/producer/2/write-data /var/snap/producer/2/write-data/ rw, @@ -769,6 +806,7 @@ slots: profile2 := ` # Read-only content sharing consumer:content -> producer:content (r#0) mount options=(bind) /var/snap/producer/common/read-common/ -> /var/snap/consumer/common/import/read-common/, remount options=(bind, ro) /var/snap/consumer/common/import/read-common/, + mount options=(rprivate) -> /var/snap/consumer/common/import/read-common/, umount /var/snap/consumer/common/import/read-common/, # Writable directory /var/snap/producer/common/read-common /var/snap/producer/common/read-common/ rw, @@ -785,6 +823,7 @@ slots: profile3 := ` # Read-only content sharing consumer:content -> producer:content (r#1) mount options=(bind) /var/snap/producer/2/read-data/ -> /var/snap/consumer/common/import/read-data/, remount options=(bind, ro) /var/snap/consumer/common/import/read-data/, + mount options=(rprivate) -> /var/snap/consumer/common/import/read-data/, umount /var/snap/consumer/common/import/read-data/, # Writable directory /var/snap/producer/2/read-data /var/snap/producer/2/read-data/ rw, @@ -801,6 +840,7 @@ slots: profile4 := ` # Read-only content sharing consumer:content -> producer:content (r#2) mount options=(bind) /snap/producer/2/read-snap/ -> /var/snap/consumer/common/import/read-snap/, remount options=(bind, ro) /var/snap/consumer/common/import/read-snap/, + mount options=(rprivate) -> /var/snap/consumer/common/import/read-snap/, umount /var/snap/consumer/common/import/read-snap/, # Writable mimic /snap/producer/2 # .. permissions for traversing the prefix that is assumed to exist @@ -822,10 +862,14 @@ slots: mount options=(bind, rw) /tmp/.snap/* -> /*, # Allow unmounting the auxiliary directory. # TODO: use fstype=tmpfs here for more strictness (LP: #1613403) + mount options=(rprivate) -> /tmp/.snap/, umount /tmp/.snap/, # Allow unmounting the destination directory as well as anything # inside. This lets us perform the undo plan in case the writable # mimic fails. + mount options=(rprivate) -> /, + mount options=(rprivate) -> /*, + mount options=(rprivate) -> /*/, umount /, umount /*, umount /*/, @@ -847,10 +891,14 @@ slots: mount options=(bind, rw) /tmp/.snap/snap/* -> /snap/*, # Allow unmounting the auxiliary directory. # TODO: use fstype=tmpfs here for more strictness (LP: #1613403) + mount options=(rprivate) -> /tmp/.snap/snap/, umount /tmp/.snap/snap/, # Allow unmounting the destination directory as well as anything # inside. This lets us perform the undo plan in case the writable # mimic fails. + mount options=(rprivate) -> /snap/, + mount options=(rprivate) -> /snap/*, + mount options=(rprivate) -> /snap/*/, umount /snap/, umount /snap/*, umount /snap/*/, @@ -872,10 +920,14 @@ slots: mount options=(bind, rw) /tmp/.snap/snap/producer/* -> /snap/producer/*, # Allow unmounting the auxiliary directory. # TODO: use fstype=tmpfs here for more strictness (LP: #1613403) + mount options=(rprivate) -> /tmp/.snap/snap/producer/, umount /tmp/.snap/snap/producer/, # Allow unmounting the destination directory as well as anything # inside. This lets us perform the undo plan in case the writable # mimic fails. + mount options=(rprivate) -> /snap/producer/, + mount options=(rprivate) -> /snap/producer/*, + mount options=(rprivate) -> /snap/producer/*/, umount /snap/producer/, umount /snap/producer/*, umount /snap/producer/*/, @@ -897,10 +949,14 @@ slots: mount options=(bind, rw) /tmp/.snap/snap/producer/2/* -> /snap/producer/2/*, # Allow unmounting the auxiliary directory. # TODO: use fstype=tmpfs here for more strictness (LP: #1613403) + mount options=(rprivate) -> /tmp/.snap/snap/producer/2/, umount /tmp/.snap/snap/producer/2/, # Allow unmounting the destination directory as well as anything # inside. This lets us perform the undo plan in case the writable # mimic fails. + mount options=(rprivate) -> /snap/producer/2/, + mount options=(rprivate) -> /snap/producer/2/*, + mount options=(rprivate) -> /snap/producer/2/*/, umount /snap/producer/2/, umount /snap/producer/2/*, umount /snap/producer/2/*/, diff --git a/interfaces/builtin/wayland.go b/interfaces/builtin/wayland.go index 219f65434e..151471a2fc 100644 --- a/interfaces/builtin/wayland.go +++ b/interfaces/builtin/wayland.go @@ -59,6 +59,7 @@ owner /run/user/[0-9]*/wayland-[0-9]* rwk, # Allow reading an Xwayland Xauth file # (see https://gitlab.gnome.org/GNOME/mutter/merge_requests/626) /run/user/[0-9]*/.mutter-Xwaylandauth.* r, +/run/user/[0-9]*/mutter/Xauthority r, # Allow write access to create /run/user/* to create XDG_RUNTIME_DIR (until # lp:1738197 is fixed). Note this is not needed if creating a session using diff --git a/interfaces/builtin/x11.go b/interfaces/builtin/x11.go index d038dd5fb5..9d03374e64 100644 --- a/interfaces/builtin/x11.go +++ b/interfaces/builtin/x11.go @@ -129,6 +129,8 @@ owner /run/user/[0-9]*/.Xauthority r, # Allow reading an Xwayland Xauth file # (see https://gitlab.gnome.org/GNOME/mutter/merge_requests/626) owner /run/user/[0-9]*/.mutter-Xwaylandauth.* r, +owner /run/user/[0-9]*/mutter/Xauthority r, + # Needed by QtSystems on X to detect mouse and keyboard. Note, the 'netlink # raw' rule is not finely mediated by apparmor so we mediate with seccomp arg diff --git a/overlord/devicestate/firstboot.go b/overlord/devicestate/firstboot.go index 170a0edd16..08da244228 100644 --- a/overlord/devicestate/firstboot.go +++ b/overlord/devicestate/firstboot.go @@ -1,7 +1,7 @@ // -*- Mode: Go; indent-tabs-mode: t -*- /* - * Copyright (C) 2014-2015 Canonical Ltd + * Copyright (C) 2014-2019 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 @@ -22,14 +22,11 @@ package devicestate import ( "errors" "fmt" - "path/filepath" "sort" "github.com/snapcore/snapd/asserts" - "github.com/snapcore/snapd/asserts/snapasserts" "github.com/snapcore/snapd/dirs" "github.com/snapcore/snapd/i18n" - "github.com/snapcore/snapd/osutil" "github.com/snapcore/snapd/overlord/assertstate" "github.com/snapcore/snapd/overlord/devicestate/internal" "github.com/snapcore/snapd/overlord/snapstate" @@ -37,13 +34,15 @@ import ( "github.com/snapcore/snapd/release" "github.com/snapcore/snapd/seed" "github.com/snapcore/snapd/snap" - "github.com/snapcore/snapd/snap/naming" "github.com/snapcore/snapd/timings" ) var errNothingToDo = errors.New("nothing to do") -func installSeedSnap(st *state.State, sn *seed.Snap, flags snapstate.Flags, tm timings.Measurer) (*state.TaskSet, *snap.Info, error) { +func installSeedSnap(st *state.State, sn *seed.Snap, flags snapstate.Flags) (*state.TaskSet, *snap.Info, error) { + if sn.Required { + flags.Required = true + } if sn.Classic { flags.Classic = true } @@ -51,29 +50,7 @@ func installSeedSnap(st *state.State, sn *seed.Snap, flags snapstate.Flags, tm t flags.DevMode = true } - path := filepath.Join(dirs.SnapSeedDir, "snaps", sn.File) - - var sideInfo snap.SideInfo - if sn.Unasserted { - sideInfo.RealName = sn.Name - } else { - var si *snap.SideInfo - var err error - timings.Run(tm, "derive-side-info", fmt.Sprintf("hash and derive side info for snap %q", sn.Name), func(nested timings.Measurer) { - si, err = snapasserts.DeriveSideInfo(path, assertstate.DB(st)) - }) - if asserts.IsNotFound(err) { - return nil, nil, fmt.Errorf("cannot find signatures with metadata for snap %q (%q)", sn.Name, path) - } - if err != nil { - return nil, nil, err - } - sideInfo = *si - sideInfo.Private = sn.Private - sideInfo.Contact = sn.Contact - } - - return snapstate.InstallPath(st, &sideInfo, path, "", sn.Channel, flags) + return snapstate.InstallPath(st, sn.SideInfo, sn.Path, "", sn.Channel, flags) } func trivialSeeding(st *state.State, markSeeded *state.Task) []*state.TaskSet { @@ -97,10 +74,15 @@ func populateStateFromSeedImpl(st *state.State, tm timings.Measurer) ([]*state.T markSeeded := st.NewTask("mark-seeded", i18n.G("Mark system seeded")) + deviceSeed, err := seed.Open(dirs.SnapSeedDir) + if err != nil { + return nil, err + } + // ack all initial assertions var model *asserts.Model timings.Run(tm, "import-assertions", "import assertions from seed", func(nested timings.Measurer) { - model, err = importAssertionsFromSeed(st) + model, err = importAssertionsFromSeed(st, deviceSeed) }) if err == errNothingToDo { return trivialSeeding(st, markSeeded), nil @@ -109,27 +91,23 @@ func populateStateFromSeedImpl(st *state.State, tm timings.Measurer) ([]*state.T return nil, err } - seedYamlFile := filepath.Join(dirs.SnapSeedDir, "seed.yaml") - if release.OnClassic && !osutil.FileExists(seedYamlFile) { + err = deviceSeed.LoadMeta(tm) + if release.OnClassic && err == seed.ErrNoMeta { // on classic it is ok to not seed any snaps return trivialSeeding(st, markSeeded), nil } - - seedMeta, err := seed.ReadYaml(seedYamlFile) if err != nil { return nil, err } - seedSnaps := seedMeta.Snaps - required := getAllRequiredSnapsForModel(model) - seeding := make(map[string]*seed.Snap, len(seedSnaps)) - for _, sn := range seedSnaps { - seeding[sn.Name] = sn + essentialSeedSnaps := deviceSeed.EssentialSnaps() + seedSnaps, err := deviceSeed.ModeSnaps("run") // XXX mode should be passed in + if err != nil { + return nil, err } - alreadySeeded := make(map[string]bool, 3) // allSnapInfos are collected for cross-check validation of bases - allSnapInfos := make(map[string]*snap.Info, len(seedSnaps)) + allSnapInfos := make(map[string]*snap.Info, len(essentialSeedSnaps)+len(seedSnaps)) tsAll := []*state.TaskSet{} configTss := []*state.TaskSet{} @@ -140,95 +118,40 @@ func populateStateFromSeedImpl(st *state.State, tm timings.Measurer) ([]*state.T } return append(all, ts) } - - baseSnap := "core" - classicWithSnapd := false - if model.Base() != "" { - baseSnap = model.Base() - } - if _, ok := seeding["snapd"]; release.OnClassic && ok { - classicWithSnapd = true - // there is no system-wide base as such - // if there is a gadget we will install its base first though - baseSnap = "" - } - - var installSeedEssential func(snapName string) error - var installGadgetBase func(gadget *snap.Info) error - installSeedEssential = func(snapName string) error { - // be idempotent for installGadgetBase use - if alreadySeeded[snapName] { - return nil - } - seedSnap := seeding[snapName] - if seedSnap == nil { - return fmt.Errorf("cannot proceed without seeding %q", snapName) - } - ts, info, err := installSeedSnap(st, seedSnap, snapstate.Flags{SkipConfigure: true, Required: true}, tm) - if err != nil { - return err - } - if info.GetType() == snap.TypeGadget { - // always make sure the base of gadget is installed first - if err := installGadgetBase(info); err != nil { - return err - } - } - tsAll = chainTs(tsAll, ts) - alreadySeeded[snapName] = true - allSnapInfos[snapName] = info - return nil - } - installGadgetBase = func(gadget *snap.Info) error { - gadgetBase := gadget.Base - if gadgetBase == "" { - gadgetBase = "core" - } - // Sanity check - // TODO: do we want to relax this? the new logic would allow - // but it might just be confusing for now - if baseSnap != "" && gadgetBase != baseSnap { - return fmt.Errorf("cannot use gadget snap because its base %q is different from model base %q", gadgetBase, model.Base()) + chainSorted := func(infos []*snap.Info, infoToTs map[*snap.Info]*state.TaskSet) { + sort.Stable(snap.ByType(infos)) + for _, info := range infos { + ts := infoToTs[info] + tsAll = chainTs(tsAll, ts) } - return installSeedEssential(gadgetBase) } - // if there are snaps to seed, core/base needs to be seeded too - if len(seedSnaps) != 0 { - // ensure "snapd" snap is installed first - if model.Base() != "" || classicWithSnapd { - if err := installSeedEssential("snapd"); err != nil { - return nil, err - } - } - if !classicWithSnapd { - if err := installSeedEssential(baseSnap); err != nil { - return nil, err - } - } + essInfoToTs := make(map[*snap.Info]*state.TaskSet, len(essentialSeedSnaps)) + essInfos := make([]*snap.Info, 0, len(essentialSeedSnaps)) + + if len(essentialSeedSnaps) != 0 { // we *always* configure "core" here even if bases are used // for booting. "core" if where the system config lives. configTss = chainTs(configTss, snapstate.ConfigureSnap(st, "core", snapstate.UseConfigDefaults)) } - if kernelName := model.Kernel(); kernelName != "" { - if err := installSeedEssential(kernelName); err != nil { - return nil, err - } - configTs := snapstate.ConfigureSnap(st, kernelName, snapstate.UseConfigDefaults) - // wait for the previous configTss - configTss = chainTs(configTss, configTs) - } - - if gadgetName := model.Gadget(); gadgetName != "" { - err := installSeedEssential(gadgetName) + for _, seedSnap := range essentialSeedSnaps { + ts, info, err := installSeedSnap(st, seedSnap, snapstate.Flags{SkipConfigure: true}) if err != nil { return nil, err } - configTs := snapstate.ConfigureSnap(st, gadgetName, snapstate.UseConfigDefaults) - // wait for the previous configTss - configTss = chainTs(configTss, configTs) + if info.GetType() == snap.TypeKernel || info.GetType() == snap.TypeGadget { + configTs := snapstate.ConfigureSnap(st, info.SnapName(), snapstate.UseConfigDefaults) + // wait for the previous configTss + configTss = chainTs(configTss, configTs) + } + essInfos = append(essInfos, info) + essInfoToTs[info] = ts + allSnapInfos[info.SnapName()] = info } + // now add/chain the tasksets in the right order based on essential + // snap types + chainSorted(essInfos, essInfoToTs) // chain together configuring core, kernel, and gadget after // installing them so that defaults are availabble from gadget @@ -241,24 +164,15 @@ func populateStateFromSeedImpl(st *state.State, tm timings.Measurer) ([]*state.T infoToTs := make(map[*snap.Info]*state.TaskSet, len(seedSnaps)) infos := make([]*snap.Info, 0, len(seedSnaps)) - for _, sn := range seedSnaps { - if alreadySeeded[sn.Name] { - continue - } - + for _, seedSnap := range seedSnaps { var flags snapstate.Flags - // TODO|XXX: turn SeedSnap into a SnapRef - if required.Contains(naming.Snap(sn.Name)) { - flags.Required = true - } - - ts, info, err := installSeedSnap(st, sn, flags, tm) + ts, info, err := installSeedSnap(st, seedSnap, flags) if err != nil { return nil, err } infos = append(infos, info) infoToTs[info] = ts - allSnapInfos[info.InstanceName()] = info + allSnapInfos[info.SnapName()] = info } // validate that all snaps have bases @@ -270,11 +184,7 @@ func populateStateFromSeedImpl(st *state.State, tm timings.Measurer) ([]*state.T // now add/chain the tasksets in the right order, note that we // only have tasksets that we did not already seeded - sort.Stable(snap.ByType(infos)) - for _, info := range infos { - ts := infoToTs[info] - tsAll = chainTs(tsAll, ts) - } + chainSorted(infos, infoToTs) if len(tsAll) == 0 { return nil, fmt.Errorf("cannot proceed, no snaps to seed") @@ -297,28 +207,20 @@ func populateStateFromSeedImpl(st *state.State, tm timings.Measurer) ([]*state.T return tsAll, nil } -func importAssertionsFromSeed(st *state.State) (*asserts.Model, error) { +func importAssertionsFromSeed(st *state.State, deviceSeed seed.Seed) (*asserts.Model, error) { // TODO: use some kind of context fo Device/SetDevice? device, err := internal.Device(st) if err != nil { return nil, err } - assertSeedDir := filepath.Join(dirs.SnapSeedDir, "assertions") // collect and // set device,model from the model assertion - var modelRef *asserts.Ref - checkForModel := func(ref *asserts.Ref) error { - if ref.Type == asserts.ModelType { - if modelRef != nil && modelRef.Unique() != ref.Unique() { - return fmt.Errorf("cannot add more than one model assertion") - } - modelRef = ref - } - return nil + commitTo := func(batch *asserts.Batch) error { + return assertstate.AddBatch(st, batch, nil) } - batch, err := seed.LoadAssertions(assertSeedDir, checkForModel) + err = deviceSeed.LoadAssertions(assertstate.DB(st), commitTo) if err == seed.ErrNoAssertions && release.OnClassic { // on classic seeding is optional // set the fallback model @@ -332,20 +234,10 @@ func importAssertionsFromSeed(st *state.State) (*asserts.Model, error) { return nil, err } - // verify we have one model assertion - if modelRef == nil { - return nil, fmt.Errorf("need a model assertion") - } - - if err := assertstate.AddBatch(st, batch, nil); err != nil { - return nil, err - } - - a, err := modelRef.Resolve(assertstate.DB(st).Find) + modelAssertion, err := deviceSeed.Model() if err != nil { - return nil, fmt.Errorf("internal error: cannot find just added assertion %v: %v", modelRef, err) + return nil, err } - modelAssertion := a.(*asserts.Model) classicModel := modelAssertion.Classic() if release.OnClassic != classicModel { diff --git a/overlord/devicestate/firstboot_test.go b/overlord/devicestate/firstboot_test.go index 8e877c1d6d..f94027ba75 100644 --- a/overlord/devicestate/firstboot_test.go +++ b/overlord/devicestate/firstboot_test.go @@ -49,6 +49,7 @@ import ( "github.com/snapcore/snapd/overlord/snapstate" "github.com/snapcore/snapd/overlord/state" "github.com/snapcore/snapd/release" + "github.com/snapcore/snapd/seed" "github.com/snapcore/snapd/seed/seedtest" "github.com/snapcore/snapd/snap" "github.com/snapcore/snapd/snap/snaptest" @@ -987,7 +988,10 @@ func (s *FirstBootTestSuite) TestImportAssertionsFromSeedClassicModelMismatch(c st.Lock() defer st.Unlock() - _, err = devicestate.ImportAssertionsFromSeed(st) + deviceSeed, err := seed.Open(dirs.SnapSeedDir) + c.Assert(err, IsNil) + + _, err = devicestate.ImportAssertionsFromSeed(st, deviceSeed) c.Assert(err, ErrorMatches, "cannot seed a classic system with an all-snaps model") } @@ -1004,7 +1008,10 @@ func (s *FirstBootTestSuite) TestImportAssertionsFromSeedAllSnapsModelMismatch(c st.Lock() defer st.Unlock() - _, err = devicestate.ImportAssertionsFromSeed(st) + deviceSeed, err := seed.Open(dirs.SnapSeedDir) + c.Assert(err, IsNil) + + _, err = devicestate.ImportAssertionsFromSeed(st, deviceSeed) c.Assert(err, ErrorMatches, "cannot seed an all-snaps system with a classic model") } @@ -1027,7 +1034,10 @@ func (s *FirstBootTestSuite) TestImportAssertionsFromSeedHappy(c *C) { st.Lock() defer st.Unlock() - model, err := devicestate.ImportAssertionsFromSeed(st) + deviceSeed, err := seed.Open(dirs.SnapSeedDir) + c.Assert(err, IsNil) + + model, err := devicestate.ImportAssertionsFromSeed(st, deviceSeed) c.Assert(err, IsNil) c.Assert(model, NotNil) @@ -1065,9 +1075,12 @@ func (s *FirstBootTestSuite) TestImportAssertionsFromSeedMissingSig(c *C) { } } + deviceSeed, err := seed.Open(dirs.SnapSeedDir) + c.Assert(err, IsNil) + // try import and verify that its rejects because other assertions are // missing - _, err := devicestate.ImportAssertionsFromSeed(st) + _, err = devicestate.ImportAssertionsFromSeed(st, deviceSeed) c.Assert(err, ErrorMatches, "cannot resolve prerequisite assertion: account-key .*") } @@ -1083,10 +1096,13 @@ func (s *FirstBootTestSuite) TestImportAssertionsFromSeedTwoModelAsserts(c *C) { model2 := s.Brands.Model("my-brand", "my-second-model", s.modelHeaders("my-second-model")) s.WriteAssertions("model2", model2) + deviceSeed, err := seed.Open(dirs.SnapSeedDir) + c.Assert(err, IsNil) + // try import and verify that its rejects because other assertions are // missing - _, err := devicestate.ImportAssertionsFromSeed(st) - c.Assert(err, ErrorMatches, "cannot add more than one model assertion") + _, err = devicestate.ImportAssertionsFromSeed(st, deviceSeed) + c.Assert(err, ErrorMatches, "cannot have multiple model assertions in seed") } func (s *FirstBootTestSuite) TestImportAssertionsFromSeedNoModelAsserts(c *C) { @@ -1101,10 +1117,13 @@ func (s *FirstBootTestSuite) TestImportAssertionsFromSeedNoModelAsserts(c *C) { } } + deviceSeed, err := seed.Open(dirs.SnapSeedDir) + c.Assert(err, IsNil) + // try import and verify that its rejects because other assertions are // missing - _, err := devicestate.ImportAssertionsFromSeed(st) - c.Assert(err, ErrorMatches, "need a model assertion") + _, err = devicestate.ImportAssertionsFromSeed(st, deviceSeed) + c.Assert(err, ErrorMatches, "seed must have a model assertion") } type core18SnapsOpts struct { @@ -1209,7 +1228,7 @@ snaps: tsAll, err := devicestate.PopulateStateFromSeedImpl(st, s.perfTimings) c.Assert(err, IsNil) - checkOrder(c, tsAll, "snapd", "core18", "pc-kernel", "pc") + checkOrder(c, tsAll, "snapd", "pc-kernel", "core18", "pc") // now run the change and check the result // use the expected kind otherwise settle with start another one @@ -1331,7 +1350,7 @@ snaps: tsAll, err := devicestate.PopulateStateFromSeedImpl(st, s.perfTimings) c.Assert(err, IsNil) - checkOrder(c, tsAll, "snapd", "core18", "pc-kernel", "pc", "other-base", "snap-req-other-base") + checkOrder(c, tsAll, "snapd", "pc-kernel", "core18", "pc", "other-base", "snap-req-other-base") } func (s *FirstBootTestSuite) TestFirstbootGadgetBaseModelBaseMismatch(c *C) { diff --git a/overlord/snapstate/handlers_link_test.go b/overlord/snapstate/handlers_link_test.go index e9a4143b1e..2037a15f1b 100644 --- a/overlord/snapstate/handlers_link_test.go +++ b/overlord/snapstate/handlers_link_test.go @@ -387,7 +387,7 @@ func (s *linkSnapSuite) TestDoLinkSnapTryToCleanupOnError(c *C) { c.Assert(err, Equals, state.ErrNoState) // tried to cleanup - c.Check(s.fakeBackend.ops, DeepEquals, fakeOps{ + expected := fakeOps{ { op: "candidate", sinfo: *si, @@ -400,7 +400,11 @@ func (s *linkSnapSuite) TestDoLinkSnapTryToCleanupOnError(c *C) { op: "unlink-snap", path: filepath.Join(dirs.SnapMountDir, "foo/35"), }, - }) + } + + // start with an easier-to-read error if this fails: + c.Check(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops()) + c.Check(s.fakeBackend.ops, DeepEquals, expected) } func (s *linkSnapSuite) TestDoLinkSnapSuccessCoreRestarts(c *C) { diff --git a/overlord/snapstate/snapstate_test.go b/overlord/snapstate/snapstate_test.go index d9243193e6..3b4d46c487 100644 --- a/overlord/snapstate/snapstate_test.go +++ b/overlord/snapstate/snapstate_test.go @@ -6725,6 +6725,7 @@ version: 1.0`) }, } + // start with an easier-to-read error if this fails: c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops()) c.Check(s.fakeBackend.ops, DeepEquals, expected) @@ -6788,41 +6789,64 @@ epoch: 1* s.settle(c) s.state.Lock() - ops := s.fakeBackend.ops - // ensure only local install was run, i.e. first action is pseudo-action current - c.Assert(ops.Ops(), HasLen, 11) - c.Check(ops[0].op, Equals, "current") - c.Check(ops[0].old, Equals, filepath.Join(dirs.SnapMountDir, "mock/x2")) - // and setup-snap - c.Check(ops[1].op, Equals, "setup-snap") - c.Check(ops[1].name, Matches, "mock") - c.Check(ops[1].path, Matches, `.*/mock_1.0_all.snap`) - c.Check(ops[1].revno, Equals, snap.R("x3")) - // and cleanup - c.Check(ops[len(ops)-1], DeepEquals, fakeOp{ - op: "cleanup-trash", - name: "mock", - revno: snap.R("x3"), - }) - - c.Check(ops[3].op, Equals, "unlink-snap") - c.Check(ops[3].path, Equals, filepath.Join(dirs.SnapMountDir, "mock/x2")) - - c.Check(ops[4].op, Equals, "copy-data") - c.Check(ops[4].path, Equals, filepath.Join(dirs.SnapMountDir, "mock/x3")) - c.Check(ops[4].old, Equals, filepath.Join(dirs.SnapMountDir, "mock/x2")) - - c.Check(ops[5].op, Equals, "setup-profiles:Doing") - c.Check(ops[5].name, Equals, "mock") - c.Check(ops[5].revno, Equals, snap.R(-3)) + expected := fakeOps{ + { + op: "current", + old: filepath.Join(dirs.SnapMountDir, "mock/x2"), + }, + { + op: "setup-snap", + name: "mock", + path: mockSnap, + revno: snap.R("x3"), + }, + { + op: "remove-snap-aliases", + name: "mock", + }, + { + op: "unlink-snap", + path: filepath.Join(dirs.SnapMountDir, "mock/x2"), + }, + { + op: "copy-data", + path: filepath.Join(dirs.SnapMountDir, "mock/x3"), + old: filepath.Join(dirs.SnapMountDir, "mock/x2"), + }, + { + op: "setup-profiles:Doing", + name: "mock", + revno: snap.R(-3), + }, + { + op: "candidate", + sinfo: snap.SideInfo{ + RealName: "mock", + Revision: snap.R(-3), + }, + }, + { + op: "link-snap", + path: filepath.Join(dirs.SnapMountDir, "mock/x3"), + }, + { + op: "auto-connect:Doing", + name: "mock", + revno: snap.R("x3"), + }, + { + op: "update-aliases", + }, + { + op: "cleanup-trash", + name: "mock", + revno: snap.R("x3"), + }, + } - c.Check(ops[6].op, Equals, "candidate") - c.Check(ops[6].sinfo, DeepEquals, snap.SideInfo{ - RealName: "mock", - Revision: snap.R(-3), - }) - c.Check(ops[7].op, Equals, "link-snap") - c.Check(ops[7].path, Equals, filepath.Join(dirs.SnapMountDir, "mock/x3")) + // start with an easier-to-read error if this fails: + c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops()) + c.Check(s.fakeBackend.ops, DeepEquals, expected) // verify snapSetup info var snapsup snapstate.SnapSetup @@ -6942,6 +6966,7 @@ epoch: 1* revno: snap.R("x1"), }, } + // start with an easier-to-read error if this fails: c.Assert(s.fakeBackend.ops.Ops(), DeepEquals, expected.Ops()) c.Check(s.fakeBackend.ops, DeepEquals, expected) diff --git a/seed/export_test.go b/seed/export_test.go new file mode 100644 index 0000000000..62c5d75fa6 --- /dev/null +++ b/seed/export_test.go @@ -0,0 +1,24 @@ +// -*- Mode: Go; indent-tabs-mode: t -*- + +/* + * Copyright (C) 2019 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 seed + +var ( + LoadAssertions = loadAssertions +) diff --git a/seed/helpers.go b/seed/helpers.go index e76ea67d58..b0f2c8e98e 100644 --- a/seed/helpers.go +++ b/seed/helpers.go @@ -20,20 +20,42 @@ package seed import ( - "errors" "fmt" "io/ioutil" "os" "path/filepath" "github.com/snapcore/snapd/asserts" + "github.com/snapcore/snapd/asserts/sysdb" ) -var ErrNoAssertions = errors.New("no seed assertions") +var trusted = sysdb.Trusted() -func LoadAssertions(assertsDir string, loaded func(*asserts.Ref) error) (*asserts.Batch, error) { - batch := asserts.NewBatch(nil) +func MockTrusted(mockTrusted []asserts.Assertion) (restore func()) { + prevTrusted := trusted + trusted = mockTrusted + return func() { + trusted = prevTrusted + } +} + +func newMemAssertionsDB() (db asserts.RODatabase, commitTo func(*asserts.Batch) error, err error) { + memDB, err := asserts.OpenDatabase(&asserts.DatabaseConfig{ + Backstore: asserts.NewMemoryBackstore(), + Trusted: trusted, + }) + if err != nil { + return nil, nil, err + } + commitTo = func(b *asserts.Batch) error { + return b.CommitTo(memDB, nil) + } + + return memDB, commitTo, nil +} + +func loadAssertions(assertsDir string, loadedFunc func(*asserts.Ref) error) (*asserts.Batch, error) { dc, err := ioutil.ReadDir(assertsDir) if err != nil { if os.IsNotExist(err) { @@ -41,15 +63,17 @@ func LoadAssertions(assertsDir string, loaded func(*asserts.Ref) error) (*assert } return nil, fmt.Errorf("cannot read assertions dir: %s", err) } + + batch := asserts.NewBatch(nil) for _, fi := range dc { fn := filepath.Join(assertsDir, fi.Name()) refs, err := readAsserts(batch, fn) if err != nil { return nil, fmt.Errorf("cannot read assertions: %s", err) } - if loaded != nil { + if loadedFunc != nil { for _, ref := range refs { - if err := loaded(ref); err != nil { + if err := loadedFunc(ref); err != nil { return nil, err } } diff --git a/seed/seed.go b/seed/seed.go new file mode 100644 index 0000000000..e65b2c4ed8 --- /dev/null +++ b/seed/seed.go @@ -0,0 +1,98 @@ +// -*- Mode: Go; indent-tabs-mode: t -*- + +/* + * Copyright (C) 2019 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 seed implements loading and validating of seed data. +package seed + +import ( + "errors" + + "github.com/snapcore/snapd/asserts" + "github.com/snapcore/snapd/snap" + "github.com/snapcore/snapd/timings" +) + +var ( + ErrNoAssertions = errors.New("no seed assertions") + ErrNoMeta = errors.New("no seed metadata") +) + +// Snap holds the details of a snap in a seed. +type Snap struct { + Path string + + SideInfo *snap.SideInfo + + Essential bool + Required bool + + // options + Channel string + DevMode bool + Classic bool +} + +func (s *Snap) SnapName() string { + return s.SideInfo.RealName +} + +func (s *Snap) ID() string { + return s.SideInfo.SnapID +} + +// Seed supports loading assertions and seed snaps' metadata. +type Seed interface { + // LoadAssertions loads all assertions from the seed with + // cross-checks. A read-only view on an assertions database + // can be passed in together with a commitTo function which + // will be used to commit the assertions to the underlying + // database. If db is nil an internal temporary database will + // be setup instead. ErrNoAssertions will be returned if there + // is no assertions directory in the seed, this is legitimate + // only on classic. + LoadAssertions(db asserts.RODatabase, commitTo func(*asserts.Batch) error) error + + // Model returns the seed provided model assertion. It is an + // error to call Model before LoadAssertions. + Model() (*asserts.Model, error) + + // LoadMeta loads the seed and seed's snaps metadata. It can + // return ErrNoMeta if there is no metadata nor snaps in the + // seed, this is legitimate only on classic. It is an error to + // call LoadMeta before LoadAssertions. + LoadMeta(tm timings.Measurer) error + + // UsesSnapdSnap returns whether the system as defined by the + // seed will use the snapd snap, after LoadMeta. + UsesSnapdSnap() bool + + // EssentialSnaps returns the essential snaps as defined by + // the seed, after LoadMeta. + EssentialSnaps() []*Snap + + // ModeSnaps returns the snaps that should be available + // in the given mode as defined by the seed, after LoadMeta. + ModeSnaps(mode string) ([]*Snap, error) +} + +// Open returns a Seed implementation for the seed at seedDir. +// TODO: more parameters for the Core20 case +func Open(seedDir string) (Seed, error) { + return &seed16{seedDir: seedDir}, nil +} diff --git a/seed/seed16.go b/seed/seed16.go new file mode 100644 index 0000000000..a57418043d --- /dev/null +++ b/seed/seed16.go @@ -0,0 +1,294 @@ +// -*- Mode: Go; indent-tabs-mode: t -*- + +/* + * Copyright (C) 2014-2019 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 seed + +/* ATTN this should *not* use: + +* dirs package: it is passed an explicit directory to work on + +* release.OnClassic: it assumes classic based on the model classic + option; consistency between system and model can/must be enforced + elsewhere + +*/ + +import ( + "fmt" + "path/filepath" + + "github.com/snapcore/snapd/asserts" + "github.com/snapcore/snapd/asserts/snapasserts" + "github.com/snapcore/snapd/osutil" + "github.com/snapcore/snapd/snap" + "github.com/snapcore/snapd/snap/naming" + "github.com/snapcore/snapd/timings" +) + +type seed16 struct { + seedDir string + + db asserts.RODatabase + + model *asserts.Model + + snaps []*Snap + essentialSnapsNum int + + usesSnapdSnap bool +} + +func (s *seed16) LoadAssertions(db asserts.RODatabase, commitTo func(*asserts.Batch) error) error { + if db == nil { + // a db was not provided, create an internal temporary one + var err error + db, commitTo, err = newMemAssertionsDB() + if err != nil { + return err + } + } + + assertSeedDir := filepath.Join(s.seedDir, "assertions") + // collect assertions and find model assertion + var modelRef *asserts.Ref + checkForModel := func(ref *asserts.Ref) error { + if ref.Type == asserts.ModelType { + if modelRef != nil && modelRef.Unique() != ref.Unique() { + return fmt.Errorf("cannot have multiple model assertions in seed") + } + modelRef = ref + } + return nil + } + + batch, err := loadAssertions(assertSeedDir, checkForModel) + if err != nil { + return err + } + + // verify we have one model assertion + if modelRef == nil { + return fmt.Errorf("seed must have a model assertion") + } + + if err := commitTo(batch); err != nil { + return err + } + + a, err := modelRef.Resolve(db.Find) + if err != nil { + return fmt.Errorf("internal error: cannot find just added assertion %v: %v", modelRef, err) + } + + // remember db for later use + s.db = db + s.model = a.(*asserts.Model) + + return nil +} + +func (s *seed16) Model() (*asserts.Model, error) { + if s.model == nil { + return nil, fmt.Errorf("internal error: model assertion unset") + } + return s.model, nil +} + +func (s *seed16) addSnap(sn *Snap16, tm timings.Measurer) (*Snap, error) { + path := filepath.Join(s.seedDir, "snaps", sn.File) + seedSnap := &Snap{ + Path: path, + // TODO|XXX: make sure channel is right for pinned tracks + Channel: sn.Channel, + Classic: sn.Classic, + DevMode: sn.DevMode, + } + + var sideInfo snap.SideInfo + if sn.Unasserted { + sideInfo.RealName = sn.Name + } else { + var si *snap.SideInfo + var err error + timings.Run(tm, "derive-side-info", fmt.Sprintf("hash and derive side info for snap %q", sn.Name), func(nested timings.Measurer) { + si, err = snapasserts.DeriveSideInfo(path, s.db) + }) + if asserts.IsNotFound(err) { + return nil, fmt.Errorf("cannot find signatures with metadata for snap %q (%q)", sn.Name, path) + } + if err != nil { + return nil, err + } + sideInfo = *si + sideInfo.Private = sn.Private + sideInfo.Contact = sn.Contact + } + + seedSnap.SideInfo = &sideInfo + + s.snaps = append(s.snaps, seedSnap) + + return seedSnap, nil +} + +func (s *seed16) LoadMeta(tm timings.Measurer) error { + model, err := s.Model() + if err != nil { + return err + } + + seedYamlFile := filepath.Join(s.seedDir, "seed.yaml") + if !osutil.FileExists(seedYamlFile) { + return ErrNoMeta + } + + seedYaml, err := ReadYaml(seedYamlFile) + if err != nil { + return err + } + yamlSnaps := seedYaml.Snaps + + required := naming.NewSnapSet(model.RequiredWithEssentialSnaps()) + seeding := make(map[string]*Snap16, len(yamlSnaps)) + for _, sn := range yamlSnaps { + seeding[sn.Name] = sn + } + added := make(map[string]bool, 3) + classic := model.Classic() + _, s.usesSnapdSnap = seeding["snapd"] + + baseSnap := "core" + classicWithSnapd := false + if model.Base() != "" { + baseSnap = model.Base() + } + if classic && s.usesSnapdSnap { + classicWithSnapd = true + // there is no system-wide base as such + // if there is a gadget we will install its base first though + baseSnap = "" + } + + // add the essential snaps + addEssential := func(snapName string) (*Snap, error) { + // be idempotent + if added[snapName] { + return nil, nil + } + yamlSnap := seeding[snapName] + if yamlSnap == nil { + return nil, fmt.Errorf("essential snap %q required by the model is missing in the seed", snapName) + } + + seedSnap, err := s.addSnap(yamlSnap, tm) + if err != nil { + return nil, err + } + + seedSnap.Essential = true + seedSnap.Required = true + added[snapName] = true + + return seedSnap, nil + } + + // if there are snaps to seed, core/base needs to be seeded too + if len(yamlSnaps) != 0 { + // ensure "snapd" snap is installed first + if model.Base() != "" || classicWithSnapd { + if _, err := addEssential("snapd"); err != nil { + return err + } + } + if !classicWithSnapd { + if _, err := addEssential(baseSnap); err != nil { + return err + } + } + } + + if kernelName := model.Kernel(); kernelName != "" { + if _, err := addEssential(kernelName); err != nil { + return err + } + } + + if gadgetName := model.Gadget(); gadgetName != "" { + gadget, err := addEssential(gadgetName) + if err != nil { + return err + } + + // always make sure the base of gadget is installed first + snapf, err := snap.Open(gadget.Path) + if err != nil { + return err + } + info, err := snap.ReadInfoFromSnapFile(snapf, gadget.SideInfo) + if err != nil { + return err + } + gadgetBase := info.Base + if gadgetBase == "" { + gadgetBase = "core" + } + // Sanity check + // TODO: do we want to relax this? the new logic would allow + // but it might just be confusing for now + if baseSnap != "" && gadgetBase != baseSnap { + return fmt.Errorf("cannot use gadget snap because its base %q is different from model base %q", gadgetBase, model.Base()) + } + if _, err = addEssential(gadgetBase); err != nil { + return err + } + } + + s.essentialSnapsNum = len(s.snaps) + + // the rest of the snaps + for _, sn := range yamlSnaps { + if added[sn.Name] { + continue + } + seedSnap, err := s.addSnap(sn, tm) + if err != nil { + return err + } + if required.Contains(seedSnap) { + seedSnap.Required = true + } + } + + return nil +} + +func (s *seed16) UsesSnapdSnap() bool { + return s.usesSnapdSnap +} + +func (s *seed16) EssentialSnaps() []*Snap { + return s.snaps[:s.essentialSnapsNum] +} + +func (s *seed16) ModeSnaps(mode string) ([]*Snap, error) { + if mode != "run" { + return nil, fmt.Errorf("internal error: Core 16/18 have only run mode, got: %s", mode) + } + return s.snaps[s.essentialSnapsNum:], nil +} diff --git a/seed/seed16_test.go b/seed/seed16_test.go new file mode 100644 index 0000000000..a916e76d57 --- /dev/null +++ b/seed/seed16_test.go @@ -0,0 +1,1058 @@ +// -*- Mode: Go; indent-tabs-mode: t -*- + +/* + * Copyright (C) 2019 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 seed_test + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + + . "gopkg.in/check.v1" + "gopkg.in/yaml.v2" + + "github.com/snapcore/snapd/asserts" + "github.com/snapcore/snapd/asserts/assertstest" + "github.com/snapcore/snapd/seed" + "github.com/snapcore/snapd/seed/seedtest" + "github.com/snapcore/snapd/snap" + "github.com/snapcore/snapd/snap/snaptest" + "github.com/snapcore/snapd/testutil" + "github.com/snapcore/snapd/timings" +) + +type seed16Suite struct { + testutil.BaseTest + + *seedtest.TestingSeed + devAcct *asserts.Account + + seedDir string + + seed16 seed.Seed + + db *asserts.Database + + perfTimings timings.Measurer +} + +var _ = Suite(&seed16Suite{}) + +var ( + brandPrivKey, _ = assertstest.GenerateKey(752) +) + +func (s *seed16Suite) SetUpTest(c *C) { + s.BaseTest.SetUpTest(c) + s.AddCleanup(snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {})) + + s.TestingSeed = &seedtest.TestingSeed{} + s.SetupAssertSigning("canonical", s) + s.Brands.Register("my-brand", brandPrivKey, map[string]interface{}{ + "verification": "verified", + }) + + s.seedDir = c.MkDir() + + s.SnapsDir = filepath.Join(s.seedDir, "snaps") + s.AssertsDir = filepath.Join(s.seedDir, "assertions") + + s.devAcct = assertstest.NewAccount(s.StoreSigning, "developer", map[string]interface{}{ + "account-id": "developerid", + }, "") + assertstest.AddMany(s.StoreSigning, s.devAcct) + + seed16, err := seed.Open(s.seedDir) + c.Assert(err, IsNil) + s.seed16 = seed16 + + db, err := asserts.OpenDatabase(&asserts.DatabaseConfig{ + Backstore: asserts.NewMemoryBackstore(), + Trusted: s.StoreSigning.Trusted, + }) + c.Assert(err, IsNil) + s.db = db + + s.perfTimings = timings.New(nil) +} + +func (s *seed16Suite) commitTo(b *asserts.Batch) error { + return b.CommitTo(s.db, nil) +} + +func (s *seed16Suite) TestLoadAssertionsNoAssertions(c *C) { + c.Check(s.seed16.LoadAssertions(s.db, s.commitTo), Equals, seed.ErrNoAssertions) +} + +func (s *seed16Suite) TestLoadAssertionsNoModelAssertion(c *C) { + err := os.Mkdir(s.AssertsDir, 0755) + c.Assert(err, IsNil) + + c.Check(s.seed16.LoadAssertions(s.db, s.commitTo), ErrorMatches, "seed must have a model assertion") +} + +func (s *seed16Suite) TestLoadAssertionsTwoModelAssertionsError(c *C) { + err := os.Mkdir(s.AssertsDir, 0755) + c.Assert(err, IsNil) + + headers := map[string]interface{}{ + "architecture": "amd64", + "kernel": "pc-kernel", + "gadget": "pc", + } + modelChain := s.MakeModelAssertionChain("my-brand", "my-model", headers) + s.WriteAssertions("model.asserts", modelChain...) + modelChain = s.MakeModelAssertionChain("my-brand", "my-model-2", headers) + s.WriteAssertions("model2.asserts", modelChain...) + + c.Check(s.seed16.LoadAssertions(s.db, s.commitTo), ErrorMatches, "cannot have multiple model assertions in seed") +} + +func (s *seed16Suite) TestLoadAssertionsConsistencyError(c *C) { + err := os.Mkdir(s.AssertsDir, 0755) + c.Assert(err, IsNil) + + // write out only the model assertion + headers := map[string]interface{}{ + "architecture": "amd64", + "kernel": "pc-kernel", + "gadget": "pc", + } + model := s.Brands.Model("my-brand", "my-model", headers) + s.WriteAssertions("model.asserts", model) + + c.Check(s.seed16.LoadAssertions(s.db, s.commitTo), ErrorMatches, "cannot resolve prerequisite assertion: account-key .*") +} + +func (s *seed16Suite) TestLoadAssertionsModelHappy(c *C) { + err := os.Mkdir(s.AssertsDir, 0755) + c.Assert(err, IsNil) + + headers := map[string]interface{}{ + "architecture": "amd64", + "kernel": "pc-kernel", + "gadget": "pc", + } + modelChain := s.MakeModelAssertionChain("my-brand", "my-model", headers) + s.WriteAssertions("model.asserts", modelChain...) + + err = s.seed16.LoadAssertions(s.db, s.commitTo) + c.Assert(err, IsNil) + + model, err := s.seed16.Model() + c.Assert(err, IsNil) + c.Check(model.Model(), Equals, "my-model") + + _, err = s.db.Find(asserts.ModelType, map[string]string{ + "series": "16", + "brand-id": "my-brand", + "model": "my-model", + }) + c.Assert(err, IsNil) +} + +func (s *seed16Suite) TestLoadAssertionsModelTempDBHappy(c *C) { + r := seed.MockTrusted(s.StoreSigning.Trusted) + defer r() + + err := os.Mkdir(s.AssertsDir, 0755) + c.Assert(err, IsNil) + + headers := map[string]interface{}{ + "architecture": "amd64", + "kernel": "pc-kernel", + "gadget": "pc", + } + modelChain := s.MakeModelAssertionChain("my-brand", "my-model", headers) + s.WriteAssertions("model.asserts", modelChain...) + + err = s.seed16.LoadAssertions(nil, nil) + c.Assert(err, IsNil) + + model, err := s.seed16.Model() + c.Assert(err, IsNil) + c.Check(model.Model(), Equals, "my-model") +} + +func (s *seed16Suite) TestSkippedLoadAssertion(c *C) { + _, err := s.seed16.Model() + c.Check(err, ErrorMatches, "internal error: model assertion unset") + + err = s.seed16.LoadMeta(s.perfTimings) + c.Check(err, ErrorMatches, "internal error: model assertion unset") +} + +func (s *seed16Suite) TestLoadMetaNoMeta(c *C) { + err := os.Mkdir(s.AssertsDir, 0755) + c.Assert(err, IsNil) + + headers := map[string]interface{}{ + "architecture": "amd64", + "kernel": "pc-kernel", + "gadget": "pc", + } + modelChain := s.MakeModelAssertionChain("my-brand", "my-model", headers) + s.WriteAssertions("model.asserts", modelChain...) + + err = s.seed16.LoadAssertions(s.db, s.commitTo) + c.Assert(err, IsNil) + + err = s.seed16.LoadMeta(s.perfTimings) + c.Check(err, Equals, seed.ErrNoMeta) +} + +func (s *seed16Suite) TestLoadMetaInvalidSeedYaml(c *C) { + err := os.Mkdir(s.AssertsDir, 0755) + c.Assert(err, IsNil) + + headers := map[string]interface{}{ + "architecture": "amd64", + "kernel": "pc-kernel", + "gadget": "pc", + } + modelChain := s.MakeModelAssertionChain("my-brand", "my-model", headers) + s.WriteAssertions("model.asserts", modelChain...) + + err = s.seed16.LoadAssertions(s.db, s.commitTo) + c.Assert(err, IsNil) + + // create a seed.yaml + content, err := yaml.Marshal(map[string]interface{}{ + "snaps": []*seed.Snap16{{ + Name: "core", + Channel: "track/not-a-risk", + }}, + }) + c.Assert(err, IsNil) + err = ioutil.WriteFile(filepath.Join(s.seedDir, "seed.yaml"), content, 0644) + c.Assert(err, IsNil) + + err = s.seed16.LoadMeta(s.perfTimings) + c.Check(err, ErrorMatches, `cannot read seed yaml: invalid risk in channel name: track/not-a-risk`) +} + +var snapYaml = map[string]string{ + "core": `name: core +type: os +version: 1.0 +`, + "pc-kernel": `name: pc-kernel +type: kernel +version: 1.0 +`, + "pc": `name: pc +type: gadget +version: 1.0 +`, + "required": `name: required +type: app +version: 1.0 +`, + "snapd": `name: snapd +type: snapd +version: 1.0 +`, + "core18": `name: core18 +type: base +version: 1.0 +`, + "pc-kernel=18": `name: pc-kernel +type: kernel +version: 1.0 +`, + "pc=18": `name: pc +type: gadget +base: core18 +version: 1.0 +`, + "required18": `name: required18 +type: app +base: core18 +version: 1.0 +`, + "classic-snap": `name: classic-snap +type: app +confinement: classic +version: 1.0 +`, + "classic-gadget": `name: classic-gadget +type: gadget +version: 1.0 +`, + "classic-gadget18": `name: classic-gadget18 +type: gadget +base: core18 +version: 1.0 +`, + "private-snap": `name: private-snap +base: core18 +version: 1.0 +`, + "contactable-snap": `name: contactable-snap +base: core18 +version: 1.0 +`, +} + +var snapPublishers = map[string]string{ + "required": "developerid", +} + +var ( + coreSeed = &seed.Snap16{ + Name: "core", + Channel: "stable", + } + kernelSeed = &seed.Snap16{ + Name: "pc-kernel", + Channel: "stable", + } + gadgetSeed = &seed.Snap16{ + Name: "pc", + Channel: "stable", + } + requiredSeed = &seed.Snap16{ + Name: "required", + Channel: "stable", + } + // Core 18 + snapdSeed = &seed.Snap16{ + Name: "snapd", + Channel: "stable", + } + core18Seed = &seed.Snap16{ + Name: "core18", + Channel: "stable", + } + kernel18Seed = &seed.Snap16{ + Name: "pc-kernel", + Channel: "18", + } + gadget18Seed = &seed.Snap16{ + Name: "pc", + Channel: "18", + } + required18Seed = &seed.Snap16{ + Name: "required18", + Channel: "stable", + } + classicSnapSeed = &seed.Snap16{ + Name: "classic-snap", + Channel: "stable", + Classic: true, + } + classicGadgetSeed = &seed.Snap16{ + Name: "classic-gadget", + Channel: "stable", + } + classicGadget18Seed = &seed.Snap16{ + Name: "classic-gadget18", + Channel: "stable", + } + privateSnapSeed = &seed.Snap16{ + Name: "private-snap", + Channel: "stable", + Private: true, + } + contactableSnapSeed = &seed.Snap16{ + Name: "contactable-snap", + Channel: "stable", + Contact: "author@example.com", + } +) + +func (s *seed16Suite) makeSeed(c *C, modelHeaders map[string]interface{}, seedSnaps ...*seed.Snap16) []*seed.Snap16 { + coreHeaders := map[string]interface{}{ + "architecture": "amd64", + } + + if _, ok := modelHeaders["classic"]; !ok { + coreHeaders["kernel"] = "pc-kernel" + coreHeaders["gadget"] = "pc" + } + + err := os.Mkdir(s.AssertsDir, 0755) + c.Assert(err, IsNil) + + modelChain := s.MakeModelAssertionChain("my-brand", "my-model", coreHeaders, modelHeaders) + s.WriteAssertions("model.asserts", modelChain...) + + err = os.Mkdir(s.SnapsDir, 0755) + c.Assert(err, IsNil) + + var completeSeedSnaps []*seed.Snap16 + for _, seedSnap := range seedSnaps { + completeSeedSnap := *seedSnap + var snapFname string + if seedSnap.Unasserted { + mockSnapFile := snaptest.MakeTestSnapWithFiles(c, snapYaml[seedSnap.Name], nil) + snapFname = filepath.Base(mockSnapFile) + err := os.Rename(mockSnapFile, filepath.Join(s.seedDir, "snaps", snapFname)) + c.Assert(err, IsNil) + } else { + publisher := snapPublishers[seedSnap.Name] + if publisher == "" { + publisher = "canonical" + } + whichYaml := seedSnap.Name + if seedSnap.Channel != "stable" { + whichYaml = whichYaml + "=" + seedSnap.Channel + } + fname, decl, rev := s.MakeAssertedSnap(c, snapYaml[whichYaml], nil, snap.R(1), publisher) + acct, err := s.StoreSigning.Find(asserts.AccountType, map[string]string{"account-id": publisher}) + c.Assert(err, IsNil) + s.WriteAssertions(fmt.Sprintf("%s.asserts", seedSnap.Name), rev, decl, acct) + snapFname = fname + } + completeSeedSnap.File = snapFname + completeSeedSnaps = append(completeSeedSnaps, &completeSeedSnap) + } + + // create a seed.yaml + content, err := yaml.Marshal(map[string]interface{}{ + "snaps": completeSeedSnaps, + }) + c.Assert(err, IsNil) + err = ioutil.WriteFile(filepath.Join(s.seedDir, "seed.yaml"), content, 0644) + c.Assert(err, IsNil) + + return completeSeedSnaps +} + +func (s *seed16Suite) expectedPath(snapName string) string { + return filepath.Join(s.seedDir, "snaps", filepath.Base(s.AssertedSnap(snapName))) +} + +func (s *seed16Suite) TestLoadMetaCore16Minimal(c *C) { + s.makeSeed(c, nil, coreSeed, kernelSeed, gadgetSeed) + + err := s.seed16.LoadAssertions(s.db, s.commitTo) + c.Assert(err, IsNil) + + err = s.seed16.LoadMeta(s.perfTimings) + c.Assert(err, IsNil) + + c.Check(s.seed16.UsesSnapdSnap(), Equals, false) + + essSnaps := s.seed16.EssentialSnaps() + c.Check(essSnaps, HasLen, 3) + + c.Check(essSnaps, DeepEquals, []*seed.Snap{ + { + Path: s.expectedPath("core"), + SideInfo: &s.AssertedSnapInfo("core").SideInfo, + Essential: true, + Required: true, + Channel: "stable", + }, { + Path: s.expectedPath("pc-kernel"), + SideInfo: &s.AssertedSnapInfo("pc-kernel").SideInfo, + Essential: true, + Required: true, + Channel: "stable", + }, { + Path: s.expectedPath("pc"), + SideInfo: &s.AssertedSnapInfo("pc").SideInfo, + Essential: true, + Required: true, + Channel: "stable", + }, + }) + + runSnaps, err := s.seed16.ModeSnaps("run") + c.Assert(err, IsNil) + c.Check(runSnaps, HasLen, 0) +} + +func (s *seed16Suite) TestLoadMetaCore16(c *C) { + s.makeSeed(c, map[string]interface{}{ + "required-snaps": []interface{}{"required"}, + }, coreSeed, kernelSeed, gadgetSeed, requiredSeed) + + err := s.seed16.LoadAssertions(s.db, s.commitTo) + c.Assert(err, IsNil) + + err = s.seed16.LoadMeta(s.perfTimings) + c.Assert(err, IsNil) + + essSnaps := s.seed16.EssentialSnaps() + c.Check(essSnaps, HasLen, 3) + + runSnaps, err := s.seed16.ModeSnaps("run") + c.Assert(err, IsNil) + c.Check(runSnaps, HasLen, 1) + + c.Check(runSnaps, DeepEquals, []*seed.Snap{ + { + Path: s.expectedPath("required"), + SideInfo: &s.AssertedSnapInfo("required").SideInfo, + Required: true, + Channel: "stable", + }, + }) +} + +func (s *seed16Suite) TestLoadMetaCore18Minimal(c *C) { + s.makeSeed(c, map[string]interface{}{ + "base": "core18", + "kernel": "pc-kernel=18", + "gadget": "pc=18", + }, snapdSeed, core18Seed, kernel18Seed, gadget18Seed) + + err := s.seed16.LoadAssertions(s.db, s.commitTo) + c.Assert(err, IsNil) + + err = s.seed16.LoadMeta(s.perfTimings) + c.Assert(err, IsNil) + + c.Check(s.seed16.UsesSnapdSnap(), Equals, true) + + essSnaps := s.seed16.EssentialSnaps() + c.Check(essSnaps, HasLen, 4) + + c.Check(essSnaps, DeepEquals, []*seed.Snap{ + { + Path: s.expectedPath("snapd"), + SideInfo: &s.AssertedSnapInfo("snapd").SideInfo, + Essential: true, + Required: true, + Channel: "stable", + }, { + Path: s.expectedPath("core18"), + SideInfo: &s.AssertedSnapInfo("core18").SideInfo, + Essential: true, + Required: true, + Channel: "stable", + }, { + Path: s.expectedPath("pc-kernel"), + SideInfo: &s.AssertedSnapInfo("pc-kernel").SideInfo, + Essential: true, + Required: true, + Channel: "18", + }, { + Path: s.expectedPath("pc"), + SideInfo: &s.AssertedSnapInfo("pc").SideInfo, + Essential: true, + Required: true, + Channel: "18", + }, + }) + + runSnaps, err := s.seed16.ModeSnaps("run") + c.Assert(err, IsNil) + c.Check(runSnaps, HasLen, 0) +} + +func (s *seed16Suite) TestLoadMetaCore18(c *C) { + s.makeSeed(c, map[string]interface{}{ + "base": "core18", + "kernel": "pc-kernel=18", + "gadget": "pc=18", + "required-snaps": []interface{}{"core", "required", "required18"}, + }, snapdSeed, core18Seed, kernel18Seed, gadget18Seed, requiredSeed, coreSeed, required18Seed) + + err := s.seed16.LoadAssertions(s.db, s.commitTo) + c.Assert(err, IsNil) + + err = s.seed16.LoadMeta(s.perfTimings) + c.Assert(err, IsNil) + + essSnaps := s.seed16.EssentialSnaps() + c.Check(essSnaps, HasLen, 4) + + c.Check(essSnaps, DeepEquals, []*seed.Snap{ + { + Path: s.expectedPath("snapd"), + SideInfo: &s.AssertedSnapInfo("snapd").SideInfo, + Essential: true, + Required: true, + Channel: "stable", + }, { + Path: s.expectedPath("core18"), + SideInfo: &s.AssertedSnapInfo("core18").SideInfo, + Essential: true, + Required: true, + Channel: "stable", + }, { + Path: s.expectedPath("pc-kernel"), + SideInfo: &s.AssertedSnapInfo("pc-kernel").SideInfo, + Essential: true, + Required: true, + Channel: "18", + }, { + Path: s.expectedPath("pc"), + SideInfo: &s.AssertedSnapInfo("pc").SideInfo, + Essential: true, + Required: true, + Channel: "18", + }, + }) + + runSnaps, err := s.seed16.ModeSnaps("run") + c.Assert(err, IsNil) + c.Check(runSnaps, HasLen, 3) + + // these are not sorted by type, firstboot will do that + c.Check(runSnaps, DeepEquals, []*seed.Snap{ + { + Path: s.expectedPath("required"), + SideInfo: &s.AssertedSnapInfo("required").SideInfo, + Required: true, + Channel: "stable", + }, { + Path: s.expectedPath("core"), + SideInfo: &s.AssertedSnapInfo("core").SideInfo, + Required: true, + Channel: "stable", + }, { + Path: s.expectedPath("required18"), + SideInfo: &s.AssertedSnapInfo("required18").SideInfo, + Required: true, + Channel: "stable", + }, + }) +} + +func (s *seed16Suite) TestLoadMetaClassicNothing(c *C) { + s.makeSeed(c, map[string]interface{}{ + "classic": "true", + }) + + err := s.seed16.LoadAssertions(s.db, s.commitTo) + c.Assert(err, IsNil) + + err = s.seed16.LoadMeta(s.perfTimings) + c.Assert(err, IsNil) + + c.Check(s.seed16.UsesSnapdSnap(), Equals, false) + + essSnaps := s.seed16.EssentialSnaps() + c.Check(essSnaps, HasLen, 0) + + runSnaps, err := s.seed16.ModeSnaps("run") + c.Assert(err, IsNil) + c.Check(runSnaps, HasLen, 0) +} + +func (s *seed16Suite) TestLoadMetaClassicCore(c *C) { + s.makeSeed(c, map[string]interface{}{ + "classic": "true", + }, coreSeed, classicSnapSeed) + + err := s.seed16.LoadAssertions(s.db, s.commitTo) + c.Assert(err, IsNil) + + err = s.seed16.LoadMeta(s.perfTimings) + c.Assert(err, IsNil) + + c.Check(s.seed16.UsesSnapdSnap(), Equals, false) + + essSnaps := s.seed16.EssentialSnaps() + c.Check(essSnaps, HasLen, 1) + c.Check(essSnaps, DeepEquals, []*seed.Snap{ + { + Path: s.expectedPath("core"), + SideInfo: &s.AssertedSnapInfo("core").SideInfo, + Essential: true, + Required: true, + Channel: "stable", + }, + }) + + // classic-snap is not required, just an extra snap + runSnaps, err := s.seed16.ModeSnaps("run") + c.Assert(err, IsNil) + c.Check(runSnaps, HasLen, 1) + c.Check(runSnaps, DeepEquals, []*seed.Snap{ + { + Path: s.expectedPath("classic-snap"), + SideInfo: &s.AssertedSnapInfo("classic-snap").SideInfo, + Channel: "stable", + Classic: true, + }, + }) +} + +func (s *seed16Suite) TestLoadMetaClassicCoreWithGadget(c *C) { + s.makeSeed(c, map[string]interface{}{ + "classic": "true", + "gadget": "classic-gadget", + }, coreSeed, classicGadgetSeed) + + err := s.seed16.LoadAssertions(s.db, s.commitTo) + c.Assert(err, IsNil) + + err = s.seed16.LoadMeta(s.perfTimings) + c.Assert(err, IsNil) + + c.Check(s.seed16.UsesSnapdSnap(), Equals, false) + + essSnaps := s.seed16.EssentialSnaps() + c.Check(essSnaps, HasLen, 2) + c.Check(essSnaps, DeepEquals, []*seed.Snap{ + { + Path: s.expectedPath("core"), + SideInfo: &s.AssertedSnapInfo("core").SideInfo, + Essential: true, + Required: true, + Channel: "stable", + }, + { + Path: s.expectedPath("classic-gadget"), + SideInfo: &s.AssertedSnapInfo("classic-gadget").SideInfo, + Essential: true, + Required: true, + Channel: "stable", + }, + }) + + runSnaps, err := s.seed16.ModeSnaps("run") + c.Assert(err, IsNil) + c.Check(runSnaps, HasLen, 0) +} + +func (s *seed16Suite) TestLoadMetaClassicSnapd(c *C) { + s.makeSeed(c, map[string]interface{}{ + "classic": "true", + "required-snaps": []interface{}{"core18", "required18"}, + }, snapdSeed, core18Seed, required18Seed) + + err := s.seed16.LoadAssertions(s.db, s.commitTo) + c.Assert(err, IsNil) + + err = s.seed16.LoadMeta(s.perfTimings) + c.Assert(err, IsNil) + + c.Check(s.seed16.UsesSnapdSnap(), Equals, true) + + essSnaps := s.seed16.EssentialSnaps() + c.Check(essSnaps, HasLen, 1) + c.Check(essSnaps, DeepEquals, []*seed.Snap{ + { + Path: s.expectedPath("snapd"), + SideInfo: &s.AssertedSnapInfo("snapd").SideInfo, + Essential: true, + Required: true, + Channel: "stable", + }, + }) + + runSnaps, err := s.seed16.ModeSnaps("run") + c.Assert(err, IsNil) + c.Check(runSnaps, HasLen, 2) + c.Check(runSnaps, DeepEquals, []*seed.Snap{ + { + Path: s.expectedPath("core18"), + SideInfo: &s.AssertedSnapInfo("core18").SideInfo, + Required: true, + Channel: "stable", + }, { + Path: s.expectedPath("required18"), + SideInfo: &s.AssertedSnapInfo("required18").SideInfo, + Required: true, + Channel: "stable", + }, + }) +} + +func (s *seed16Suite) TestLoadMetaClassicSnapdWithGadget(c *C) { + s.makeSeed(c, map[string]interface{}{ + "classic": "true", + "gadget": "classic-gadget", + }, snapdSeed, classicGadgetSeed, coreSeed) + + err := s.seed16.LoadAssertions(s.db, s.commitTo) + c.Assert(err, IsNil) + + err = s.seed16.LoadMeta(s.perfTimings) + c.Assert(err, IsNil) + + c.Check(s.seed16.UsesSnapdSnap(), Equals, true) + + essSnaps := s.seed16.EssentialSnaps() + c.Check(essSnaps, HasLen, 3) + c.Check(essSnaps, DeepEquals, []*seed.Snap{ + { + Path: s.expectedPath("snapd"), + SideInfo: &s.AssertedSnapInfo("snapd").SideInfo, + Essential: true, + Required: true, + Channel: "stable", + }, { + Path: s.expectedPath("classic-gadget"), + SideInfo: &s.AssertedSnapInfo("classic-gadget").SideInfo, + Essential: true, + Required: true, + Channel: "stable", + }, { + Path: s.expectedPath("core"), + SideInfo: &s.AssertedSnapInfo("core").SideInfo, + Essential: true, + Required: true, + Channel: "stable", + }, + }) + + runSnaps, err := s.seed16.ModeSnaps("run") + c.Assert(err, IsNil) + c.Check(runSnaps, HasLen, 0) +} + +func (s *seed16Suite) TestLoadMetaClassicSnapdWithGadget18(c *C) { + s.makeSeed(c, map[string]interface{}{ + "classic": "true", + "gadget": "classic-gadget18", + "required-snaps": []interface{}{"core", "required"}, + }, snapdSeed, coreSeed, requiredSeed, classicGadget18Seed, core18Seed) + + err := s.seed16.LoadAssertions(s.db, s.commitTo) + c.Assert(err, IsNil) + + err = s.seed16.LoadMeta(s.perfTimings) + c.Assert(err, IsNil) + + c.Check(s.seed16.UsesSnapdSnap(), Equals, true) + + essSnaps := s.seed16.EssentialSnaps() + c.Check(essSnaps, HasLen, 3) + c.Check(essSnaps, DeepEquals, []*seed.Snap{ + { + Path: s.expectedPath("snapd"), + SideInfo: &s.AssertedSnapInfo("snapd").SideInfo, + Essential: true, + Required: true, + Channel: "stable", + }, { + Path: s.expectedPath("classic-gadget18"), + SideInfo: &s.AssertedSnapInfo("classic-gadget18").SideInfo, + Essential: true, + Required: true, + Channel: "stable", + }, { + Path: s.expectedPath("core18"), + SideInfo: &s.AssertedSnapInfo("core18").SideInfo, + Essential: true, + Required: true, + Channel: "stable", + }, + }) + + runSnaps, err := s.seed16.ModeSnaps("run") + c.Assert(err, IsNil) + c.Check(runSnaps, HasLen, 2) + c.Check(runSnaps, DeepEquals, []*seed.Snap{ + { + Path: s.expectedPath("core"), + SideInfo: &s.AssertedSnapInfo("core").SideInfo, + Required: true, + Channel: "stable", + }, { + Path: s.expectedPath("required"), + SideInfo: &s.AssertedSnapInfo("required").SideInfo, + Required: true, + Channel: "stable", + }, + }) +} + +func (s *seed16Suite) TestLoadMetaCore18Local(c *C) { + localRequired18Seed := &seed.Snap16{ + Name: "required18", + Unasserted: true, + DevMode: true, + } + s.makeSeed(c, map[string]interface{}{ + "base": "core18", + "kernel": "pc-kernel=18", + "gadget": "pc=18", + "required-snaps": []interface{}{"core", "required18"}, + }, snapdSeed, core18Seed, kernel18Seed, gadget18Seed, localRequired18Seed) + + err := s.seed16.LoadAssertions(s.db, s.commitTo) + c.Assert(err, IsNil) + + err = s.seed16.LoadMeta(s.perfTimings) + c.Assert(err, IsNil) + + essSnaps := s.seed16.EssentialSnaps() + c.Check(essSnaps, HasLen, 4) + + c.Check(essSnaps, DeepEquals, []*seed.Snap{ + { + Path: s.expectedPath("snapd"), + SideInfo: &s.AssertedSnapInfo("snapd").SideInfo, + Essential: true, + Required: true, + Channel: "stable", + }, { + Path: s.expectedPath("core18"), + SideInfo: &s.AssertedSnapInfo("core18").SideInfo, + Essential: true, + Required: true, + Channel: "stable", + }, { + Path: s.expectedPath("pc-kernel"), + SideInfo: &s.AssertedSnapInfo("pc-kernel").SideInfo, + Essential: true, + Required: true, + Channel: "18", + }, { + Path: s.expectedPath("pc"), + SideInfo: &s.AssertedSnapInfo("pc").SideInfo, + Essential: true, + Required: true, + Channel: "18", + }, + }) + + runSnaps, err := s.seed16.ModeSnaps("run") + c.Assert(err, IsNil) + c.Check(runSnaps, HasLen, 1) + + c.Check(runSnaps, DeepEquals, []*seed.Snap{ + { + Path: filepath.Join(s.seedDir, "snaps", "required18_1.0_all.snap"), + SideInfo: &snap.SideInfo{RealName: "required18"}, + Required: true, + DevMode: true, + }, + }) +} + +func (s *seed16Suite) TestLoadMetaCore18StoreInfo(c *C) { + s.makeSeed(c, map[string]interface{}{ + "base": "core18", + "kernel": "pc-kernel=18", + "gadget": "pc=18", + }, snapdSeed, core18Seed, kernel18Seed, gadget18Seed, privateSnapSeed, contactableSnapSeed) + + err := s.seed16.LoadAssertions(s.db, s.commitTo) + c.Assert(err, IsNil) + + err = s.seed16.LoadMeta(s.perfTimings) + c.Assert(err, IsNil) + + essSnaps := s.seed16.EssentialSnaps() + c.Check(essSnaps, HasLen, 4) + + runSnaps, err := s.seed16.ModeSnaps("run") + c.Assert(err, IsNil) + c.Check(runSnaps, HasLen, 2) + + privateSnapSideInfo := s.AssertedSnapInfo("private-snap").SideInfo + privateSnapSideInfo.Private = true + contactableSnapSideInfo := s.AssertedSnapInfo("contactable-snap").SideInfo + contactableSnapSideInfo.Contact = "author@example.com" + + // these are not sorted by type, firstboot will do that + c.Check(runSnaps, DeepEquals, []*seed.Snap{ + { + Path: s.expectedPath("private-snap"), + SideInfo: &privateSnapSideInfo, + Channel: "stable", + }, { + Path: s.expectedPath("contactable-snap"), + SideInfo: &contactableSnapSideInfo, + Channel: "stable", + }, + }) +} + +func (s *seed16Suite) TestLoadMetaBrokenSeed(c *C) { + seedSnap16s := s.makeSeed(c, map[string]interface{}{ + "base": "core18", + "kernel": "pc-kernel=18", + "gadget": "pc=18", + "required-snaps": []interface{}{"required18"}, + }, snapdSeed, core18Seed, kernel18Seed, gadget18Seed, required18Seed) + + otherSnapFile := snaptest.MakeTestSnapWithFiles(c, `name: other +version: other`, nil) + otherFname := filepath.Base(otherSnapFile) + err := os.Rename(otherSnapFile, filepath.Join(s.seedDir, "snaps", otherFname)) + c.Assert(err, IsNil) + + const otherBaseGadget = `name: pc +type: gadget +base: other-base +version: other-base +` + otherBaseGadgetFname, obgDecl, obgRev := s.MakeAssertedSnap(c, otherBaseGadget, nil, snap.R(3), "canonical") + s.WriteAssertions("other-gadget.asserts", obgDecl, obgRev) + + err = s.seed16.LoadAssertions(s.db, s.commitTo) + c.Assert(err, IsNil) + + omit := func(which int) func([]*seed.Snap16) []*seed.Snap16 { + return func(snaps []*seed.Snap16) []*seed.Snap16 { + broken := make([]*seed.Snap16, 0, len(snaps)-1) + for i, sn := range snaps { + if i == which { + continue + } + broken = append(broken, sn) + } + return broken + } + } + replaceFile := func(snapName, fname string) func([]*seed.Snap16) []*seed.Snap16 { + return func(snaps []*seed.Snap16) []*seed.Snap16 { + for i := range snaps { + if snaps[i].Name != snapName { + continue + } + sn := *snaps[i] + sn.File = fname + snaps[i] = &sn + } + return snaps + } + } + + tests := []struct { + breakSeed func([]*seed.Snap16) []*seed.Snap16 + err string + }{ + {omit(0), `essential snap "snapd" required by the model is missing in the seed`}, + {omit(1), `essential snap "core18" required by the model is missing in the seed`}, + {omit(2), `essential snap "pc-kernel" required by the model is missing in the seed`}, + {omit(3), `essential snap "pc" required by the model is missing in the seed`}, + // omitting "required18" currently doesn't error in any way + {replaceFile("core18", otherFname), `cannot find signatures with metadata for snap "core18".*`}, + {replaceFile("required18", otherFname), `cannot find signatures with metadata for snap "required18".*`}, + {replaceFile("core18", "not-existent"), `cannot compute snap .* digest: .*`}, + {replaceFile("pc", otherBaseGadgetFname), `cannot use gadget snap because its base "other-base" is different from model base "core18"`}, + } + + for _, t := range tests { + testSeedSnap16s := make([]*seed.Snap16, 5) + copy(testSeedSnap16s, seedSnap16s) + + testSeedSnap16s = t.breakSeed(testSeedSnap16s) + content, err := yaml.Marshal(map[string]interface{}{ + "snaps": testSeedSnap16s, + }) + c.Assert(err, IsNil) + err = ioutil.WriteFile(filepath.Join(s.seedDir, "seed.yaml"), content, 0644) + c.Assert(err, IsNil) + + c.Check(s.seed16.LoadMeta(s.perfTimings), ErrorMatches, t.err) + } +} diff --git a/seed/seed_yaml.go b/seed/seed_yaml.go index 166b00a848..db24e393f4 100644 --- a/seed/seed_yaml.go +++ b/seed/seed_yaml.go @@ -34,7 +34,8 @@ import ( // Snap points to a snap in the seed to install, together with // assertions (or alone if unasserted is true) it will be used to // drive the installation and ultimately set SideInfo/SnapState for it. -type Snap struct { +// TODO: make this internal +type Snap16 struct { Name string `yaml:"name"` // cross-reference/audit @@ -55,11 +56,13 @@ type Snap struct { File string `yaml:"file"` } -type Seed struct { - Snaps []*Snap `yaml:"snaps"` +// TODO: make all of this internal only + +type Seed16 struct { + Snaps []*Snap16 `yaml:"snaps"` } -func ReadYaml(fn string) (*Seed, error) { +func ReadYaml(fn string) (*Seed16, error) { errPrefix := "cannot read seed yaml" yamlData, err := ioutil.ReadFile(fn) @@ -67,7 +70,7 @@ func ReadYaml(fn string) (*Seed, error) { return nil, fmt.Errorf("%s: %v", errPrefix, err) } - var seed Seed + var seed Seed16 if err := yaml.Unmarshal(yamlData, &seed); err != nil { return nil, fmt.Errorf("%s: cannot unmarshal %q: %s", errPrefix, yamlData, err) } @@ -105,7 +108,7 @@ func ReadYaml(fn string) (*Seed, error) { return &seed, nil } -func (seed *Seed) Write(seedFn string) error { +func (seed *Seed16) Write(seedFn string) error { data, err := yaml.Marshal(&seed) if err != nil { return err diff --git a/seed/seed_yaml_test.go b/seed/seed_yaml_test.go index 0ff68547be..ee9ec65eda 100644 --- a/seed/seed_yaml_test.go +++ b/seed/seed_yaml_test.go @@ -55,7 +55,7 @@ func (s *seedYamlTestSuite) TestSimple(c *C) { seedYaml, err := seed.ReadYaml(fn) c.Assert(err, IsNil) c.Assert(seedYaml.Snaps, HasLen, 2) - c.Assert(seedYaml.Snaps[0], DeepEquals, &seed.Snap{ + c.Assert(seedYaml.Snaps[0], DeepEquals, &seed.Snap16{ File: "foo_1.0_all.snap", Name: "foo", SnapID: "snapidsnapidsnapid", @@ -63,7 +63,7 @@ func (s *seedYamlTestSuite) TestSimple(c *C) { Channel: "stable", DevMode: true, }) - c.Assert(seedYaml.Snaps[1], DeepEquals, &seed.Snap{ + c.Assert(seedYaml.Snaps[1], DeepEquals, &seed.Snap16{ File: "local.snap", Name: "local", Unasserted: true, diff --git a/seed/seedtest/seedtest.go b/seed/seedtest/seedtest.go index a2ea4e9300..4cc4b2db74 100644 --- a/seed/seedtest/seedtest.go +++ b/seed/seedtest/seedtest.go @@ -112,6 +112,7 @@ func (ss *SeedSnaps) MakeAssertedSnap(c *C, snapYaml string, files [][]string, r } ss.snaps[snapName] = snapFile + info.SideInfo.RealName = snapName ss.infos[snapName] = info return declA.(*asserts.SnapDeclaration), revA.(*asserts.SnapRevision) diff --git a/tests/lib/bin/mountinfo-tool b/tests/lib/bin/mountinfo-tool index ec51733572..53a7297846 100755 --- a/tests/lib/bin/mountinfo-tool +++ b/tests/lib/bin/mountinfo-tool @@ -94,6 +94,9 @@ class MountInfoEntry(object): self.fs_type = "" self.mount_source = "" self.sb_opts = "" + # This field does not represent kernel state. + # It is a marker for an entry being matched by a filter. + self.matched = False def __eq__(self, other): # type: (object) -> Union[NotImplemented, bool] @@ -687,6 +690,13 @@ The exit code indicates if any mount point matched the query. raise SystemExit(exc) entries = [MountInfoEntry.parse(line) for line in opts.file] + # Apply entry filtering ahead of any renumbering. + num_matched = 0 + for e in entries: + if matches(e, filters): + e.matched = True + num_matched += 1 + # Build rewrite state based on reference tables. This way the entries # we will display can be correlated to other tables. rs = RewriteState() @@ -725,9 +735,6 @@ The exit code indicates if any mount point matched the query. if opts.rename: rewrite_rename(entries, rewrite_order, rs) - # Apply entry filtering. - entries = [e for e in entries if matches(e, filters)] - # Apply entry reordering for display. if opts.display_order: @@ -737,6 +744,8 @@ The exit code indicates if any mount point matched the query. entries.sort(key=display_key_fn) for e in entries: + if not e.matched: + continue if attrs: values = [] # type: List[Any] for attr in attrs: @@ -747,15 +756,16 @@ The exit code indicates if any mount point matched the query. print(*values) else: print(e) - if opts.one and len(entries) != 1: + if opts.one and num_matched != 1: raise SystemExit( - "--one requires exactly one match, found {}".format(len(entries)) + "--one requires exactly one match, found {}".format(num_matched) ) - # Return with an exit code indicating if anything matched. - # This allows mountinfo-tool to be used in scripts. - if len(entries) == 0: + # Return with an exit code indicating if anything matched. + # This allows mountinfo-tool to be used in scripts. + if num_matched == 0: raise SystemExit(1) + class MountInfoEntryTests(unittest.TestCase): non_zero_values = { diff --git a/tests/lib/boot.sh b/tests/lib/boot.sh index 475ceccdf8..282f1b26f3 100644 --- a/tests/lib/boot.sh +++ b/tests/lib/boot.sh @@ -1,6 +1,7 @@ #!/bin/bash GRUB_EDITENV=grub-editenv +GRUBENV_FILE=/boot/grub/grubenv case "$SPREAD_SYSTEM" in fedora-*|opensuse-*|amazon-*|centos-*) GRUB_EDITENV=grub2-editenv @@ -11,12 +12,16 @@ bootenv() { if [ $# -eq 0 ]; then if command -v "$GRUB_EDITENV" >/dev/null; then "$GRUB_EDITENV" list + elif [ -s "$GRUBENV_FILE" ]; then + cat "$GRUBENV_FILE" else fw_printenv fi else if command -v "$GRUB_EDITENV" >/dev/null; then "$GRUB_EDITENV" list | grep "^$1" + elif [ -s "$GRUBENV_FILE" ]; then + grep "^$1" "$GRUBENV_FILE" else fw_printenv "$1" fi | sed "s/^${1}=//" @@ -29,6 +34,8 @@ bootenv_unset() { if command -v "$GRUB_EDITENV" >/dev/null; then "$GRUB_EDITENV" /boot/grub/grubenv unset "$var" + elif [ -s "$GRUBENV_FILE" ]; then + sed -i "/^$var=/d" "$GRUBENV_FILE" else fw_setenv "$var" fi diff --git a/tests/main/mount-ns/google.ubuntu-core-16-64/PER-SNAP-16.expected.txt b/tests/main/mount-ns/google.ubuntu-core-16-64/PER-SNAP-16.expected.txt index 6a6e2da177..246d87e3a6 100644 --- a/tests/main/mount-ns/google.ubuntu-core-16-64/PER-SNAP-16.expected.txt +++ b/tests/main/mount-ns/google.ubuntu-core-16-64/PER-SNAP-16.expected.txt @@ -69,160 +69,152 @@ 1069 1065 2:10 /snapd/ns /run/snapd/ns rw,nosuid,noexec,relatime - tmpfs tmpfs rw,size=VARIABLE,mode=755 1070 1065 2:13 / /run/user/0 rw,nosuid,nodev,relatime master:59 - tmpfs tmpfs rw,size=VARIABLE,mode=700 1071 1001 1:1 /system-data/snap /snap rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1072 1071 1:1 /system-data/snap /snap rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1073 1071 0:2 / /snap/core/1 ro,nodev,relatime master:60 - squashfs /dev/loop2 ro -1074 1072 0:2 / /snap/core/1 ro,nodev,relatime master:60 - squashfs /dev/loop2 ro -1075 1071 0:3 / /snap/core18/1 ro,nodev,relatime master:61 - squashfs /dev/loop3 ro -1076 1072 0:3 / /snap/core18/1 ro,nodev,relatime master:61 - squashfs /dev/loop3 ro -1077 1071 0:4 / /snap/pc-kernel/1 ro,nodev,relatime master:62 - squashfs /dev/loop4 ro -1078 1072 0:4 / /snap/pc-kernel/1 ro,nodev,relatime master:62 - squashfs /dev/loop4 ro -1079 1071 0:5 / /snap/pc/1 ro,nodev,relatime master:63 - squashfs /dev/loop5 ro -1080 1072 0:5 / /snap/pc/1 ro,nodev,relatime master:63 - squashfs /dev/loop5 ro -1081 1071 0:6 / /snap/test-snapd-mountinfo-core16/1 ro,nodev,relatime master:64 - squashfs /dev/loop6 ro -1082 1072 0:6 / /snap/test-snapd-mountinfo-core16/1 ro,nodev,relatime master:64 - squashfs /dev/loop6 ro -1083 1071 0:7 / /snap/test-snapd-mountinfo-core18/1 ro,nodev,relatime master:65 - squashfs /dev/loop7 ro -1084 1072 0:7 / /snap/test-snapd-mountinfo-core18/1 ro,nodev,relatime master:65 - squashfs /dev/loop7 ro -1085 1071 0:8 / /snap/test-snapd-rsync/1 ro,nodev,relatime master:66 - squashfs /dev/loop8 ro -1086 1072 0:8 / /snap/test-snapd-rsync/1 ro,nodev,relatime master:66 - squashfs /dev/loop8 ro -1087 1001 2:14 / /sys rw,nosuid,nodev,noexec,relatime master:67 - sysfs sysfs rw -1088 1087 2:15 / /sys/fs/cgroup rw master:68 - tmpfs tmpfs rw,mode=755 -1089 1088 2:16 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime master:69 - cgroup cgroup rw,blkio -1090 1088 2:17 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime master:70 - cgroup cgroup rw,cpu,cpuacct -1091 1088 2:18 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime master:71 - cgroup cgroup rw,cpuset,clone_children -1092 1088 2:19 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime master:72 - cgroup cgroup rw,devices -1093 1088 2:20 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime master:73 - cgroup cgroup rw,freezer -1094 1088 2:21 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime master:74 - cgroup cgroup rw,hugetlb,release_agent=/run/cgmanager/agents/cgm-release-agent.hugetlb -1095 1088 2:22 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime master:75 - cgroup cgroup rw,memory -1096 1088 2:23 / /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime master:76 - cgroup cgroup rw,net_cls,net_prio -1097 1088 2:24 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime master:77 - cgroup cgroup rw,perf_event,release_agent=/run/cgmanager/agents/cgm-release-agent.perf_event -1098 1088 2:25 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime master:78 - cgroup cgroup rw,pids,release_agent=/run/cgmanager/agents/cgm-release-agent.pids -1099 1088 2:26 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime master:79 - cgroup cgroup rw,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd -1100 1087 2:27 / /sys/fs/fuse/connections rw,relatime master:80 - fusectl fusectl rw -1101 1087 2:28 / /sys/fs/pstore rw,nosuid,nodev,noexec,relatime master:81 - pstore pstore rw -1102 1087 2:29 / /sys/kernel/debug rw,relatime master:82 - debugfs debugfs rw -1103 1087 2:30 / /sys/kernel/security rw,nosuid,nodev,noexec,relatime master:83 - securityfs securityfs rw -1104 1001 2:31 / /tmp rw,relatime master:84 - tmpfs tmpfs rw -1105 1104 2:31 /snap.test-snapd-mountinfo-core16/tmp /tmp rw,relatime - tmpfs tmpfs rw -1106 1001 1:1 /system-data/var/cache/apparmor /var/cache/apparmor rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1107 1001 1:1 /system-data/var/cache/snapd /var/cache/snapd rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1108 1001 1:1 /system-data/var/lib/apparmor /var/lib/apparmor rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1109 1001 1:1 /system-data/var/lib/cloud /var/lib/cloud rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1110 1001 1:1 /system-data/var/lib/console-conf /var/lib/console-conf rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1111 1001 1:1 /system-data/var/lib/dbus /var/lib/dbus rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1112 1001 1:1 /system-data/var/lib/dhcp /var/lib/dhcp rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1113 1001 1:1 /system-data/var/lib/extrausers /var/lib/extrausers rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1114 1001 1:1 /system-data/var/lib/initramfs-tools /var/lib/initramfs-tools rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1115 1001 1:1 /system-data/var/lib/logrotate /var/lib/logrotate rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1116 1001 1:1 /system-data/var/lib/misc /var/lib/misc rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1117 1001 1:1 /system-data/var/lib/snapd /var/lib/snapd rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1119 1118 0:0 / /var/lib/snapd/hostfs ro,relatime master:1 - squashfs /dev/loop0 ro -1118 1117 1:1 /system-data/var/lib/snapd/hostfs /var/lib/snapd/hostfs rw,relatime - ext4 /dev/sda3 rw,data=ordered -1120 1119 1:0 / /var/lib/snapd/hostfs/boot/efi rw,relatime master:2 - vfat /dev/sda2 rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro -1121 1119 1:0 /EFI/ubuntu /var/lib/snapd/hostfs/boot/grub rw,relatime master:2 - vfat /dev/sda2 rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro -1122 1119 1:1 /system-data/etc/apparmor.d/cache /var/lib/snapd/hostfs/etc/apparmor.d/cache rw,relatime master:8 - ext4 /dev/sda3 rw,data=ordered -1123 1119 1:1 /system-data/etc/cloud /var/lib/snapd/hostfs/etc/cloud rw,relatime master:9 - ext4 /dev/sda3 rw,data=ordered -1124 1119 1:1 /system-data/etc/dbus-1/system.d /var/lib/snapd/hostfs/etc/dbus-1/system.d rw,relatime master:10 - ext4 /dev/sda3 rw,data=ordered -1125 1119 1:1 /system-data/etc/default/keyboard /var/lib/snapd/hostfs/etc/default/keyboard rw,relatime master:11 - ext4 /dev/sda3 rw,data=ordered -1126 1119 1:1 /system-data/etc/default/swapfile /var/lib/snapd/hostfs/etc/default/swapfile rw,relatime master:12 - ext4 /dev/sda3 rw,data=ordered -1127 1119 1:1 /system-data/etc/environment /var/lib/snapd/hostfs/etc/environment rw,relatime master:13 - ext4 /dev/sda3 rw,data=ordered -1128 1119 2:5 /image.fstab /var/lib/snapd/hostfs/etc/fstab rw,nosuid,noexec,relatime master:14 - tmpfs tmpfs rw,mode=755 -1129 1119 1:1 /system-data/root/test-etc/group /var/lib/snapd/hostfs/etc/group ro,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1130 1119 1:1 /system-data/root/test-etc/gshadow /var/lib/snapd/hostfs/etc/gshadow ro,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1131 1119 1:1 /system-data/etc/hosts /var/lib/snapd/hostfs/etc/hosts rw,relatime master:16 - ext4 /dev/sda3 rw,data=ordered -1132 1119 1:1 /system-data/etc/init /var/lib/snapd/hostfs/etc/init rw,relatime master:17 - ext4 /dev/sda3 rw,data=ordered -1133 1119 1:1 /system-data/etc/init.d /var/lib/snapd/hostfs/etc/init.d rw,relatime master:18 - ext4 /dev/sda3 rw,data=ordered -1134 1119 1:1 /system-data/etc/iproute2 /var/lib/snapd/hostfs/etc/iproute2 rw,relatime master:19 - ext4 /dev/sda3 rw,data=ordered -1135 1119 1:1 /system-data/etc/machine-id /var/lib/snapd/hostfs/etc/machine-id rw,relatime master:20 - ext4 /dev/sda3 rw,data=ordered -1136 1119 1:1 /system-data/etc/modprobe.d /var/lib/snapd/hostfs/etc/modprobe.d rw,relatime master:21 - ext4 /dev/sda3 rw,data=ordered -1137 1119 1:1 /system-data/etc/modules-load.d /var/lib/snapd/hostfs/etc/modules-load.d rw,relatime master:22 - ext4 /dev/sda3 rw,data=ordered -1138 1119 1:1 /system-data/etc/netplan /var/lib/snapd/hostfs/etc/netplan rw,relatime master:23 - ext4 /dev/sda3 rw,data=ordered -1139 1119 1:1 /system-data/etc/network/if-up.d /var/lib/snapd/hostfs/etc/network/if-up.d rw,relatime master:24 - ext4 /dev/sda3 rw,data=ordered -1140 1119 1:1 /system-data/etc/network/interfaces.d /var/lib/snapd/hostfs/etc/network/interfaces.d rw,relatime master:25 - ext4 /dev/sda3 rw,data=ordered -1141 1119 1:1 /system-data/root/test-etc/passwd /var/lib/snapd/hostfs/etc/passwd ro,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1142 1119 1:1 /system-data/etc/ppp /var/lib/snapd/hostfs/etc/ppp rw,relatime master:26 - ext4 /dev/sda3 rw,data=ordered -1143 1119 1:1 /system-data/etc/rc0.d /var/lib/snapd/hostfs/etc/rc0.d rw,relatime master:27 - ext4 /dev/sda3 rw,data=ordered -1144 1119 1:1 /system-data/etc/rc1.d /var/lib/snapd/hostfs/etc/rc1.d rw,relatime master:28 - ext4 /dev/sda3 rw,data=ordered -1145 1119 1:1 /system-data/etc/rc2.d /var/lib/snapd/hostfs/etc/rc2.d rw,relatime master:29 - ext4 /dev/sda3 rw,data=ordered -1146 1119 1:1 /system-data/etc/rc3.d /var/lib/snapd/hostfs/etc/rc3.d rw,relatime master:30 - ext4 /dev/sda3 rw,data=ordered -1147 1119 1:1 /system-data/etc/rc4.d /var/lib/snapd/hostfs/etc/rc4.d rw,relatime master:31 - ext4 /dev/sda3 rw,data=ordered -1148 1119 1:1 /system-data/etc/rc5.d /var/lib/snapd/hostfs/etc/rc5.d rw,relatime master:32 - ext4 /dev/sda3 rw,data=ordered -1149 1119 1:1 /system-data/etc/rc6.d /var/lib/snapd/hostfs/etc/rc6.d rw,relatime master:33 - ext4 /dev/sda3 rw,data=ordered -1150 1119 1:1 /system-data/etc/rcS.d /var/lib/snapd/hostfs/etc/rcS.d rw,relatime master:34 - ext4 /dev/sda3 rw,data=ordered -1151 1119 1:1 /system-data/etc/rsyslog.d /var/lib/snapd/hostfs/etc/rsyslog.d rw,relatime master:35 - ext4 /dev/sda3 rw,data=ordered -1152 1119 1:1 /system-data/root/test-etc/shadow /var/lib/snapd/hostfs/etc/shadow ro,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1153 1119 1:1 /system-data/etc/ssh /var/lib/snapd/hostfs/etc/ssh rw,relatime master:36 - ext4 /dev/sda3 rw,data=ordered -1154 1119 1:1 /system-data/etc/sudoers.d /var/lib/snapd/hostfs/etc/sudoers.d rw,relatime master:37 - ext4 /dev/sda3 rw,data=ordered -1155 1119 1:1 /system-data/etc/sysctl.d /var/lib/snapd/hostfs/etc/sysctl.d rw,relatime master:38 - ext4 /dev/sda3 rw,data=ordered -1156 1119 1:1 /system-data/etc/systemd/logind.conf.d /var/lib/snapd/hostfs/etc/systemd/logind.conf.d rw,relatime master:39 - ext4 /dev/sda3 rw,data=ordered -1157 1119 1:1 /system-data/etc/systemd/network /var/lib/snapd/hostfs/etc/systemd/network rw,relatime master:40 - ext4 /dev/sda3 rw,data=ordered -1158 1119 1:1 /system-data/etc/systemd/system /var/lib/snapd/hostfs/etc/systemd/system rw,relatime master:41 - ext4 /dev/sda3 rw,data=ordered -1159 1158 1:1 /system-data/etc/systemd/system /var/lib/snapd/hostfs/etc/systemd/system rw,relatime master:42 - ext4 /dev/sda3 rw,data=ordered -1160 1119 1:1 /system-data/etc/systemd/system.conf.d /var/lib/snapd/hostfs/etc/systemd/system.conf.d rw,relatime master:43 - ext4 /dev/sda3 rw,data=ordered -1161 1119 1:1 /system-data/etc/systemd/timesyncd.conf /var/lib/snapd/hostfs/etc/systemd/timesyncd.conf rw,relatime master:44 - ext4 /dev/sda3 rw,data=ordered -1162 1119 1:1 /system-data/etc/systemd/user.conf.d /var/lib/snapd/hostfs/etc/systemd/user.conf.d rw,relatime master:45 - ext4 /dev/sda3 rw,data=ordered -1163 1119 1:1 /system-data/etc/udev/rules.d /var/lib/snapd/hostfs/etc/udev/rules.d rw,relatime master:46 - ext4 /dev/sda3 rw,data=ordered -1164 1119 1:1 /system-data/etc/update-motd.d /var/lib/snapd/hostfs/etc/update-motd.d rw,relatime master:47 - ext4 /dev/sda3 rw,data=ordered -1165 1119 1:1 /system-data/etc/writable /var/lib/snapd/hostfs/etc/writable rw,relatime master:48 - ext4 /dev/sda3 rw,data=ordered -1166 1119 1:1 /user-data /var/lib/snapd/hostfs/home rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1167 1119 0:1 /firmware /var/lib/snapd/hostfs/lib/firmware ro,relatime master:49 - squashfs /dev/loop1 ro -1168 1119 0:1 /modules /var/lib/snapd/hostfs/lib/modules ro,relatime master:50 - squashfs /dev/loop1 ro -1169 1119 2:6 / /var/lib/snapd/hostfs/media rw,relatime master:51 - tmpfs tmpfs rw -1170 1119 2:7 / /var/lib/snapd/hostfs/mnt rw,relatime master:52 - tmpfs tmpfs rw -1171 1119 1:1 /system-data/root /var/lib/snapd/hostfs/root rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1172 1119 2:5 / /var/lib/snapd/hostfs/run rw,nosuid,noexec,relatime master:56 - tmpfs tmpfs rw,mode=755 -1173 1172 2:10 / /var/lib/snapd/hostfs/run rw,nosuid,noexec,relatime master:55 - tmpfs tmpfs rw,size=VARIABLE,mode=755 -1174 1173 2:11 / /var/lib/snapd/hostfs/run/cgmanager/fs rw,relatime master:57 - tmpfs cgmfs rw,size=VARIABLE,mode=755 -1175 1173 2:12 / /var/lib/snapd/hostfs/run/lock rw,nosuid,nodev,noexec,relatime master:58 - tmpfs tmpfs rw,size=VARIABLE -1176 1173 2:10 /snapd/ns /var/lib/snapd/hostfs/run/snapd/ns rw,nosuid,noexec,relatime - tmpfs tmpfs rw,size=VARIABLE,mode=755 -1177 1173 2:13 / /var/lib/snapd/hostfs/run/user/0 rw,nosuid,nodev,relatime master:59 - tmpfs tmpfs rw,size=VARIABLE,mode=700 -1178 1119 1:1 /system-data/snap /var/lib/snapd/hostfs/snap rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1179 1178 0:2 / /var/lib/snapd/hostfs/snap/core/1 ro,nodev,relatime master:60 - squashfs /dev/loop2 ro -1180 1178 0:3 / /var/lib/snapd/hostfs/snap/core18/1 ro,nodev,relatime master:61 - squashfs /dev/loop3 ro -1181 1178 0:4 / /var/lib/snapd/hostfs/snap/pc-kernel/1 ro,nodev,relatime master:62 - squashfs /dev/loop4 ro -1182 1178 0:5 / /var/lib/snapd/hostfs/snap/pc/1 ro,nodev,relatime master:63 - squashfs /dev/loop5 ro -1183 1178 0:6 / /var/lib/snapd/hostfs/snap/test-snapd-mountinfo-core16/1 ro,nodev,relatime master:64 - squashfs /dev/loop6 ro -1184 1178 0:7 / /var/lib/snapd/hostfs/snap/test-snapd-mountinfo-core18/1 ro,nodev,relatime master:65 - squashfs /dev/loop7 ro -1185 1178 0:8 / /var/lib/snapd/hostfs/snap/test-snapd-rsync/1 ro,nodev,relatime master:66 - squashfs /dev/loop8 ro -1186 1119 2:31 / /var/lib/snapd/hostfs/tmp rw,relatime master:84 - tmpfs tmpfs rw -1187 1119 1:1 /system-data/var/cache/apparmor /var/lib/snapd/hostfs/var/cache/apparmor rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1188 1119 1:1 /system-data/var/cache/snapd /var/lib/snapd/hostfs/var/cache/snapd rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1189 1119 1:1 /system-data/var/lib/apparmor /var/lib/snapd/hostfs/var/lib/apparmor rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1190 1119 1:1 /system-data/var/lib/cloud /var/lib/snapd/hostfs/var/lib/cloud rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1191 1119 1:1 /system-data/var/lib/console-conf /var/lib/snapd/hostfs/var/lib/console-conf rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1192 1119 1:1 /system-data/var/lib/dbus /var/lib/snapd/hostfs/var/lib/dbus rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1193 1119 1:1 /system-data/var/lib/dhcp /var/lib/snapd/hostfs/var/lib/dhcp rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1194 1119 1:1 /system-data/var/lib/extrausers /var/lib/snapd/hostfs/var/lib/extrausers rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1195 1119 1:1 /system-data/var/lib/initramfs-tools /var/lib/snapd/hostfs/var/lib/initramfs-tools rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1196 1119 1:1 /system-data/var/lib/logrotate /var/lib/snapd/hostfs/var/lib/logrotate rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1197 1119 1:1 /system-data/var/lib/misc /var/lib/snapd/hostfs/var/lib/misc rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1198 1119 1:1 /system-data/var/lib/snapd /var/lib/snapd/hostfs/var/lib/snapd rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1199 1119 2:32 / /var/lib/snapd/hostfs/var/lib/sudo rw,relatime master:85 - tmpfs tmpfs rw,mode=700 -1200 1119 1:1 /system-data/var/lib/systemd/random-seed /var/lib/snapd/hostfs/var/lib/systemd/random-seed rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1201 1119 1:1 /system-data/var/lib/systemd/rfkill /var/lib/snapd/hostfs/var/lib/systemd/rfkill rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1202 1119 1:1 /system-data/var/lib/waagent /var/lib/snapd/hostfs/var/lib/waagent rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1203 1119 1:1 /system-data/var/log /var/lib/snapd/hostfs/var/log rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1204 1119 1:1 /system-data/var/snap /var/lib/snapd/hostfs/var/snap rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1205 1119 1:1 /system-data/var/tmp /var/lib/snapd/hostfs/var/tmp rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1206 1119 1:1 / /var/lib/snapd/hostfs/writable rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1207 1206 0:2 / /var/lib/snapd/hostfs/writable/system-data/snap/core/1 ro,nodev,relatime master:60 - squashfs /dev/loop2 ro -1208 1206 0:3 / /var/lib/snapd/hostfs/writable/system-data/snap/core18/1 ro,nodev,relatime master:61 - squashfs /dev/loop3 ro -1209 1206 0:4 / /var/lib/snapd/hostfs/writable/system-data/snap/pc-kernel/1 ro,nodev,relatime master:62 - squashfs /dev/loop4 ro -1210 1206 0:5 / /var/lib/snapd/hostfs/writable/system-data/snap/pc/1 ro,nodev,relatime master:63 - squashfs /dev/loop5 ro -1211 1206 0:6 / /var/lib/snapd/hostfs/writable/system-data/snap/test-snapd-mountinfo-core16/1 ro,nodev,relatime master:64 - squashfs /dev/loop6 ro -1212 1206 0:7 / /var/lib/snapd/hostfs/writable/system-data/snap/test-snapd-mountinfo-core18/1 ro,nodev,relatime master:65 - squashfs /dev/loop7 ro -1213 1206 0:8 / /var/lib/snapd/hostfs/writable/system-data/snap/test-snapd-rsync/1 ro,nodev,relatime master:66 - squashfs /dev/loop8 ro -1214 1001 2:32 / /var/lib/sudo rw,relatime master:85 - tmpfs tmpfs rw,mode=700 -1215 1001 1:1 /system-data/var/lib/systemd/random-seed /var/lib/systemd/random-seed rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1216 1001 1:1 /system-data/var/lib/systemd/rfkill /var/lib/systemd/rfkill rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1217 1001 1:1 /system-data/var/lib/waagent /var/lib/waagent rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1218 1001 1:1 /system-data/var/log /var/log rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1219 1001 1:1 /system-data/var/snap /var/snap rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1220 1001 1:1 /system-data/var/tmp /var/tmp rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1221 1001 1:1 / /writable rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -1222 1221 0:2 / /writable/system-data/snap/core/1 ro,nodev,relatime master:60 - squashfs /dev/loop2 ro -1223 1221 0:3 / /writable/system-data/snap/core18/1 ro,nodev,relatime master:61 - squashfs /dev/loop3 ro -1224 1221 0:4 / /writable/system-data/snap/pc-kernel/1 ro,nodev,relatime master:62 - squashfs /dev/loop4 ro -1225 1221 0:5 / /writable/system-data/snap/pc/1 ro,nodev,relatime master:63 - squashfs /dev/loop5 ro -1226 1221 0:6 / /writable/system-data/snap/test-snapd-mountinfo-core16/1 ro,nodev,relatime master:64 - squashfs /dev/loop6 ro -1227 1221 0:7 / /writable/system-data/snap/test-snapd-mountinfo-core18/1 ro,nodev,relatime master:65 - squashfs /dev/loop7 ro -1228 1221 0:8 / /writable/system-data/snap/test-snapd-rsync/1 ro,nodev,relatime master:66 - squashfs /dev/loop8 ro +1072 1071 0:2 / /snap/core/1 ro,nodev,relatime master:60 - squashfs /dev/loop2 ro +1073 1071 0:3 / /snap/core18/1 ro,nodev,relatime master:61 - squashfs /dev/loop3 ro +1074 1071 0:4 / /snap/pc-kernel/1 ro,nodev,relatime master:62 - squashfs /dev/loop4 ro +1075 1071 0:5 / /snap/pc/1 ro,nodev,relatime master:63 - squashfs /dev/loop5 ro +1076 1071 0:6 / /snap/test-snapd-mountinfo-core16/1 ro,nodev,relatime master:64 - squashfs /dev/loop6 ro +1077 1071 0:7 / /snap/test-snapd-mountinfo-core18/1 ro,nodev,relatime master:65 - squashfs /dev/loop7 ro +1078 1071 0:8 / /snap/test-snapd-rsync/1 ro,nodev,relatime master:66 - squashfs /dev/loop8 ro +1079 1001 2:14 / /sys rw,nosuid,nodev,noexec,relatime master:67 - sysfs sysfs rw +1080 1079 2:15 / /sys/fs/cgroup rw master:68 - tmpfs tmpfs rw,mode=755 +1081 1080 2:16 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime master:69 - cgroup cgroup rw,blkio +1082 1080 2:17 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime master:70 - cgroup cgroup rw,cpu,cpuacct +1083 1080 2:18 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime master:71 - cgroup cgroup rw,cpuset,clone_children +1084 1080 2:19 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime master:72 - cgroup cgroup rw,devices +1085 1080 2:20 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime master:73 - cgroup cgroup rw,freezer +1086 1080 2:21 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime master:74 - cgroup cgroup rw,hugetlb,release_agent=/run/cgmanager/agents/cgm-release-agent.hugetlb +1087 1080 2:22 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime master:75 - cgroup cgroup rw,memory +1088 1080 2:23 / /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime master:76 - cgroup cgroup rw,net_cls,net_prio +1089 1080 2:24 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime master:77 - cgroup cgroup rw,perf_event,release_agent=/run/cgmanager/agents/cgm-release-agent.perf_event +1090 1080 2:25 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime master:78 - cgroup cgroup rw,pids,release_agent=/run/cgmanager/agents/cgm-release-agent.pids +1091 1080 2:26 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime master:79 - cgroup cgroup rw,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd +1092 1079 2:27 / /sys/fs/fuse/connections rw,relatime master:80 - fusectl fusectl rw +1093 1079 2:28 / /sys/fs/pstore rw,nosuid,nodev,noexec,relatime master:81 - pstore pstore rw +1094 1079 2:29 / /sys/kernel/debug rw,relatime master:82 - debugfs debugfs rw +1095 1079 2:30 / /sys/kernel/security rw,nosuid,nodev,noexec,relatime master:83 - securityfs securityfs rw +1096 1001 2:31 / /tmp rw,relatime master:84 - tmpfs tmpfs rw +1097 1096 2:31 /snap.test-snapd-mountinfo-core16/tmp /tmp rw,relatime - tmpfs tmpfs rw +1098 1001 1:1 /system-data/var/cache/apparmor /var/cache/apparmor rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1099 1001 1:1 /system-data/var/cache/snapd /var/cache/snapd rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1100 1001 1:1 /system-data/var/lib/apparmor /var/lib/apparmor rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1101 1001 1:1 /system-data/var/lib/cloud /var/lib/cloud rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1102 1001 1:1 /system-data/var/lib/console-conf /var/lib/console-conf rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1103 1001 1:1 /system-data/var/lib/dbus /var/lib/dbus rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1104 1001 1:1 /system-data/var/lib/dhcp /var/lib/dhcp rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1105 1001 1:1 /system-data/var/lib/extrausers /var/lib/extrausers rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1106 1001 1:1 /system-data/var/lib/initramfs-tools /var/lib/initramfs-tools rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1107 1001 1:1 /system-data/var/lib/logrotate /var/lib/logrotate rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1108 1001 1:1 /system-data/var/lib/misc /var/lib/misc rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1109 1001 1:1 /system-data/var/lib/snapd /var/lib/snapd rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1111 1110 0:0 / /var/lib/snapd/hostfs ro,relatime master:1 - squashfs /dev/loop0 ro +1110 1109 1:1 /system-data/var/lib/snapd/hostfs /var/lib/snapd/hostfs rw,relatime - ext4 /dev/sda3 rw,data=ordered +1112 1111 1:0 / /var/lib/snapd/hostfs/boot/efi rw,relatime master:2 - vfat /dev/sda2 rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro +1113 1111 1:0 /EFI/ubuntu /var/lib/snapd/hostfs/boot/grub rw,relatime master:2 - vfat /dev/sda2 rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro +1114 1111 1:1 /system-data/etc/apparmor.d/cache /var/lib/snapd/hostfs/etc/apparmor.d/cache rw,relatime master:8 - ext4 /dev/sda3 rw,data=ordered +1115 1111 1:1 /system-data/etc/cloud /var/lib/snapd/hostfs/etc/cloud rw,relatime master:9 - ext4 /dev/sda3 rw,data=ordered +1116 1111 1:1 /system-data/etc/dbus-1/system.d /var/lib/snapd/hostfs/etc/dbus-1/system.d rw,relatime master:10 - ext4 /dev/sda3 rw,data=ordered +1117 1111 1:1 /system-data/etc/default/keyboard /var/lib/snapd/hostfs/etc/default/keyboard rw,relatime master:11 - ext4 /dev/sda3 rw,data=ordered +1118 1111 1:1 /system-data/etc/default/swapfile /var/lib/snapd/hostfs/etc/default/swapfile rw,relatime master:12 - ext4 /dev/sda3 rw,data=ordered +1119 1111 1:1 /system-data/etc/environment /var/lib/snapd/hostfs/etc/environment rw,relatime master:13 - ext4 /dev/sda3 rw,data=ordered +1120 1111 2:5 /image.fstab /var/lib/snapd/hostfs/etc/fstab rw,nosuid,noexec,relatime master:14 - tmpfs tmpfs rw,mode=755 +1121 1111 1:1 /system-data/root/test-etc/group /var/lib/snapd/hostfs/etc/group ro,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1122 1111 1:1 /system-data/root/test-etc/gshadow /var/lib/snapd/hostfs/etc/gshadow ro,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1123 1111 1:1 /system-data/etc/hosts /var/lib/snapd/hostfs/etc/hosts rw,relatime master:16 - ext4 /dev/sda3 rw,data=ordered +1124 1111 1:1 /system-data/etc/init /var/lib/snapd/hostfs/etc/init rw,relatime master:17 - ext4 /dev/sda3 rw,data=ordered +1125 1111 1:1 /system-data/etc/init.d /var/lib/snapd/hostfs/etc/init.d rw,relatime master:18 - ext4 /dev/sda3 rw,data=ordered +1126 1111 1:1 /system-data/etc/iproute2 /var/lib/snapd/hostfs/etc/iproute2 rw,relatime master:19 - ext4 /dev/sda3 rw,data=ordered +1127 1111 1:1 /system-data/etc/machine-id /var/lib/snapd/hostfs/etc/machine-id rw,relatime master:20 - ext4 /dev/sda3 rw,data=ordered +1128 1111 1:1 /system-data/etc/modprobe.d /var/lib/snapd/hostfs/etc/modprobe.d rw,relatime master:21 - ext4 /dev/sda3 rw,data=ordered +1129 1111 1:1 /system-data/etc/modules-load.d /var/lib/snapd/hostfs/etc/modules-load.d rw,relatime master:22 - ext4 /dev/sda3 rw,data=ordered +1130 1111 1:1 /system-data/etc/netplan /var/lib/snapd/hostfs/etc/netplan rw,relatime master:23 - ext4 /dev/sda3 rw,data=ordered +1131 1111 1:1 /system-data/etc/network/if-up.d /var/lib/snapd/hostfs/etc/network/if-up.d rw,relatime master:24 - ext4 /dev/sda3 rw,data=ordered +1132 1111 1:1 /system-data/etc/network/interfaces.d /var/lib/snapd/hostfs/etc/network/interfaces.d rw,relatime master:25 - ext4 /dev/sda3 rw,data=ordered +1133 1111 1:1 /system-data/root/test-etc/passwd /var/lib/snapd/hostfs/etc/passwd ro,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1134 1111 1:1 /system-data/etc/ppp /var/lib/snapd/hostfs/etc/ppp rw,relatime master:26 - ext4 /dev/sda3 rw,data=ordered +1135 1111 1:1 /system-data/etc/rc0.d /var/lib/snapd/hostfs/etc/rc0.d rw,relatime master:27 - ext4 /dev/sda3 rw,data=ordered +1136 1111 1:1 /system-data/etc/rc1.d /var/lib/snapd/hostfs/etc/rc1.d rw,relatime master:28 - ext4 /dev/sda3 rw,data=ordered +1137 1111 1:1 /system-data/etc/rc2.d /var/lib/snapd/hostfs/etc/rc2.d rw,relatime master:29 - ext4 /dev/sda3 rw,data=ordered +1138 1111 1:1 /system-data/etc/rc3.d /var/lib/snapd/hostfs/etc/rc3.d rw,relatime master:30 - ext4 /dev/sda3 rw,data=ordered +1139 1111 1:1 /system-data/etc/rc4.d /var/lib/snapd/hostfs/etc/rc4.d rw,relatime master:31 - ext4 /dev/sda3 rw,data=ordered +1140 1111 1:1 /system-data/etc/rc5.d /var/lib/snapd/hostfs/etc/rc5.d rw,relatime master:32 - ext4 /dev/sda3 rw,data=ordered +1141 1111 1:1 /system-data/etc/rc6.d /var/lib/snapd/hostfs/etc/rc6.d rw,relatime master:33 - ext4 /dev/sda3 rw,data=ordered +1142 1111 1:1 /system-data/etc/rcS.d /var/lib/snapd/hostfs/etc/rcS.d rw,relatime master:34 - ext4 /dev/sda3 rw,data=ordered +1143 1111 1:1 /system-data/etc/rsyslog.d /var/lib/snapd/hostfs/etc/rsyslog.d rw,relatime master:35 - ext4 /dev/sda3 rw,data=ordered +1144 1111 1:1 /system-data/root/test-etc/shadow /var/lib/snapd/hostfs/etc/shadow ro,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1145 1111 1:1 /system-data/etc/ssh /var/lib/snapd/hostfs/etc/ssh rw,relatime master:36 - ext4 /dev/sda3 rw,data=ordered +1146 1111 1:1 /system-data/etc/sudoers.d /var/lib/snapd/hostfs/etc/sudoers.d rw,relatime master:37 - ext4 /dev/sda3 rw,data=ordered +1147 1111 1:1 /system-data/etc/sysctl.d /var/lib/snapd/hostfs/etc/sysctl.d rw,relatime master:38 - ext4 /dev/sda3 rw,data=ordered +1148 1111 1:1 /system-data/etc/systemd/logind.conf.d /var/lib/snapd/hostfs/etc/systemd/logind.conf.d rw,relatime master:39 - ext4 /dev/sda3 rw,data=ordered +1149 1111 1:1 /system-data/etc/systemd/network /var/lib/snapd/hostfs/etc/systemd/network rw,relatime master:40 - ext4 /dev/sda3 rw,data=ordered +1150 1111 1:1 /system-data/etc/systemd/system /var/lib/snapd/hostfs/etc/systemd/system rw,relatime master:41 - ext4 /dev/sda3 rw,data=ordered +1151 1150 1:1 /system-data/etc/systemd/system /var/lib/snapd/hostfs/etc/systemd/system rw,relatime master:42 - ext4 /dev/sda3 rw,data=ordered +1152 1111 1:1 /system-data/etc/systemd/system.conf.d /var/lib/snapd/hostfs/etc/systemd/system.conf.d rw,relatime master:43 - ext4 /dev/sda3 rw,data=ordered +1153 1111 1:1 /system-data/etc/systemd/timesyncd.conf /var/lib/snapd/hostfs/etc/systemd/timesyncd.conf rw,relatime master:44 - ext4 /dev/sda3 rw,data=ordered +1154 1111 1:1 /system-data/etc/systemd/user.conf.d /var/lib/snapd/hostfs/etc/systemd/user.conf.d rw,relatime master:45 - ext4 /dev/sda3 rw,data=ordered +1155 1111 1:1 /system-data/etc/udev/rules.d /var/lib/snapd/hostfs/etc/udev/rules.d rw,relatime master:46 - ext4 /dev/sda3 rw,data=ordered +1156 1111 1:1 /system-data/etc/update-motd.d /var/lib/snapd/hostfs/etc/update-motd.d rw,relatime master:47 - ext4 /dev/sda3 rw,data=ordered +1157 1111 1:1 /system-data/etc/writable /var/lib/snapd/hostfs/etc/writable rw,relatime master:48 - ext4 /dev/sda3 rw,data=ordered +1158 1111 1:1 /user-data /var/lib/snapd/hostfs/home rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1159 1111 0:1 /firmware /var/lib/snapd/hostfs/lib/firmware ro,relatime master:49 - squashfs /dev/loop1 ro +1160 1111 0:1 /modules /var/lib/snapd/hostfs/lib/modules ro,relatime master:50 - squashfs /dev/loop1 ro +1161 1111 2:6 / /var/lib/snapd/hostfs/media rw,relatime master:51 - tmpfs tmpfs rw +1162 1111 2:7 / /var/lib/snapd/hostfs/mnt rw,relatime master:52 - tmpfs tmpfs rw +1163 1111 1:1 /system-data/root /var/lib/snapd/hostfs/root rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1164 1111 2:5 / /var/lib/snapd/hostfs/run rw,nosuid,noexec,relatime master:56 - tmpfs tmpfs rw,mode=755 +1165 1164 2:10 / /var/lib/snapd/hostfs/run rw,nosuid,noexec,relatime master:55 - tmpfs tmpfs rw,size=VARIABLE,mode=755 +1166 1165 2:11 / /var/lib/snapd/hostfs/run/cgmanager/fs rw,relatime master:57 - tmpfs cgmfs rw,size=VARIABLE,mode=755 +1167 1165 2:12 / /var/lib/snapd/hostfs/run/lock rw,nosuid,nodev,noexec,relatime master:58 - tmpfs tmpfs rw,size=VARIABLE +1168 1165 2:10 /snapd/ns /var/lib/snapd/hostfs/run/snapd/ns rw,nosuid,noexec,relatime - tmpfs tmpfs rw,size=VARIABLE,mode=755 +1169 1165 2:13 / /var/lib/snapd/hostfs/run/user/0 rw,nosuid,nodev,relatime master:59 - tmpfs tmpfs rw,size=VARIABLE,mode=700 +1170 1111 1:1 /system-data/snap /var/lib/snapd/hostfs/snap rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1171 1170 0:2 / /var/lib/snapd/hostfs/snap/core/1 ro,nodev,relatime master:60 - squashfs /dev/loop2 ro +1172 1170 0:3 / /var/lib/snapd/hostfs/snap/core18/1 ro,nodev,relatime master:61 - squashfs /dev/loop3 ro +1173 1170 0:4 / /var/lib/snapd/hostfs/snap/pc-kernel/1 ro,nodev,relatime master:62 - squashfs /dev/loop4 ro +1174 1170 0:5 / /var/lib/snapd/hostfs/snap/pc/1 ro,nodev,relatime master:63 - squashfs /dev/loop5 ro +1175 1170 0:6 / /var/lib/snapd/hostfs/snap/test-snapd-mountinfo-core16/1 ro,nodev,relatime master:64 - squashfs /dev/loop6 ro +1176 1170 0:7 / /var/lib/snapd/hostfs/snap/test-snapd-mountinfo-core18/1 ro,nodev,relatime master:65 - squashfs /dev/loop7 ro +1177 1170 0:8 / /var/lib/snapd/hostfs/snap/test-snapd-rsync/1 ro,nodev,relatime master:66 - squashfs /dev/loop8 ro +1178 1111 2:31 / /var/lib/snapd/hostfs/tmp rw,relatime master:84 - tmpfs tmpfs rw +1179 1111 1:1 /system-data/var/cache/apparmor /var/lib/snapd/hostfs/var/cache/apparmor rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1180 1111 1:1 /system-data/var/cache/snapd /var/lib/snapd/hostfs/var/cache/snapd rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1181 1111 1:1 /system-data/var/lib/apparmor /var/lib/snapd/hostfs/var/lib/apparmor rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1182 1111 1:1 /system-data/var/lib/cloud /var/lib/snapd/hostfs/var/lib/cloud rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1183 1111 1:1 /system-data/var/lib/console-conf /var/lib/snapd/hostfs/var/lib/console-conf rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1184 1111 1:1 /system-data/var/lib/dbus /var/lib/snapd/hostfs/var/lib/dbus rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1185 1111 1:1 /system-data/var/lib/dhcp /var/lib/snapd/hostfs/var/lib/dhcp rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1186 1111 1:1 /system-data/var/lib/extrausers /var/lib/snapd/hostfs/var/lib/extrausers rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1187 1111 1:1 /system-data/var/lib/initramfs-tools /var/lib/snapd/hostfs/var/lib/initramfs-tools rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1188 1111 1:1 /system-data/var/lib/logrotate /var/lib/snapd/hostfs/var/lib/logrotate rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1189 1111 1:1 /system-data/var/lib/misc /var/lib/snapd/hostfs/var/lib/misc rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1190 1111 1:1 /system-data/var/lib/snapd /var/lib/snapd/hostfs/var/lib/snapd rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1191 1111 2:32 / /var/lib/snapd/hostfs/var/lib/sudo rw,relatime master:85 - tmpfs tmpfs rw,mode=700 +1192 1111 1:1 /system-data/var/lib/systemd/random-seed /var/lib/snapd/hostfs/var/lib/systemd/random-seed rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1193 1111 1:1 /system-data/var/lib/systemd/rfkill /var/lib/snapd/hostfs/var/lib/systemd/rfkill rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1194 1111 1:1 /system-data/var/lib/waagent /var/lib/snapd/hostfs/var/lib/waagent rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1195 1111 1:1 /system-data/var/log /var/lib/snapd/hostfs/var/log rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1196 1111 1:1 /system-data/var/snap /var/lib/snapd/hostfs/var/snap rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1197 1111 1:1 /system-data/var/tmp /var/lib/snapd/hostfs/var/tmp rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1198 1111 1:1 / /var/lib/snapd/hostfs/writable rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1199 1198 0:2 / /var/lib/snapd/hostfs/writable/system-data/snap/core/1 ro,nodev,relatime master:60 - squashfs /dev/loop2 ro +1200 1198 0:3 / /var/lib/snapd/hostfs/writable/system-data/snap/core18/1 ro,nodev,relatime master:61 - squashfs /dev/loop3 ro +1201 1198 0:4 / /var/lib/snapd/hostfs/writable/system-data/snap/pc-kernel/1 ro,nodev,relatime master:62 - squashfs /dev/loop4 ro +1202 1198 0:5 / /var/lib/snapd/hostfs/writable/system-data/snap/pc/1 ro,nodev,relatime master:63 - squashfs /dev/loop5 ro +1203 1198 0:6 / /var/lib/snapd/hostfs/writable/system-data/snap/test-snapd-mountinfo-core16/1 ro,nodev,relatime master:64 - squashfs /dev/loop6 ro +1204 1198 0:7 / /var/lib/snapd/hostfs/writable/system-data/snap/test-snapd-mountinfo-core18/1 ro,nodev,relatime master:65 - squashfs /dev/loop7 ro +1205 1198 0:8 / /var/lib/snapd/hostfs/writable/system-data/snap/test-snapd-rsync/1 ro,nodev,relatime master:66 - squashfs /dev/loop8 ro +1206 1001 2:32 / /var/lib/sudo rw,relatime master:85 - tmpfs tmpfs rw,mode=700 +1207 1001 1:1 /system-data/var/lib/systemd/random-seed /var/lib/systemd/random-seed rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1208 1001 1:1 /system-data/var/lib/systemd/rfkill /var/lib/systemd/rfkill rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1209 1001 1:1 /system-data/var/lib/waagent /var/lib/waagent rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1210 1001 1:1 /system-data/var/log /var/log rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1211 1001 1:1 /system-data/var/snap /var/snap rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1212 1001 1:1 /system-data/var/tmp /var/tmp rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1213 1001 1:1 / /writable rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +1214 1213 0:2 / /writable/system-data/snap/core/1 ro,nodev,relatime master:60 - squashfs /dev/loop2 ro +1215 1213 0:3 / /writable/system-data/snap/core18/1 ro,nodev,relatime master:61 - squashfs /dev/loop3 ro +1216 1213 0:4 / /writable/system-data/snap/pc-kernel/1 ro,nodev,relatime master:62 - squashfs /dev/loop4 ro +1217 1213 0:5 / /writable/system-data/snap/pc/1 ro,nodev,relatime master:63 - squashfs /dev/loop5 ro +1218 1213 0:6 / /writable/system-data/snap/test-snapd-mountinfo-core16/1 ro,nodev,relatime master:64 - squashfs /dev/loop6 ro +1219 1213 0:7 / /writable/system-data/snap/test-snapd-mountinfo-core18/1 ro,nodev,relatime master:65 - squashfs /dev/loop7 ro +1220 1213 0:8 / /writable/system-data/snap/test-snapd-rsync/1 ro,nodev,relatime master:66 - squashfs /dev/loop8 ro diff --git a/tests/main/mount-ns/google.ubuntu-core-16-64/PER-USER-16.expected.txt b/tests/main/mount-ns/google.ubuntu-core-16-64/PER-USER-16.expected.txt index 4cef5723c5..76ce4d303f 100644 --- a/tests/main/mount-ns/google.ubuntu-core-16-64/PER-USER-16.expected.txt +++ b/tests/main/mount-ns/google.ubuntu-core-16-64/PER-USER-16.expected.txt @@ -69,160 +69,152 @@ 2069 2065 2:10 /snapd/ns /run/snapd/ns rw,nosuid,noexec,relatime - tmpfs tmpfs rw,size=VARIABLE,mode=755 2070 2065 2:13 / /run/user/0 rw,nosuid,nodev,relatime master:59 - tmpfs tmpfs rw,size=VARIABLE,mode=700 2071 2001 1:1 /system-data/snap /snap rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2072 2071 1:1 /system-data/snap /snap rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2073 2071 0:2 / /snap/core/1 ro,nodev,relatime master:60 - squashfs /dev/loop2 ro -2074 2072 0:2 / /snap/core/1 ro,nodev,relatime master:60 - squashfs /dev/loop2 ro -2075 2071 0:3 / /snap/core18/1 ro,nodev,relatime master:61 - squashfs /dev/loop3 ro -2076 2072 0:3 / /snap/core18/1 ro,nodev,relatime master:61 - squashfs /dev/loop3 ro -2077 2071 0:4 / /snap/pc-kernel/1 ro,nodev,relatime master:62 - squashfs /dev/loop4 ro -2078 2072 0:4 / /snap/pc-kernel/1 ro,nodev,relatime master:62 - squashfs /dev/loop4 ro -2079 2071 0:5 / /snap/pc/1 ro,nodev,relatime master:63 - squashfs /dev/loop5 ro -2080 2072 0:5 / /snap/pc/1 ro,nodev,relatime master:63 - squashfs /dev/loop5 ro -2081 2071 0:6 / /snap/test-snapd-mountinfo-core16/1 ro,nodev,relatime master:64 - squashfs /dev/loop6 ro -2082 2072 0:6 / /snap/test-snapd-mountinfo-core16/1 ro,nodev,relatime master:64 - squashfs /dev/loop6 ro -2083 2071 0:7 / /snap/test-snapd-mountinfo-core18/1 ro,nodev,relatime master:65 - squashfs /dev/loop7 ro -2084 2072 0:7 / /snap/test-snapd-mountinfo-core18/1 ro,nodev,relatime master:65 - squashfs /dev/loop7 ro -2085 2071 0:8 / /snap/test-snapd-rsync/1 ro,nodev,relatime master:66 - squashfs /dev/loop8 ro -2086 2072 0:8 / /snap/test-snapd-rsync/1 ro,nodev,relatime master:66 - squashfs /dev/loop8 ro -2087 2001 2:14 / /sys rw,nosuid,nodev,noexec,relatime master:67 - sysfs sysfs rw -2088 2087 2:15 / /sys/fs/cgroup rw master:68 - tmpfs tmpfs rw,mode=755 -2089 2088 2:16 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime master:69 - cgroup cgroup rw,blkio -2090 2088 2:17 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime master:70 - cgroup cgroup rw,cpu,cpuacct -2091 2088 2:18 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime master:71 - cgroup cgroup rw,cpuset,clone_children -2092 2088 2:19 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime master:72 - cgroup cgroup rw,devices -2093 2088 2:20 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime master:73 - cgroup cgroup rw,freezer -2094 2088 2:21 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime master:74 - cgroup cgroup rw,hugetlb,release_agent=/run/cgmanager/agents/cgm-release-agent.hugetlb -2095 2088 2:22 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime master:75 - cgroup cgroup rw,memory -2096 2088 2:23 / /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime master:76 - cgroup cgroup rw,net_cls,net_prio -2097 2088 2:24 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime master:77 - cgroup cgroup rw,perf_event,release_agent=/run/cgmanager/agents/cgm-release-agent.perf_event -2098 2088 2:25 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime master:78 - cgroup cgroup rw,pids,release_agent=/run/cgmanager/agents/cgm-release-agent.pids -2099 2088 2:26 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime master:79 - cgroup cgroup rw,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd -2100 2087 2:27 / /sys/fs/fuse/connections rw,relatime master:80 - fusectl fusectl rw -2101 2087 2:28 / /sys/fs/pstore rw,nosuid,nodev,noexec,relatime master:81 - pstore pstore rw -2102 2087 2:29 / /sys/kernel/debug rw,relatime master:82 - debugfs debugfs rw -2103 2087 2:30 / /sys/kernel/security rw,nosuid,nodev,noexec,relatime master:83 - securityfs securityfs rw -2104 2001 2:31 / /tmp rw,relatime master:84 - tmpfs tmpfs rw -2105 2104 2:31 /snap.test-snapd-mountinfo-core16/tmp /tmp rw,relatime - tmpfs tmpfs rw -2106 2001 1:1 /system-data/var/cache/apparmor /var/cache/apparmor rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2107 2001 1:1 /system-data/var/cache/snapd /var/cache/snapd rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2108 2001 1:1 /system-data/var/lib/apparmor /var/lib/apparmor rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2109 2001 1:1 /system-data/var/lib/cloud /var/lib/cloud rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2110 2001 1:1 /system-data/var/lib/console-conf /var/lib/console-conf rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2111 2001 1:1 /system-data/var/lib/dbus /var/lib/dbus rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2112 2001 1:1 /system-data/var/lib/dhcp /var/lib/dhcp rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2113 2001 1:1 /system-data/var/lib/extrausers /var/lib/extrausers rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2114 2001 1:1 /system-data/var/lib/initramfs-tools /var/lib/initramfs-tools rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2115 2001 1:1 /system-data/var/lib/logrotate /var/lib/logrotate rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2116 2001 1:1 /system-data/var/lib/misc /var/lib/misc rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2117 2001 1:1 /system-data/var/lib/snapd /var/lib/snapd rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2119 2118 0:0 / /var/lib/snapd/hostfs ro,relatime master:1 - squashfs /dev/loop0 ro -2118 2117 1:1 /system-data/var/lib/snapd/hostfs /var/lib/snapd/hostfs rw,relatime - ext4 /dev/sda3 rw,data=ordered -2120 2119 1:0 / /var/lib/snapd/hostfs/boot/efi rw,relatime master:2 - vfat /dev/sda2 rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro -2121 2119 1:0 /EFI/ubuntu /var/lib/snapd/hostfs/boot/grub rw,relatime master:2 - vfat /dev/sda2 rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro -2122 2119 1:1 /system-data/etc/apparmor.d/cache /var/lib/snapd/hostfs/etc/apparmor.d/cache rw,relatime master:8 - ext4 /dev/sda3 rw,data=ordered -2123 2119 1:1 /system-data/etc/cloud /var/lib/snapd/hostfs/etc/cloud rw,relatime master:9 - ext4 /dev/sda3 rw,data=ordered -2124 2119 1:1 /system-data/etc/dbus-1/system.d /var/lib/snapd/hostfs/etc/dbus-1/system.d rw,relatime master:10 - ext4 /dev/sda3 rw,data=ordered -2125 2119 1:1 /system-data/etc/default/keyboard /var/lib/snapd/hostfs/etc/default/keyboard rw,relatime master:11 - ext4 /dev/sda3 rw,data=ordered -2126 2119 1:1 /system-data/etc/default/swapfile /var/lib/snapd/hostfs/etc/default/swapfile rw,relatime master:12 - ext4 /dev/sda3 rw,data=ordered -2127 2119 1:1 /system-data/etc/environment /var/lib/snapd/hostfs/etc/environment rw,relatime master:13 - ext4 /dev/sda3 rw,data=ordered -2128 2119 2:5 /image.fstab /var/lib/snapd/hostfs/etc/fstab rw,nosuid,noexec,relatime master:14 - tmpfs tmpfs rw,mode=755 -2129 2119 1:1 /system-data/root/test-etc/group /var/lib/snapd/hostfs/etc/group ro,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2130 2119 1:1 /system-data/root/test-etc/gshadow /var/lib/snapd/hostfs/etc/gshadow ro,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2131 2119 1:1 /system-data/etc/hosts /var/lib/snapd/hostfs/etc/hosts rw,relatime master:16 - ext4 /dev/sda3 rw,data=ordered -2132 2119 1:1 /system-data/etc/init /var/lib/snapd/hostfs/etc/init rw,relatime master:17 - ext4 /dev/sda3 rw,data=ordered -2133 2119 1:1 /system-data/etc/init.d /var/lib/snapd/hostfs/etc/init.d rw,relatime master:18 - ext4 /dev/sda3 rw,data=ordered -2134 2119 1:1 /system-data/etc/iproute2 /var/lib/snapd/hostfs/etc/iproute2 rw,relatime master:19 - ext4 /dev/sda3 rw,data=ordered -2135 2119 1:1 /system-data/etc/machine-id /var/lib/snapd/hostfs/etc/machine-id rw,relatime master:20 - ext4 /dev/sda3 rw,data=ordered -2136 2119 1:1 /system-data/etc/modprobe.d /var/lib/snapd/hostfs/etc/modprobe.d rw,relatime master:21 - ext4 /dev/sda3 rw,data=ordered -2137 2119 1:1 /system-data/etc/modules-load.d /var/lib/snapd/hostfs/etc/modules-load.d rw,relatime master:22 - ext4 /dev/sda3 rw,data=ordered -2138 2119 1:1 /system-data/etc/netplan /var/lib/snapd/hostfs/etc/netplan rw,relatime master:23 - ext4 /dev/sda3 rw,data=ordered -2139 2119 1:1 /system-data/etc/network/if-up.d /var/lib/snapd/hostfs/etc/network/if-up.d rw,relatime master:24 - ext4 /dev/sda3 rw,data=ordered -2140 2119 1:1 /system-data/etc/network/interfaces.d /var/lib/snapd/hostfs/etc/network/interfaces.d rw,relatime master:25 - ext4 /dev/sda3 rw,data=ordered -2141 2119 1:1 /system-data/root/test-etc/passwd /var/lib/snapd/hostfs/etc/passwd ro,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2142 2119 1:1 /system-data/etc/ppp /var/lib/snapd/hostfs/etc/ppp rw,relatime master:26 - ext4 /dev/sda3 rw,data=ordered -2143 2119 1:1 /system-data/etc/rc0.d /var/lib/snapd/hostfs/etc/rc0.d rw,relatime master:27 - ext4 /dev/sda3 rw,data=ordered -2144 2119 1:1 /system-data/etc/rc1.d /var/lib/snapd/hostfs/etc/rc1.d rw,relatime master:28 - ext4 /dev/sda3 rw,data=ordered -2145 2119 1:1 /system-data/etc/rc2.d /var/lib/snapd/hostfs/etc/rc2.d rw,relatime master:29 - ext4 /dev/sda3 rw,data=ordered -2146 2119 1:1 /system-data/etc/rc3.d /var/lib/snapd/hostfs/etc/rc3.d rw,relatime master:30 - ext4 /dev/sda3 rw,data=ordered -2147 2119 1:1 /system-data/etc/rc4.d /var/lib/snapd/hostfs/etc/rc4.d rw,relatime master:31 - ext4 /dev/sda3 rw,data=ordered -2148 2119 1:1 /system-data/etc/rc5.d /var/lib/snapd/hostfs/etc/rc5.d rw,relatime master:32 - ext4 /dev/sda3 rw,data=ordered -2149 2119 1:1 /system-data/etc/rc6.d /var/lib/snapd/hostfs/etc/rc6.d rw,relatime master:33 - ext4 /dev/sda3 rw,data=ordered -2150 2119 1:1 /system-data/etc/rcS.d /var/lib/snapd/hostfs/etc/rcS.d rw,relatime master:34 - ext4 /dev/sda3 rw,data=ordered -2151 2119 1:1 /system-data/etc/rsyslog.d /var/lib/snapd/hostfs/etc/rsyslog.d rw,relatime master:35 - ext4 /dev/sda3 rw,data=ordered -2152 2119 1:1 /system-data/root/test-etc/shadow /var/lib/snapd/hostfs/etc/shadow ro,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2153 2119 1:1 /system-data/etc/ssh /var/lib/snapd/hostfs/etc/ssh rw,relatime master:36 - ext4 /dev/sda3 rw,data=ordered -2154 2119 1:1 /system-data/etc/sudoers.d /var/lib/snapd/hostfs/etc/sudoers.d rw,relatime master:37 - ext4 /dev/sda3 rw,data=ordered -2155 2119 1:1 /system-data/etc/sysctl.d /var/lib/snapd/hostfs/etc/sysctl.d rw,relatime master:38 - ext4 /dev/sda3 rw,data=ordered -2156 2119 1:1 /system-data/etc/systemd/logind.conf.d /var/lib/snapd/hostfs/etc/systemd/logind.conf.d rw,relatime master:39 - ext4 /dev/sda3 rw,data=ordered -2157 2119 1:1 /system-data/etc/systemd/network /var/lib/snapd/hostfs/etc/systemd/network rw,relatime master:40 - ext4 /dev/sda3 rw,data=ordered -2158 2119 1:1 /system-data/etc/systemd/system /var/lib/snapd/hostfs/etc/systemd/system rw,relatime master:41 - ext4 /dev/sda3 rw,data=ordered -2159 2158 1:1 /system-data/etc/systemd/system /var/lib/snapd/hostfs/etc/systemd/system rw,relatime master:42 - ext4 /dev/sda3 rw,data=ordered -2160 2119 1:1 /system-data/etc/systemd/system.conf.d /var/lib/snapd/hostfs/etc/systemd/system.conf.d rw,relatime master:43 - ext4 /dev/sda3 rw,data=ordered -2161 2119 1:1 /system-data/etc/systemd/timesyncd.conf /var/lib/snapd/hostfs/etc/systemd/timesyncd.conf rw,relatime master:44 - ext4 /dev/sda3 rw,data=ordered -2162 2119 1:1 /system-data/etc/systemd/user.conf.d /var/lib/snapd/hostfs/etc/systemd/user.conf.d rw,relatime master:45 - ext4 /dev/sda3 rw,data=ordered -2163 2119 1:1 /system-data/etc/udev/rules.d /var/lib/snapd/hostfs/etc/udev/rules.d rw,relatime master:46 - ext4 /dev/sda3 rw,data=ordered -2164 2119 1:1 /system-data/etc/update-motd.d /var/lib/snapd/hostfs/etc/update-motd.d rw,relatime master:47 - ext4 /dev/sda3 rw,data=ordered -2165 2119 1:1 /system-data/etc/writable /var/lib/snapd/hostfs/etc/writable rw,relatime master:48 - ext4 /dev/sda3 rw,data=ordered -2166 2119 1:1 /user-data /var/lib/snapd/hostfs/home rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2167 2119 0:1 /firmware /var/lib/snapd/hostfs/lib/firmware ro,relatime master:49 - squashfs /dev/loop1 ro -2168 2119 0:1 /modules /var/lib/snapd/hostfs/lib/modules ro,relatime master:50 - squashfs /dev/loop1 ro -2169 2119 2:6 / /var/lib/snapd/hostfs/media rw,relatime master:51 - tmpfs tmpfs rw -2170 2119 2:7 / /var/lib/snapd/hostfs/mnt rw,relatime master:52 - tmpfs tmpfs rw -2171 2119 1:1 /system-data/root /var/lib/snapd/hostfs/root rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2172 2119 2:5 / /var/lib/snapd/hostfs/run rw,nosuid,noexec,relatime master:56 - tmpfs tmpfs rw,mode=755 -2173 2172 2:10 / /var/lib/snapd/hostfs/run rw,nosuid,noexec,relatime master:55 - tmpfs tmpfs rw,size=VARIABLE,mode=755 -2174 2173 2:11 / /var/lib/snapd/hostfs/run/cgmanager/fs rw,relatime master:57 - tmpfs cgmfs rw,size=VARIABLE,mode=755 -2175 2173 2:12 / /var/lib/snapd/hostfs/run/lock rw,nosuid,nodev,noexec,relatime master:58 - tmpfs tmpfs rw,size=VARIABLE -2176 2173 2:10 /snapd/ns /var/lib/snapd/hostfs/run/snapd/ns rw,nosuid,noexec,relatime - tmpfs tmpfs rw,size=VARIABLE,mode=755 -2177 2173 2:13 / /var/lib/snapd/hostfs/run/user/0 rw,nosuid,nodev,relatime master:59 - tmpfs tmpfs rw,size=VARIABLE,mode=700 -2178 2119 1:1 /system-data/snap /var/lib/snapd/hostfs/snap rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2179 2178 0:2 / /var/lib/snapd/hostfs/snap/core/1 ro,nodev,relatime master:60 - squashfs /dev/loop2 ro -2180 2178 0:3 / /var/lib/snapd/hostfs/snap/core18/1 ro,nodev,relatime master:61 - squashfs /dev/loop3 ro -2181 2178 0:4 / /var/lib/snapd/hostfs/snap/pc-kernel/1 ro,nodev,relatime master:62 - squashfs /dev/loop4 ro -2182 2178 0:5 / /var/lib/snapd/hostfs/snap/pc/1 ro,nodev,relatime master:63 - squashfs /dev/loop5 ro -2183 2178 0:6 / /var/lib/snapd/hostfs/snap/test-snapd-mountinfo-core16/1 ro,nodev,relatime master:64 - squashfs /dev/loop6 ro -2184 2178 0:7 / /var/lib/snapd/hostfs/snap/test-snapd-mountinfo-core18/1 ro,nodev,relatime master:65 - squashfs /dev/loop7 ro -2185 2178 0:8 / /var/lib/snapd/hostfs/snap/test-snapd-rsync/1 ro,nodev,relatime master:66 - squashfs /dev/loop8 ro -2186 2119 2:31 / /var/lib/snapd/hostfs/tmp rw,relatime master:84 - tmpfs tmpfs rw -2187 2119 1:1 /system-data/var/cache/apparmor /var/lib/snapd/hostfs/var/cache/apparmor rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2188 2119 1:1 /system-data/var/cache/snapd /var/lib/snapd/hostfs/var/cache/snapd rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2189 2119 1:1 /system-data/var/lib/apparmor /var/lib/snapd/hostfs/var/lib/apparmor rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2190 2119 1:1 /system-data/var/lib/cloud /var/lib/snapd/hostfs/var/lib/cloud rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2191 2119 1:1 /system-data/var/lib/console-conf /var/lib/snapd/hostfs/var/lib/console-conf rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2192 2119 1:1 /system-data/var/lib/dbus /var/lib/snapd/hostfs/var/lib/dbus rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2193 2119 1:1 /system-data/var/lib/dhcp /var/lib/snapd/hostfs/var/lib/dhcp rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2194 2119 1:1 /system-data/var/lib/extrausers /var/lib/snapd/hostfs/var/lib/extrausers rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2195 2119 1:1 /system-data/var/lib/initramfs-tools /var/lib/snapd/hostfs/var/lib/initramfs-tools rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2196 2119 1:1 /system-data/var/lib/logrotate /var/lib/snapd/hostfs/var/lib/logrotate rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2197 2119 1:1 /system-data/var/lib/misc /var/lib/snapd/hostfs/var/lib/misc rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2198 2119 1:1 /system-data/var/lib/snapd /var/lib/snapd/hostfs/var/lib/snapd rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2199 2119 2:32 / /var/lib/snapd/hostfs/var/lib/sudo rw,relatime master:85 - tmpfs tmpfs rw,mode=700 -2200 2119 1:1 /system-data/var/lib/systemd/random-seed /var/lib/snapd/hostfs/var/lib/systemd/random-seed rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2201 2119 1:1 /system-data/var/lib/systemd/rfkill /var/lib/snapd/hostfs/var/lib/systemd/rfkill rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2202 2119 1:1 /system-data/var/lib/waagent /var/lib/snapd/hostfs/var/lib/waagent rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2203 2119 1:1 /system-data/var/log /var/lib/snapd/hostfs/var/log rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2204 2119 1:1 /system-data/var/snap /var/lib/snapd/hostfs/var/snap rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2205 2119 1:1 /system-data/var/tmp /var/lib/snapd/hostfs/var/tmp rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2206 2119 1:1 / /var/lib/snapd/hostfs/writable rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2207 2206 0:2 / /var/lib/snapd/hostfs/writable/system-data/snap/core/1 ro,nodev,relatime master:60 - squashfs /dev/loop2 ro -2208 2206 0:3 / /var/lib/snapd/hostfs/writable/system-data/snap/core18/1 ro,nodev,relatime master:61 - squashfs /dev/loop3 ro -2209 2206 0:4 / /var/lib/snapd/hostfs/writable/system-data/snap/pc-kernel/1 ro,nodev,relatime master:62 - squashfs /dev/loop4 ro -2210 2206 0:5 / /var/lib/snapd/hostfs/writable/system-data/snap/pc/1 ro,nodev,relatime master:63 - squashfs /dev/loop5 ro -2211 2206 0:6 / /var/lib/snapd/hostfs/writable/system-data/snap/test-snapd-mountinfo-core16/1 ro,nodev,relatime master:64 - squashfs /dev/loop6 ro -2212 2206 0:7 / /var/lib/snapd/hostfs/writable/system-data/snap/test-snapd-mountinfo-core18/1 ro,nodev,relatime master:65 - squashfs /dev/loop7 ro -2213 2206 0:8 / /var/lib/snapd/hostfs/writable/system-data/snap/test-snapd-rsync/1 ro,nodev,relatime master:66 - squashfs /dev/loop8 ro -2214 2001 2:32 / /var/lib/sudo rw,relatime master:85 - tmpfs tmpfs rw,mode=700 -2215 2001 1:1 /system-data/var/lib/systemd/random-seed /var/lib/systemd/random-seed rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2216 2001 1:1 /system-data/var/lib/systemd/rfkill /var/lib/systemd/rfkill rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2217 2001 1:1 /system-data/var/lib/waagent /var/lib/waagent rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2218 2001 1:1 /system-data/var/log /var/log rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2219 2001 1:1 /system-data/var/snap /var/snap rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2220 2001 1:1 /system-data/var/tmp /var/tmp rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2221 2001 1:1 / /writable rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered -2222 2221 0:2 / /writable/system-data/snap/core/1 ro,nodev,relatime master:60 - squashfs /dev/loop2 ro -2223 2221 0:3 / /writable/system-data/snap/core18/1 ro,nodev,relatime master:61 - squashfs /dev/loop3 ro -2224 2221 0:4 / /writable/system-data/snap/pc-kernel/1 ro,nodev,relatime master:62 - squashfs /dev/loop4 ro -2225 2221 0:5 / /writable/system-data/snap/pc/1 ro,nodev,relatime master:63 - squashfs /dev/loop5 ro -2226 2221 0:6 / /writable/system-data/snap/test-snapd-mountinfo-core16/1 ro,nodev,relatime master:64 - squashfs /dev/loop6 ro -2227 2221 0:7 / /writable/system-data/snap/test-snapd-mountinfo-core18/1 ro,nodev,relatime master:65 - squashfs /dev/loop7 ro -2228 2221 0:8 / /writable/system-data/snap/test-snapd-rsync/1 ro,nodev,relatime master:66 - squashfs /dev/loop8 ro +2072 2071 0:2 / /snap/core/1 ro,nodev,relatime master:60 - squashfs /dev/loop2 ro +2073 2071 0:3 / /snap/core18/1 ro,nodev,relatime master:61 - squashfs /dev/loop3 ro +2074 2071 0:4 / /snap/pc-kernel/1 ro,nodev,relatime master:62 - squashfs /dev/loop4 ro +2075 2071 0:5 / /snap/pc/1 ro,nodev,relatime master:63 - squashfs /dev/loop5 ro +2076 2071 0:6 / /snap/test-snapd-mountinfo-core16/1 ro,nodev,relatime master:64 - squashfs /dev/loop6 ro +2077 2071 0:7 / /snap/test-snapd-mountinfo-core18/1 ro,nodev,relatime master:65 - squashfs /dev/loop7 ro +2078 2071 0:8 / /snap/test-snapd-rsync/1 ro,nodev,relatime master:66 - squashfs /dev/loop8 ro +2079 2001 2:14 / /sys rw,nosuid,nodev,noexec,relatime master:67 - sysfs sysfs rw +2080 2079 2:15 / /sys/fs/cgroup rw master:68 - tmpfs tmpfs rw,mode=755 +2081 2080 2:16 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime master:69 - cgroup cgroup rw,blkio +2082 2080 2:17 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime master:70 - cgroup cgroup rw,cpu,cpuacct +2083 2080 2:18 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime master:71 - cgroup cgroup rw,cpuset,clone_children +2084 2080 2:19 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime master:72 - cgroup cgroup rw,devices +2085 2080 2:20 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime master:73 - cgroup cgroup rw,freezer +2086 2080 2:21 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime master:74 - cgroup cgroup rw,hugetlb,release_agent=/run/cgmanager/agents/cgm-release-agent.hugetlb +2087 2080 2:22 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime master:75 - cgroup cgroup rw,memory +2088 2080 2:23 / /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime master:76 - cgroup cgroup rw,net_cls,net_prio +2089 2080 2:24 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime master:77 - cgroup cgroup rw,perf_event,release_agent=/run/cgmanager/agents/cgm-release-agent.perf_event +2090 2080 2:25 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime master:78 - cgroup cgroup rw,pids,release_agent=/run/cgmanager/agents/cgm-release-agent.pids +2091 2080 2:26 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime master:79 - cgroup cgroup rw,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd +2092 2079 2:27 / /sys/fs/fuse/connections rw,relatime master:80 - fusectl fusectl rw +2093 2079 2:28 / /sys/fs/pstore rw,nosuid,nodev,noexec,relatime master:81 - pstore pstore rw +2094 2079 2:29 / /sys/kernel/debug rw,relatime master:82 - debugfs debugfs rw +2095 2079 2:30 / /sys/kernel/security rw,nosuid,nodev,noexec,relatime master:83 - securityfs securityfs rw +2096 2001 2:31 / /tmp rw,relatime master:84 - tmpfs tmpfs rw +2097 2096 2:31 /snap.test-snapd-mountinfo-core16/tmp /tmp rw,relatime - tmpfs tmpfs rw +2098 2001 1:1 /system-data/var/cache/apparmor /var/cache/apparmor rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2099 2001 1:1 /system-data/var/cache/snapd /var/cache/snapd rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2100 2001 1:1 /system-data/var/lib/apparmor /var/lib/apparmor rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2101 2001 1:1 /system-data/var/lib/cloud /var/lib/cloud rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2102 2001 1:1 /system-data/var/lib/console-conf /var/lib/console-conf rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2103 2001 1:1 /system-data/var/lib/dbus /var/lib/dbus rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2104 2001 1:1 /system-data/var/lib/dhcp /var/lib/dhcp rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2105 2001 1:1 /system-data/var/lib/extrausers /var/lib/extrausers rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2106 2001 1:1 /system-data/var/lib/initramfs-tools /var/lib/initramfs-tools rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2107 2001 1:1 /system-data/var/lib/logrotate /var/lib/logrotate rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2108 2001 1:1 /system-data/var/lib/misc /var/lib/misc rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2109 2001 1:1 /system-data/var/lib/snapd /var/lib/snapd rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2111 2110 0:0 / /var/lib/snapd/hostfs ro,relatime master:1 - squashfs /dev/loop0 ro +2110 2109 1:1 /system-data/var/lib/snapd/hostfs /var/lib/snapd/hostfs rw,relatime - ext4 /dev/sda3 rw,data=ordered +2112 2111 1:0 / /var/lib/snapd/hostfs/boot/efi rw,relatime master:2 - vfat /dev/sda2 rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro +2113 2111 1:0 /EFI/ubuntu /var/lib/snapd/hostfs/boot/grub rw,relatime master:2 - vfat /dev/sda2 rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro +2114 2111 1:1 /system-data/etc/apparmor.d/cache /var/lib/snapd/hostfs/etc/apparmor.d/cache rw,relatime master:8 - ext4 /dev/sda3 rw,data=ordered +2115 2111 1:1 /system-data/etc/cloud /var/lib/snapd/hostfs/etc/cloud rw,relatime master:9 - ext4 /dev/sda3 rw,data=ordered +2116 2111 1:1 /system-data/etc/dbus-1/system.d /var/lib/snapd/hostfs/etc/dbus-1/system.d rw,relatime master:10 - ext4 /dev/sda3 rw,data=ordered +2117 2111 1:1 /system-data/etc/default/keyboard /var/lib/snapd/hostfs/etc/default/keyboard rw,relatime master:11 - ext4 /dev/sda3 rw,data=ordered +2118 2111 1:1 /system-data/etc/default/swapfile /var/lib/snapd/hostfs/etc/default/swapfile rw,relatime master:12 - ext4 /dev/sda3 rw,data=ordered +2119 2111 1:1 /system-data/etc/environment /var/lib/snapd/hostfs/etc/environment rw,relatime master:13 - ext4 /dev/sda3 rw,data=ordered +2120 2111 2:5 /image.fstab /var/lib/snapd/hostfs/etc/fstab rw,nosuid,noexec,relatime master:14 - tmpfs tmpfs rw,mode=755 +2121 2111 1:1 /system-data/root/test-etc/group /var/lib/snapd/hostfs/etc/group ro,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2122 2111 1:1 /system-data/root/test-etc/gshadow /var/lib/snapd/hostfs/etc/gshadow ro,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2123 2111 1:1 /system-data/etc/hosts /var/lib/snapd/hostfs/etc/hosts rw,relatime master:16 - ext4 /dev/sda3 rw,data=ordered +2124 2111 1:1 /system-data/etc/init /var/lib/snapd/hostfs/etc/init rw,relatime master:17 - ext4 /dev/sda3 rw,data=ordered +2125 2111 1:1 /system-data/etc/init.d /var/lib/snapd/hostfs/etc/init.d rw,relatime master:18 - ext4 /dev/sda3 rw,data=ordered +2126 2111 1:1 /system-data/etc/iproute2 /var/lib/snapd/hostfs/etc/iproute2 rw,relatime master:19 - ext4 /dev/sda3 rw,data=ordered +2127 2111 1:1 /system-data/etc/machine-id /var/lib/snapd/hostfs/etc/machine-id rw,relatime master:20 - ext4 /dev/sda3 rw,data=ordered +2128 2111 1:1 /system-data/etc/modprobe.d /var/lib/snapd/hostfs/etc/modprobe.d rw,relatime master:21 - ext4 /dev/sda3 rw,data=ordered +2129 2111 1:1 /system-data/etc/modules-load.d /var/lib/snapd/hostfs/etc/modules-load.d rw,relatime master:22 - ext4 /dev/sda3 rw,data=ordered +2130 2111 1:1 /system-data/etc/netplan /var/lib/snapd/hostfs/etc/netplan rw,relatime master:23 - ext4 /dev/sda3 rw,data=ordered +2131 2111 1:1 /system-data/etc/network/if-up.d /var/lib/snapd/hostfs/etc/network/if-up.d rw,relatime master:24 - ext4 /dev/sda3 rw,data=ordered +2132 2111 1:1 /system-data/etc/network/interfaces.d /var/lib/snapd/hostfs/etc/network/interfaces.d rw,relatime master:25 - ext4 /dev/sda3 rw,data=ordered +2133 2111 1:1 /system-data/root/test-etc/passwd /var/lib/snapd/hostfs/etc/passwd ro,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2134 2111 1:1 /system-data/etc/ppp /var/lib/snapd/hostfs/etc/ppp rw,relatime master:26 - ext4 /dev/sda3 rw,data=ordered +2135 2111 1:1 /system-data/etc/rc0.d /var/lib/snapd/hostfs/etc/rc0.d rw,relatime master:27 - ext4 /dev/sda3 rw,data=ordered +2136 2111 1:1 /system-data/etc/rc1.d /var/lib/snapd/hostfs/etc/rc1.d rw,relatime master:28 - ext4 /dev/sda3 rw,data=ordered +2137 2111 1:1 /system-data/etc/rc2.d /var/lib/snapd/hostfs/etc/rc2.d rw,relatime master:29 - ext4 /dev/sda3 rw,data=ordered +2138 2111 1:1 /system-data/etc/rc3.d /var/lib/snapd/hostfs/etc/rc3.d rw,relatime master:30 - ext4 /dev/sda3 rw,data=ordered +2139 2111 1:1 /system-data/etc/rc4.d /var/lib/snapd/hostfs/etc/rc4.d rw,relatime master:31 - ext4 /dev/sda3 rw,data=ordered +2140 2111 1:1 /system-data/etc/rc5.d /var/lib/snapd/hostfs/etc/rc5.d rw,relatime master:32 - ext4 /dev/sda3 rw,data=ordered +2141 2111 1:1 /system-data/etc/rc6.d /var/lib/snapd/hostfs/etc/rc6.d rw,relatime master:33 - ext4 /dev/sda3 rw,data=ordered +2142 2111 1:1 /system-data/etc/rcS.d /var/lib/snapd/hostfs/etc/rcS.d rw,relatime master:34 - ext4 /dev/sda3 rw,data=ordered +2143 2111 1:1 /system-data/etc/rsyslog.d /var/lib/snapd/hostfs/etc/rsyslog.d rw,relatime master:35 - ext4 /dev/sda3 rw,data=ordered +2144 2111 1:1 /system-data/root/test-etc/shadow /var/lib/snapd/hostfs/etc/shadow ro,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2145 2111 1:1 /system-data/etc/ssh /var/lib/snapd/hostfs/etc/ssh rw,relatime master:36 - ext4 /dev/sda3 rw,data=ordered +2146 2111 1:1 /system-data/etc/sudoers.d /var/lib/snapd/hostfs/etc/sudoers.d rw,relatime master:37 - ext4 /dev/sda3 rw,data=ordered +2147 2111 1:1 /system-data/etc/sysctl.d /var/lib/snapd/hostfs/etc/sysctl.d rw,relatime master:38 - ext4 /dev/sda3 rw,data=ordered +2148 2111 1:1 /system-data/etc/systemd/logind.conf.d /var/lib/snapd/hostfs/etc/systemd/logind.conf.d rw,relatime master:39 - ext4 /dev/sda3 rw,data=ordered +2149 2111 1:1 /system-data/etc/systemd/network /var/lib/snapd/hostfs/etc/systemd/network rw,relatime master:40 - ext4 /dev/sda3 rw,data=ordered +2150 2111 1:1 /system-data/etc/systemd/system /var/lib/snapd/hostfs/etc/systemd/system rw,relatime master:41 - ext4 /dev/sda3 rw,data=ordered +2151 2150 1:1 /system-data/etc/systemd/system /var/lib/snapd/hostfs/etc/systemd/system rw,relatime master:42 - ext4 /dev/sda3 rw,data=ordered +2152 2111 1:1 /system-data/etc/systemd/system.conf.d /var/lib/snapd/hostfs/etc/systemd/system.conf.d rw,relatime master:43 - ext4 /dev/sda3 rw,data=ordered +2153 2111 1:1 /system-data/etc/systemd/timesyncd.conf /var/lib/snapd/hostfs/etc/systemd/timesyncd.conf rw,relatime master:44 - ext4 /dev/sda3 rw,data=ordered +2154 2111 1:1 /system-data/etc/systemd/user.conf.d /var/lib/snapd/hostfs/etc/systemd/user.conf.d rw,relatime master:45 - ext4 /dev/sda3 rw,data=ordered +2155 2111 1:1 /system-data/etc/udev/rules.d /var/lib/snapd/hostfs/etc/udev/rules.d rw,relatime master:46 - ext4 /dev/sda3 rw,data=ordered +2156 2111 1:1 /system-data/etc/update-motd.d /var/lib/snapd/hostfs/etc/update-motd.d rw,relatime master:47 - ext4 /dev/sda3 rw,data=ordered +2157 2111 1:1 /system-data/etc/writable /var/lib/snapd/hostfs/etc/writable rw,relatime master:48 - ext4 /dev/sda3 rw,data=ordered +2158 2111 1:1 /user-data /var/lib/snapd/hostfs/home rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2159 2111 0:1 /firmware /var/lib/snapd/hostfs/lib/firmware ro,relatime master:49 - squashfs /dev/loop1 ro +2160 2111 0:1 /modules /var/lib/snapd/hostfs/lib/modules ro,relatime master:50 - squashfs /dev/loop1 ro +2161 2111 2:6 / /var/lib/snapd/hostfs/media rw,relatime master:51 - tmpfs tmpfs rw +2162 2111 2:7 / /var/lib/snapd/hostfs/mnt rw,relatime master:52 - tmpfs tmpfs rw +2163 2111 1:1 /system-data/root /var/lib/snapd/hostfs/root rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2164 2111 2:5 / /var/lib/snapd/hostfs/run rw,nosuid,noexec,relatime master:56 - tmpfs tmpfs rw,mode=755 +2165 2164 2:10 / /var/lib/snapd/hostfs/run rw,nosuid,noexec,relatime master:55 - tmpfs tmpfs rw,size=VARIABLE,mode=755 +2166 2165 2:11 / /var/lib/snapd/hostfs/run/cgmanager/fs rw,relatime master:57 - tmpfs cgmfs rw,size=VARIABLE,mode=755 +2167 2165 2:12 / /var/lib/snapd/hostfs/run/lock rw,nosuid,nodev,noexec,relatime master:58 - tmpfs tmpfs rw,size=VARIABLE +2168 2165 2:10 /snapd/ns /var/lib/snapd/hostfs/run/snapd/ns rw,nosuid,noexec,relatime - tmpfs tmpfs rw,size=VARIABLE,mode=755 +2169 2165 2:13 / /var/lib/snapd/hostfs/run/user/0 rw,nosuid,nodev,relatime master:59 - tmpfs tmpfs rw,size=VARIABLE,mode=700 +2170 2111 1:1 /system-data/snap /var/lib/snapd/hostfs/snap rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2171 2170 0:2 / /var/lib/snapd/hostfs/snap/core/1 ro,nodev,relatime master:60 - squashfs /dev/loop2 ro +2172 2170 0:3 / /var/lib/snapd/hostfs/snap/core18/1 ro,nodev,relatime master:61 - squashfs /dev/loop3 ro +2173 2170 0:4 / /var/lib/snapd/hostfs/snap/pc-kernel/1 ro,nodev,relatime master:62 - squashfs /dev/loop4 ro +2174 2170 0:5 / /var/lib/snapd/hostfs/snap/pc/1 ro,nodev,relatime master:63 - squashfs /dev/loop5 ro +2175 2170 0:6 / /var/lib/snapd/hostfs/snap/test-snapd-mountinfo-core16/1 ro,nodev,relatime master:64 - squashfs /dev/loop6 ro +2176 2170 0:7 / /var/lib/snapd/hostfs/snap/test-snapd-mountinfo-core18/1 ro,nodev,relatime master:65 - squashfs /dev/loop7 ro +2177 2170 0:8 / /var/lib/snapd/hostfs/snap/test-snapd-rsync/1 ro,nodev,relatime master:66 - squashfs /dev/loop8 ro +2178 2111 2:31 / /var/lib/snapd/hostfs/tmp rw,relatime master:84 - tmpfs tmpfs rw +2179 2111 1:1 /system-data/var/cache/apparmor /var/lib/snapd/hostfs/var/cache/apparmor rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2180 2111 1:1 /system-data/var/cache/snapd /var/lib/snapd/hostfs/var/cache/snapd rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2181 2111 1:1 /system-data/var/lib/apparmor /var/lib/snapd/hostfs/var/lib/apparmor rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2182 2111 1:1 /system-data/var/lib/cloud /var/lib/snapd/hostfs/var/lib/cloud rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2183 2111 1:1 /system-data/var/lib/console-conf /var/lib/snapd/hostfs/var/lib/console-conf rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2184 2111 1:1 /system-data/var/lib/dbus /var/lib/snapd/hostfs/var/lib/dbus rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2185 2111 1:1 /system-data/var/lib/dhcp /var/lib/snapd/hostfs/var/lib/dhcp rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2186 2111 1:1 /system-data/var/lib/extrausers /var/lib/snapd/hostfs/var/lib/extrausers rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2187 2111 1:1 /system-data/var/lib/initramfs-tools /var/lib/snapd/hostfs/var/lib/initramfs-tools rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2188 2111 1:1 /system-data/var/lib/logrotate /var/lib/snapd/hostfs/var/lib/logrotate rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2189 2111 1:1 /system-data/var/lib/misc /var/lib/snapd/hostfs/var/lib/misc rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2190 2111 1:1 /system-data/var/lib/snapd /var/lib/snapd/hostfs/var/lib/snapd rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2191 2111 2:32 / /var/lib/snapd/hostfs/var/lib/sudo rw,relatime master:85 - tmpfs tmpfs rw,mode=700 +2192 2111 1:1 /system-data/var/lib/systemd/random-seed /var/lib/snapd/hostfs/var/lib/systemd/random-seed rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2193 2111 1:1 /system-data/var/lib/systemd/rfkill /var/lib/snapd/hostfs/var/lib/systemd/rfkill rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2194 2111 1:1 /system-data/var/lib/waagent /var/lib/snapd/hostfs/var/lib/waagent rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2195 2111 1:1 /system-data/var/log /var/lib/snapd/hostfs/var/log rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2196 2111 1:1 /system-data/var/snap /var/lib/snapd/hostfs/var/snap rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2197 2111 1:1 /system-data/var/tmp /var/lib/snapd/hostfs/var/tmp rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2198 2111 1:1 / /var/lib/snapd/hostfs/writable rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2199 2198 0:2 / /var/lib/snapd/hostfs/writable/system-data/snap/core/1 ro,nodev,relatime master:60 - squashfs /dev/loop2 ro +2200 2198 0:3 / /var/lib/snapd/hostfs/writable/system-data/snap/core18/1 ro,nodev,relatime master:61 - squashfs /dev/loop3 ro +2201 2198 0:4 / /var/lib/snapd/hostfs/writable/system-data/snap/pc-kernel/1 ro,nodev,relatime master:62 - squashfs /dev/loop4 ro +2202 2198 0:5 / /var/lib/snapd/hostfs/writable/system-data/snap/pc/1 ro,nodev,relatime master:63 - squashfs /dev/loop5 ro +2203 2198 0:6 / /var/lib/snapd/hostfs/writable/system-data/snap/test-snapd-mountinfo-core16/1 ro,nodev,relatime master:64 - squashfs /dev/loop6 ro +2204 2198 0:7 / /var/lib/snapd/hostfs/writable/system-data/snap/test-snapd-mountinfo-core18/1 ro,nodev,relatime master:65 - squashfs /dev/loop7 ro +2205 2198 0:8 / /var/lib/snapd/hostfs/writable/system-data/snap/test-snapd-rsync/1 ro,nodev,relatime master:66 - squashfs /dev/loop8 ro +2206 2001 2:32 / /var/lib/sudo rw,relatime master:85 - tmpfs tmpfs rw,mode=700 +2207 2001 1:1 /system-data/var/lib/systemd/random-seed /var/lib/systemd/random-seed rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2208 2001 1:1 /system-data/var/lib/systemd/rfkill /var/lib/systemd/rfkill rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2209 2001 1:1 /system-data/var/lib/waagent /var/lib/waagent rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2210 2001 1:1 /system-data/var/log /var/log rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2211 2001 1:1 /system-data/var/snap /var/snap rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2212 2001 1:1 /system-data/var/tmp /var/tmp rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2213 2001 1:1 / /writable rw,relatime master:15 - ext4 /dev/sda3 rw,data=ordered +2214 2213 0:2 / /writable/system-data/snap/core/1 ro,nodev,relatime master:60 - squashfs /dev/loop2 ro +2215 2213 0:3 / /writable/system-data/snap/core18/1 ro,nodev,relatime master:61 - squashfs /dev/loop3 ro +2216 2213 0:4 / /writable/system-data/snap/pc-kernel/1 ro,nodev,relatime master:62 - squashfs /dev/loop4 ro +2217 2213 0:5 / /writable/system-data/snap/pc/1 ro,nodev,relatime master:63 - squashfs /dev/loop5 ro +2218 2213 0:6 / /writable/system-data/snap/test-snapd-mountinfo-core16/1 ro,nodev,relatime master:64 - squashfs /dev/loop6 ro +2219 2213 0:7 / /writable/system-data/snap/test-snapd-mountinfo-core18/1 ro,nodev,relatime master:65 - squashfs /dev/loop7 ro +2220 2213 0:8 / /writable/system-data/snap/test-snapd-rsync/1 ro,nodev,relatime master:66 - squashfs /dev/loop8 ro diff --git a/tests/main/ubuntu-core-upgrade/task.yaml b/tests/main/ubuntu-core-upgrade/task.yaml index 4e80af8c89..af675d06f6 100644 --- a/tests/main/ubuntu-core-upgrade/task.yaml +++ b/tests/main/ubuntu-core-upgrade/task.yaml @@ -1,6 +1,6 @@ summary: Upgrade the core snap and revert a few times -systems: [ubuntu-core-16-*] +systems: [ubuntu-core-1*] # Start early as it takes a long time. priority: 100 @@ -24,15 +24,30 @@ restore: | snap remove core --revision=x3 prepare: | - snap list | awk "/^core / {print(\$3)}" > nextBoot + #shellcheck source=tests/lib/systems.sh + . "$TESTSLIB"/systems.sh + + TARGET_SNAP=core + if is_core18_system; then + TARGET_SNAP=core18 + fi + + snap list | awk "/^${TARGET_SNAP} / {print(\$3)}" > nextBoot snap install test-snapd-tools execute: | #shellcheck source=tests/lib/boot.sh . "$TESTSLIB"/boot.sh + #shellcheck source=tests/lib/systems.sh + . "$TESTSLIB"/systems.sh + + TARGET_SNAP=core + if is_core18_system; then + TARGET_SNAP=core18 + fi # FIXME Why it starting with snap_mode=try the first time? - # Perhaps because core is installed after seeding? Do we + # Perhaps because $TARGET_SNAP is installed after seeding? Do we # want that on pristine images? if [ "$SPREAD_REBOOT" != 0 ]; then echo "Waiting for snapd to clean snap_mode" @@ -41,12 +56,12 @@ execute: | done echo "Ensure the bootloader is correct after reboot" - test "$(bootenv snap_core)" = "core_$(cat nextBoot).snap" + test "$(bootenv snap_core)" = "${TARGET_SNAP}_$(cat nextBoot).snap" test "$(bootenv snap_try_core)" = "" test "$(bootenv snap_mode)" = "" fi - snap list | awk "/^core / {print(\$3)}" > prevBoot + snap list | awk "/^${TARGET_SNAP} / {print(\$3)}" > prevBoot # wait for ongoing change if there is one if [ -f curChg ] ; then @@ -56,10 +71,10 @@ execute: | case "$SPREAD_REBOOT" in - 0) cmd="snap install --dangerous /var/lib/snapd/snaps/core_$(cat prevBoot).snap" ;; - 1) cmd="snap revert core" ;; - 2) cmd="snap install --dangerous /var/lib/snapd/snaps/core_$(cat prevBoot).snap" ;; - 3) cmd="snap revert core" ;; + 0) cmd="snap install --dangerous /var/lib/snapd/snaps/${TARGET_SNAP}_$(cat prevBoot).snap" ;; + 1) cmd="snap revert $TARGET_SNAP" ;; + 2) cmd="snap install --dangerous /var/lib/snapd/snaps/${TARGET_SNAP}_$(cat prevBoot).snap" ;; + 3) cmd="snap revert $TARGET_SNAP" ;; 4) exit 0 ;; esac @@ -78,9 +93,9 @@ execute: | test-snapd-tools.echo hello | MATCH hello echo "Ensure the bootloader is correct before reboot" - readlink /snap/core/current > nextBoot + readlink "/snap/${TARGET_SNAP}/current" > nextBoot test "$(cat prevBoot)" != "$(cat nextBoot)" - test "$(bootenv snap_try_core)" = "core_$(cat nextBoot).snap" + test "$(bootenv snap_try_core)" = "${TARGET_SNAP}_$(cat nextBoot).snap" test "$(bootenv snap_mode)" = "try" echo "Ensure the device is scheduled for auto-reboot" diff --git a/tests/main/ubuntu-core-writablepaths/task.yaml b/tests/main/ubuntu-core-writablepaths/task.yaml index 0c6d1e8e9a..16bf5c4b10 100644 --- a/tests/main/ubuntu-core-writablepaths/task.yaml +++ b/tests/main/ubuntu-core-writablepaths/task.yaml @@ -1,6 +1,6 @@ summary: Ensure that the writable paths on the image are correct -systems: [ubuntu-core-16-*] +systems: [ubuntu-core-1*] execute: | echo "Ensure everything in writable-paths is actually writable" diff --git a/tests/regression/lp-1667385/task.yaml b/tests/regression/lp-1667385/task.yaml index 716c221ad4..e6c56755c5 100644 --- a/tests/regression/lp-1667385/task.yaml +++ b/tests/regression/lp-1667385/task.yaml @@ -5,7 +5,7 @@ details: | (e.g. from when the user installed it) should be preserved. # run on ubuntu-{14,16,18,20+} and ubuntu-core-16-* -systems: [ubuntu-1*, ubuntu-2*, ubuntu-3*, ubuntu-core-16-*] +systems: [ubuntu-1*, ubuntu-2*, ubuntu-3*, ubuntu-core-1*] environment: FLAG/jailmode: jailmode diff --git a/tests/regression/lp-1802581/task.yaml b/tests/regression/lp-1802581/task.yaml index eb10e281ea..38e51a13e3 100644 --- a/tests/regression/lp-1802581/task.yaml +++ b/tests/regression/lp-1802581/task.yaml @@ -17,7 +17,7 @@ description: | exporting the pin, would always run before the apparmor backend, which could now rely on the pin being exposed to userspace. -systems: [ubuntu-core-16-64] +systems: [ubuntu-core-1*-64] prepare: | # Core image that were created using spread will have a fake "gpio-pin". |
