diff options
| author | Pawel Stolowski <stolowski@gmail.com> | 2018-06-20 12:35:32 +0200 |
|---|---|---|
| committer | Pawel Stolowski <stolowski@gmail.com> | 2018-06-20 12:35:32 +0200 |
| commit | f31897ab9500ad0aba03d51362019091fb1a2b84 (patch) | |
| tree | 6b2d38d26ad3cc15f560093cfbced790967410f6 | |
| parent | 00ac0b391fbe9f0b3d8076a5e5811315ff6e9d2b (diff) | |
| parent | 82479957466e54232b8eb162f42667154e582ddb (diff) | |
Merge branch 'master' into self-connect-fixself-connect-fix
97 files changed, 1183 insertions, 646 deletions
diff --git a/asserts/device_asserts.go b/asserts/device_asserts.go index 4f2f7d7293..1feb83d69f 100644 --- a/asserts/device_asserts.go +++ b/asserts/device_asserts.go @@ -215,6 +215,7 @@ func assembleModel(assert assertionBase) (Assertion, error) { return nil, err } + // TODO parallel-install: verify if snap names are valid store names reqSnaps, err := checkStringList(assert.headers, "required-snaps") if err != nil { return nil, err diff --git a/boot/kernel_os.go b/boot/kernel_os.go index 9bb2bb43f5..d63a670082 100644 --- a/boot/kernel_os.go +++ b/boot/kernel_os.go @@ -109,7 +109,7 @@ func SetNextBoot(s *snap.Info) error { } if s.Type != snap.TypeOS && s.Type != snap.TypeKernel && s.Type != snap.TypeBase { - return fmt.Errorf("cannot set next boot to snap %q with type %q", s.Name(), s.Type) + return fmt.Errorf("cannot set next boot to snap %q with type %q", s.StoreName(), s.Type) } bootloader, err := partition.FindBootloader() @@ -155,8 +155,9 @@ func SetNextBoot(s *snap.Info) error { }) } -// KernelOsBaseRebootRequired returns whether a reboot is required to swith to the given OS or kernel snap. -func KernelOsBaseRebootRequired(s *snap.Info) bool { +// ChangeRequiresReboot returns whether a reboot is required to switch +// to the given OS, base or kernel snap. +func ChangeRequiresReboot(s *snap.Info) bool { if s.Type != snap.TypeKernel && s.Type != snap.TypeOS && s.Type != snap.TypeBase { return false } diff --git a/boot/kernel_os_test.go b/boot/kernel_os_test.go index a1bfac3593..a011ab9f0e 100644 --- a/boot/kernel_os_test.go +++ b/boot/kernel_os_test.go @@ -178,7 +178,7 @@ func (s *kernelOSSuite) TestSetNextBootForCore(c *C) { "snap_mode": "try", }) - c.Check(boot.KernelOsBaseRebootRequired(info), Equals, true) + c.Check(boot.ChangeRequiresReboot(info), Equals, true) } func (s *kernelOSSuite) TestSetNextBootWithBaseForCore(c *C) { @@ -198,7 +198,7 @@ func (s *kernelOSSuite) TestSetNextBootWithBaseForCore(c *C) { "snap_mode": "try", }) - c.Check(boot.KernelOsBaseRebootRequired(info), Equals, true) + c.Check(boot.ChangeRequiresReboot(info), Equals, true) } func (s *kernelOSSuite) TestSetNextBootForKernel(c *C) { @@ -220,11 +220,11 @@ func (s *kernelOSSuite) TestSetNextBootForKernel(c *C) { s.bootloader.BootVars["snap_kernel"] = "krnl_40.snap" s.bootloader.BootVars["snap_try_kernel"] = "krnl_42.snap" - c.Check(boot.KernelOsBaseRebootRequired(info), Equals, true) + c.Check(boot.ChangeRequiresReboot(info), Equals, true) // simulate good boot s.bootloader.BootVars["snap_kernel"] = "krnl_42.snap" - c.Check(boot.KernelOsBaseRebootRequired(info), Equals, false) + c.Check(boot.ChangeRequiresReboot(info), Equals, false) } func (s *kernelOSSuite) TestSetNextBootForKernelForTheSameKernel(c *C) { diff --git a/cmd/snap-update-ns/change.go b/cmd/snap-update-ns/change.go index 8587cdc27b..6e29137501 100644 --- a/cmd/snap-update-ns/change.go +++ b/cmd/snap-update-ns/change.go @@ -66,6 +66,18 @@ func (c Change) String() string { // changePerform is Change.Perform that can be mocked for testing. var changePerform func(*Change, *Secure) ([]*Change, error) +// mimicRequired provides information if an error warrants a writable mimic. +// +// The returned path is the location where a mimic should be constructed. +func mimicRequired(err error) (needsMimic bool, path string) { + switch err.(type) { + case *ReadOnlyFsError: + rofsErr := err.(*ReadOnlyFsError) + return true, rofsErr.Path + } + return false, "" +} + func (c *Change) createPath(path string, pokeHoles bool, sec *Secure) ([]*Change, error) { // If we've been asked to create a missing path, and the mount // entry uses the ignore-missing option, return an error. @@ -100,12 +112,12 @@ func (c *Change) createPath(path string, pokeHoles bool, sec *Secure) ([]*Change case "symlink": err = sec.MksymlinkAll(path, mode, uid, gid, c.Entry.XSnapdSymlink()) } - if err2, ok := err.(*ReadOnlyFsError); ok && pokeHoles { - // If the writing failed because the underlying file-system is read-only - // we can construct a writable mimic to fix that. - changes, err = createWritableMimic(err2.Path, path, sec) + if needsMimic, mimicPath := mimicRequired(err); needsMimic && pokeHoles { + // If the error can be recovered by using a writable mimic + // then construct one and try again. + changes, err = createWritableMimic(mimicPath, path, sec) if err != nil { - err = fmt.Errorf("cannot create writable mimic over %q: %s", err2.Path, err) + err = fmt.Errorf("cannot create writable mimic over %q: %s", mimicPath, err) } else { // Try once again. Note that we care *just* about the error. We have already // performed the hole poking and thus additional changes must be nil. diff --git a/cmd/snap/cmd_info.go b/cmd/snap/cmd_info.go index 821379aee0..3356931abd 100644 --- a/cmd/snap/cmd_info.go +++ b/cmd/snap/cmd_info.go @@ -136,7 +136,7 @@ func tryDirect(w io.Writer, path string, verbose bool) bool { return false } fmt.Fprintf(w, "path:\t%q\n", path) - fmt.Fprintf(w, "name:\t%s\n", info.Name()) + fmt.Fprintf(w, "name:\t%s\n", info.InstanceName()) fmt.Fprintf(w, "summary:\t%s\n", formatSummary(info.Summary())) var notes *Notes diff --git a/cmd/snap/cmd_run.go b/cmd/snap/cmd_run.go index d28e18aa1a..0006fd4d0a 100644 --- a/cmd/snap/cmd_run.go +++ b/cmd/snap/cmd_run.go @@ -679,21 +679,29 @@ func (x *cmdRun) runCmdUnderStrace(origCmd, env []string) error { func (x *cmdRun) runSnapConfine(info *snap.Info, securityTag, snapApp, hook string, args []string) error { snapConfine := filepath.Join(dirs.DistroLibExecDir, "snap-confine") - // if we re-exec, we must run the snap-confine from the core snap + // if we re-exec, we must run the snap-confine from the core/snapd snap // as well, if they get out of sync, havoc will happen if isReexeced() { - // run snap-confine from the core snap. that will work because - // snap-confine on the core snap is mostly statically linked - // (except libudev and libc) - snapConfine = filepath.Join(dirs.SnapMountDir, "core/current", dirs.CoreLibExecDir, "snap-confine") + // exe is something like /snap/{snapd,core}/123/usr/bin/snap + exe, err := osReadlink("/proc/self/exe") + if err != nil { + return err + } + // snapBase will be "/snap/{core,snapd}/$rev/" because + // the snap binary is always at $root/usr/bin/snap + snapBase := filepath.Clean(filepath.Join(filepath.Dir(exe), "..", "..")) + // Run snap-confine from the core/snapd snap. That + // will work because snap-confine on the core/snapd snap is + // mostly statically linked (except libudev and libc) + snapConfine = filepath.Join(snapBase, dirs.CoreLibExecDir, "snap-confine") } if !osutil.FileExists(snapConfine) { if hook != "" { - logger.Noticef("WARNING: skipping running hook %q of snap %q: missing snap-confine", hook, info.Name()) + logger.Noticef("WARNING: skipping running hook %q of snap %q: missing snap-confine", hook, info.InstanceName()) return nil } - return fmt.Errorf(i18n.G("missing snap-confine: try updating your snapd package")) + return fmt.Errorf(i18n.G("missing snap-confine: try updating your core/snapd package")) } if err := createUserDataDirs(info); err != nil { diff --git a/cmd/snap/cmd_run_test.go b/cmd/snap/cmd_run_test.go index d6323fad86..234076045a 100644 --- a/cmd/snap/cmd_run_test.go +++ b/cmd/snap/cmd_run_test.go @@ -94,7 +94,7 @@ func (s *SnapSuite) TestSnapRunWhenMissingConfine(c *check.C) { // and run it! // a regular run will fail _, err := snaprun.Parser().ParseArgs([]string{"run", "snapname.app", "--arg1", "arg2"}) - c.Assert(err, check.ErrorMatches, `.* your snapd package`) + c.Assert(err, check.ErrorMatches, `.* your core/snapd package`) // a hook run will not fail _, err = snaprun.Parser().ParseArgs([]string{"run", "--hook=configure", "snapname"}) c.Assert(err, check.IsNil) @@ -465,7 +465,7 @@ func (s *SnapSuite) TestSnapRunIsReexeced(c *check.C) { } func (s *SnapSuite) TestSnapRunAppIntegrationFromCore(c *check.C) { - defer mockSnapConfine(filepath.Join(dirs.SnapMountDir, "core", "current", dirs.CoreLibExecDir))() + defer mockSnapConfine(filepath.Join(dirs.SnapMountDir, "core", "111", dirs.CoreLibExecDir))() // mock installed snap snaptest.MockSnapCurrent(c, string(mockYaml), &snap.SideInfo{ @@ -494,9 +494,48 @@ func (s *SnapSuite) TestSnapRunAppIntegrationFromCore(c *check.C) { rest, err := snaprun.Parser().ParseArgs([]string{"run", "snapname.app", "--arg1", "arg2"}) c.Assert(err, check.IsNil) c.Assert(rest, check.DeepEquals, []string{"snapname.app", "--arg1", "arg2"}) - c.Check(execArg0, check.Equals, filepath.Join(dirs.SnapMountDir, "/core/current", dirs.CoreLibExecDir, "snap-confine")) + c.Check(execArg0, check.Equals, filepath.Join(dirs.SnapMountDir, "/core/111", dirs.CoreLibExecDir, "snap-confine")) c.Check(execArgs, check.DeepEquals, []string{ - filepath.Join(dirs.SnapMountDir, "/core/current", dirs.CoreLibExecDir, "snap-confine"), + filepath.Join(dirs.SnapMountDir, "/core/111", dirs.CoreLibExecDir, "snap-confine"), + "snap.snapname.app", + filepath.Join(dirs.CoreLibExecDir, "snap-exec"), + "snapname.app", "--arg1", "arg2"}) + c.Check(execEnv, testutil.Contains, "SNAP_REVISION=x2") +} + +func (s *SnapSuite) TestSnapRunAppIntegrationFromSnapd(c *check.C) { + defer mockSnapConfine(filepath.Join(dirs.SnapMountDir, "snapd", "222", dirs.CoreLibExecDir))() + + // mock installed snap + snaptest.MockSnapCurrent(c, string(mockYaml), &snap.SideInfo{ + Revision: snap.R("x2"), + }) + + // pretend to be running from snapd + restorer := snaprun.MockOsReadlink(func(string) (string, error) { + return filepath.Join(dirs.SnapMountDir, "snapd/222/usr/bin/snap"), nil + }) + defer restorer() + + // redirect exec + execArg0 := "" + execArgs := []string{} + execEnv := []string{} + restorer = snaprun.MockSyscallExec(func(arg0 string, args []string, envv []string) error { + execArg0 = arg0 + execArgs = args + execEnv = envv + return nil + }) + defer restorer() + + // and run it! + rest, err := snaprun.Parser().ParseArgs([]string{"run", "snapname.app", "--arg1", "arg2"}) + c.Assert(err, check.IsNil) + c.Assert(rest, check.DeepEquals, []string{"snapname.app", "--arg1", "arg2"}) + c.Check(execArg0, check.Equals, filepath.Join(dirs.SnapMountDir, "/snapd/222", dirs.CoreLibExecDir, "snap-confine")) + c.Check(execArgs, check.DeepEquals, []string{ + filepath.Join(dirs.SnapMountDir, "/snapd/222", dirs.CoreLibExecDir, "snap-confine"), "snap.snapname.app", filepath.Join(dirs.CoreLibExecDir, "snap-exec"), "snapname.app", "--arg1", "arg2"}) diff --git a/daemon/api.go b/daemon/api.go index 60622f9e89..d72d235ba1 100644 --- a/daemon/api.go +++ b/daemon/api.go @@ -768,9 +768,9 @@ func storeUpdates(c *Command, r *http.Request, user *auth.UserState) Response { func sendStorePackages(route *mux.Route, meta *Meta, found []*snap.Info) Response { results := make([]*json.RawMessage, 0, len(found)) for _, x := range found { - url, err := route.URL("name", x.Name()) + url, err := route.URL("name", x.InstanceName()) if err != nil { - logger.Noticef("Cannot build URL for snap %q revision %s: %v", x.Name(), x.Revision, err) + logger.Noticef("Cannot build URL for snap %q revision %s: %v", x.InstanceName(), x.Revision, err) continue } @@ -826,7 +826,7 @@ func getSnapsInfo(c *Command, r *http.Request, user *auth.UserState) Response { results := make([]*json.RawMessage, len(found)) for i, x := range found { - name := x.info.Name() + name := x.info.InstanceName() rev := x.info.Revision url, err := route.URL("name", name) @@ -1359,14 +1359,14 @@ func trySnap(c *Command, r *http.Request, user *auth.UserState, trydir string, f return BadRequest("cannot read snap info for %s: %s", trydir, err) } - tset, err := snapstateTryPath(st, info.Name(), trydir, flags) + tset, err := snapstateTryPath(st, info.InstanceName(), trydir, flags) if err != nil { return BadRequest("cannot try %s: %s", trydir, err) } - msg := fmt.Sprintf(i18n.G("Try %q snap from %s"), info.Name(), trydir) - chg := newChange(st, "try-snap", msg, []*state.TaskSet{tset}, []string{info.Name()}) - chg.Set("api-data", map[string]string{"snap-name": info.Name()}) + msg := fmt.Sprintf(i18n.G("Try %q snap from %s"), info.InstanceName(), trydir) + chg := newChange(st, "try-snap", msg, []*state.TaskSet{tset}, []string{info.InstanceName()}) + chg.Set("api-data", map[string]string{"snap-name": info.InstanceName()}) ensureStateSoon(st) @@ -1567,7 +1567,7 @@ out: if err != nil { return BadRequest("cannot read snap file: %v", err) } - snapName = info.Name() + snapName = info.InstanceName() sideInfo = &snap.SideInfo{RealName: snapName} } @@ -1576,6 +1576,7 @@ out: msg = fmt.Sprintf(i18n.G("Install %q snap from file %q"), snapName, origPath) } + // TODO parallel-install: pass instance key if needed tset, err := snapstateInstallPath(st, sideInfo, tempPath, "", flags) if err != nil { return InternalError("cannot install snap file: %v", err) @@ -1778,7 +1779,7 @@ func getLegacyConnections(c *Command, r *http.Request, user *auth.UserState) Res apps = append(apps, app.Name) } pj := plugJSON{ - Snap: plug.Snap.Name(), + Snap: plug.Snap.InstanceName(), Name: plug.Name, Interface: plug.Interface, Attrs: plug.Attrs, @@ -1795,7 +1796,7 @@ func getLegacyConnections(c *Command, r *http.Request, user *auth.UserState) Res } sj := slotJSON{ - Snap: slot.Snap.Name(), + Snap: slot.Snap.InstanceName(), Name: slot.Name, Interface: slot.Interface, Attrs: slot.Attrs, diff --git a/daemon/api_mock_test.go b/daemon/api_mock_test.go index 978518e492..b476b9deee 100644 --- a/daemon/api_mock_test.go +++ b/daemon/api_mock_test.go @@ -41,11 +41,11 @@ func (s *apiSuite) mockSnap(c *C, yamlText string) *snap.Info { defer st.Unlock() // Put a side info into the state - snapstate.Set(st, snapInfo.Name(), &snapstate.SnapState{ + snapstate.Set(st, snapInfo.InstanceName(), &snapstate.SnapState{ Active: true, Sequence: []*snap.SideInfo{ { - RealName: snapInfo.Name(), + RealName: snapInfo.StoreName(), Revision: snapInfo.Revision, SnapID: "ididid", }, diff --git a/daemon/snap.go b/daemon/snap.go index c49a2fca9d..368c848857 100644 --- a/daemon/snap.go +++ b/daemon/snap.go @@ -157,8 +157,8 @@ type bySnapApp []*snap.AppInfo func (a bySnapApp) Len() int { return len(a) } func (a bySnapApp) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a bySnapApp) Less(i, j int) bool { - iName := a[i].Snap.Name() - jName := a[j].Snap.Name() + iName := a[i].Snap.InstanceName() + jName := a[j].Snap.InstanceName() if iName == jName { return a[i].Name < a[j].Name } @@ -221,7 +221,7 @@ func appInfosFor(st *state.State, names []string, opts appInfoOptions) ([]*snap. found := make(map[string]bool) appInfos := make([]*snap.AppInfo, 0, len(requested)) for _, snp := range snaps { - snapName := snp.info.Name() + snapName := snp.info.InstanceName() apps := make([]*snap.AppInfo, 0, len(snp.info.Apps)) for _, app := range snp.info.Apps { if !opts.service || app.IsService() { @@ -272,7 +272,7 @@ func clientAppInfosFromSnapAppInfos(apps []*snap.AppInfo) []client.AppInfo { out := make([]client.AppInfo, len(apps)) for i, app := range apps { out[i] = client.AppInfo{ - Snap: app.Snap.Name(), + Snap: app.Snap.InstanceName(), Name: app.Name, CommonID: app.CommonID, } @@ -321,7 +321,7 @@ func mapLocal(about aboutSnap) *client.Snap { ID: localSnap.SnapID, InstallDate: localSnap.InstallDate(), InstalledSize: localSnap.Size, - Name: localSnap.Name(), + Name: localSnap.InstanceName(), Revision: localSnap.Revision, Status: status, Summary: localSnap.Summary(), @@ -382,7 +382,7 @@ func mapRemote(remoteSnap *snap.Info) *client.Snap { DownloadSize: remoteSnap.Size, Icon: snapIcon(remoteSnap), ID: remoteSnap.SnapID, - Name: remoteSnap.Name(), + Name: remoteSnap.InstanceName(), Revision: remoteSnap.Revision, Status: status, Summary: remoteSnap.Summary(), diff --git a/image/helpers.go b/image/helpers.go index 6542ad1a43..7f4ff67467 100644 --- a/image/helpers.go +++ b/image/helpers.go @@ -306,7 +306,7 @@ func FetchAndCheckSnapAssertions(snapPath string, info *snap.Info, f asserts.Fet } // cross checks - if err := snapasserts.CrossCheck(info.Name(), sha3_384, size, &info.SideInfo, db); err != nil { + if err := snapasserts.CrossCheck(info.InstanceName(), sha3_384, size, &info.SideInfo, db); err != nil { return nil, err } @@ -315,7 +315,7 @@ func FetchAndCheckSnapAssertions(snapPath string, info *snap.Info, f asserts.Fet "snap-id": info.SnapID, }) if err != nil { - return nil, fmt.Errorf("internal error: lost snap declaration for %q: %v", info.Name(), err) + return nil, fmt.Errorf("internal error: lost snap declaration for %q: %v", info.InstanceName(), err) } return a.(*asserts.SnapDeclaration), nil } diff --git a/image/image.go b/image/image.go index 8e12fdfa14..9ba3182b4e 100644 --- a/image/image.go +++ b/image/image.go @@ -63,7 +63,7 @@ type localInfos struct { func (li *localInfos) Name(pathOrName string) string { if info := li.pathToInfo[pathOrName]; info != nil { - return info.Name() + return info.InstanceName() } return pathOrName } @@ -101,7 +101,7 @@ func localSnaps(tsto *ToolingStore, opts *Options) (*localInfos, error) { } // local snap gets local revision info.Revision = snap.R(-1) - nameToPath[info.Name()] = snapName + nameToPath[info.InstanceName()] = snapName local[snapName] = info si, err := snapasserts.DeriveSideInfo(snapName, tsto) @@ -137,6 +137,8 @@ func Prepare(opts *Options) error { return err } + // TODO parallel-install: parallel installs should be blocked for now + local, err := localSnaps(tsto, opts) if err != nil { return err @@ -399,7 +401,7 @@ func bootstrapToRootDir(tsto *ToolingStore, model *asserts.Model, opts *Options, // set seed.yaml seedYaml.Snaps = append(seedYaml.Snaps, &snap.SeedSnap{ - Name: info.Name(), + Name: info.InstanceName(), SnapID: info.SnapID, // cross-ref Channel: info.Channel, File: filepath.Base(fn), diff --git a/image/image_test.go b/image/image_test.go index e6f7942c61..80bbeeb572 100644 --- a/image/image_test.go +++ b/image/image_test.go @@ -338,7 +338,7 @@ func infoFromSnapYaml(c *C, snapYaml string, rev snap.Revision) *snap.Info { c.Assert(err, IsNil) if !rev.Unset() { - info.SnapID = info.Name() + "-Id" + info.SnapID = info.InstanceName() + "-Id" info.Revision = rev } return info @@ -568,7 +568,7 @@ func (s *imageSuite) TestBootstrapToRootDirLocalCoreBrandKernel(c *C) { c.Check(osutil.FileExists(p), Equals, true) c.Check(seed.Snaps[i], DeepEquals, &snap.SeedSnap{ - Name: info.Name(), + Name: info.InstanceName(), SnapID: info.SnapID, File: fn, Unasserted: unasserted, @@ -761,7 +761,7 @@ func (s *imageSuite) TestBootstrapWithBase(c *C) { c.Check(osutil.FileExists(p), Equals, true) c.Check(seed.Snaps[i], DeepEquals, &snap.SeedSnap{ - Name: info.Name(), + Name: info.InstanceName(), SnapID: info.SnapID, File: fn, Unasserted: unasserted, @@ -949,7 +949,7 @@ func (s *imageSuite) TestBootstrapToRootDirLocalSnapsWithStoreAsserts(c *C) { c.Check(osutil.FileExists(p), Equals, true, Commentf("cannot find %s", p)) c.Check(seed.Snaps[i], DeepEquals, &snap.SeedSnap{ - Name: info.Name(), + Name: info.InstanceName(), SnapID: info.SnapID, File: fn, Unasserted: false, diff --git a/interfaces/apparmor/backend.go b/interfaces/apparmor/backend.go index 19fe157f88..4f20500b2e 100644 --- a/interfaces/apparmor/backend.go +++ b/interfaces/apparmor/backend.go @@ -176,16 +176,17 @@ func (b *Backend) Initialize() error { return nil } -// snapConfineFromCoreProfile returns the apparmor profile for snap-confine in the given core snap. -func snapConfineFromCoreProfile(coreInfo *snap.Info) (dir, glob string, content map[string]*osutil.FileState, err error) { +// snapConfineFromSnapProfile returns the apparmor profile for +// snap-confine in the given core/snapd snap. +func snapConfineFromSnapProfile(info *snap.Info) (dir, glob string, content map[string]*osutil.FileState, err error) { // Find the vanilla apparmor profile for snap-confine as present in the given core snap. // We must test the ".real" suffix first, this is a workaround for // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=858004 - vanillaProfilePath := filepath.Join(coreInfo.MountDir(), "/etc/apparmor.d/usr.lib.snapd.snap-confine.real") + vanillaProfilePath := filepath.Join(info.MountDir(), "/etc/apparmor.d/usr.lib.snapd.snap-confine.real") vanillaProfileText, err := ioutil.ReadFile(vanillaProfilePath) if os.IsNotExist(err) { - vanillaProfilePath = filepath.Join(coreInfo.MountDir(), "/etc/apparmor.d/usr.lib.snapd.snap-confine") + vanillaProfilePath = filepath.Join(info.MountDir(), "/etc/apparmor.d/usr.lib.snapd.snap-confine") vanillaProfileText, err = ioutil.ReadFile(vanillaProfilePath) } if err != nil { @@ -193,13 +194,20 @@ func snapConfineFromCoreProfile(coreInfo *snap.Info) (dir, glob string, content } // Replace the path to vanilla snap-confine with the path to the mounted snap-confine from core. - snapConfineInCore := filepath.Join(coreInfo.MountDir(), "usr/lib/snapd/snap-confine") + snapConfineInCore := filepath.Join(info.MountDir(), "usr/lib/snapd/snap-confine") patchedProfileText := bytes.Replace( vanillaProfileText, []byte("/usr/lib/snapd/snap-confine"), []byte(snapConfineInCore), -1) - // /snap/core/111/usr/lib/snapd/snap-confine -> snap.core.111.usr.lib.snapd.snap-confine - patchedProfileName := strings.Replace(snapConfineInCore[1:], "/", ".", -1) - // snap.core.111.usr.lib.snapd.snap-confine -> snap.core.*.usr.lib.snapd.snap-confine - patchedProfileGlob := strings.Replace(patchedProfileName, "."+coreInfo.Revision.String()+".", ".*.", 1) + + // We need to add a uniqe prefix that can never collide with a + // snap on the system. Using "snap-confine.*" is similar to + // "snap-update-ns.*" that is already used there + // + // So + // /snap/core/111/usr/lib/snapd/snap-confine + // becomes + // snap-confine.core.111 + patchedProfileName := fmt.Sprintf("snap-confine.%s.%s", info.InstanceName(), info.Revision) + patchedProfileGlob := fmt.Sprintf("snap-confine.%s.*", info.InstanceName()) // Return information for EnsureDirState that describes the re-exec profile for snap-confine. content = map[string]*osutil.FileState{ @@ -208,22 +216,23 @@ func snapConfineFromCoreProfile(coreInfo *snap.Info) (dir, glob string, content Mode: 0644, }, } - return dirs.SystemApparmorDir, patchedProfileGlob, content, nil + + return dirs.SnapAppArmorDir, patchedProfileGlob, content, nil } -// setupSnapConfineReexec will setup apparmor profiles on a classic -// system on the hosts /etc/apparmor.d directory. This is needed for -// running snap-confine from the core snap. +// setupSnapConfineReexec will setup apparmor profiles inside the host's +// /var/lib/snapd/apparmor/profiles directory. This is needed for +// running snap-confine from the core or snapd snap. // // Additionally it will cleanup stale apparmor profiles it created. -func setupSnapConfineReexec(coreInfo *snap.Info) error { +func setupSnapConfineReexec(info *snap.Info) error { err := os.MkdirAll(dirs.SnapConfineAppArmorDir, 0755) if err != nil { return fmt.Errorf("cannot create snap-confine policy directory: %s", err) } - dir, glob, content, err := snapConfineFromCoreProfile(coreInfo) - cache := dirs.SystemApparmorCacheDir + dir, glob, content, err := snapConfineFromSnapProfile(info) + cache := dirs.AppArmorCacheDir if err != nil { return fmt.Errorf("cannot compute snap-confine profile: %s", err) } @@ -277,7 +286,7 @@ func profileGlobs(snapName string) []string { // This method should be called after changing plug, slots, connections between // them or application present in the snap. func (b *Backend) Setup(snapInfo *snap.Info, opts interfaces.ConfinementOptions, repo *interfaces.Repository) error { - snapName := snapInfo.Name() + snapName := snapInfo.InstanceName() spec, err := repo.SnapSpecification(b.Name(), snapName) if err != nil { return fmt.Errorf("cannot obtain apparmor specification for snap %q: %s", snapName, err) @@ -294,6 +303,16 @@ func (b *Backend) Setup(snapInfo *snap.Info, opts interfaces.ConfinementOptions, logger.Noticef("cannot create host snap-confine apparmor configuration: %s", err) } } + + // Deal with the "snapd" snap - we do the setup slightly differently + // here because this will run both on classic and on Ubuntu Core 18 + // systems but /etc/apparmor.d is not writable on core18 systems + if snapName == "snapd" && release.AppArmorLevel() != release.NoAppArmor { + if err := setupSnapConfineReexec(snapInfo); err != nil { + logger.Noticef("cannot create host snap-confine apparmor configuration: %s", err) + } + } + // core on core devices is also special, the apparmor cache gets // confused too easy, especially at rollbacks, so we delete the cache. // See LP:#1460152 and @@ -318,7 +337,7 @@ func (b *Backend) Setup(snapInfo *snap.Info, opts interfaces.ConfinementOptions, return fmt.Errorf("cannot obtain expected security files for snap %q: %s", snapName, err) } dir := dirs.SnapAppArmorDir - globs := profileGlobs(snapInfo.Name()) + globs := profileGlobs(snapInfo.InstanceName()) cache := dirs.AppArmorCacheDir if err := os.MkdirAll(dir, 0755); err != nil { return fmt.Errorf("cannot create directory for apparmor profiles %q: %s", dir, err) @@ -397,7 +416,8 @@ func addUpdateNSProfile(snapInfo *snap.Info, opts interfaces.ConfinementOptions, policy := templatePattern.ReplaceAllStringFunc(updateNSTemplate, func(placeholder string) string { switch placeholder { case "###SNAP_NAME###": - return snapInfo.Name() + // TODO parallel-install: use of proper instance/store name + return snapInfo.InstanceName() case "###SNIPPETS###": return snippets } @@ -405,7 +425,7 @@ func addUpdateNSProfile(snapInfo *snap.Info, opts interfaces.ConfinementOptions, }) // Ensure that the snap-update-ns profile is on disk. - profileName := nsProfile(snapInfo.Name()) + profileName := nsProfile(snapInfo.InstanceName()) content[profileName] = &osutil.FileState{ Content: []byte(policy), Mode: 0644, diff --git a/interfaces/apparmor/backend_test.go b/interfaces/apparmor/backend_test.go index 3ef8db9fe0..0254d4e54c 100644 --- a/interfaces/apparmor/backend_test.go +++ b/interfaces/apparmor/backend_test.go @@ -25,7 +25,6 @@ import ( "os" "os/user" "path/filepath" - "strings" . "gopkg.in/check.v1" @@ -604,6 +603,11 @@ func (s *backendSuite) TestCombineSnippetsOpenSUSETumbleweedOldKernel(c *C) { const coreYaml = `name: core version: 1 +type: os +` + +const snapdYaml = `name: snapd +version: 1 ` func (s *backendSuite) writeVanillaSnapConfineProfile(c *C, coreInfo *snap.Info) { @@ -625,9 +629,9 @@ func (s *backendSuite) TestSnapConfineProfile(c *C) { coreInfo := snaptest.MockInfo(c, coreYaml, &snap.SideInfo{Revision: snap.R(111)}) s.writeVanillaSnapConfineProfile(c, coreInfo) // We expect to see the same profile, just anchored at a different directory. - expectedProfileDir := filepath.Join(dirs.GlobalRootDir, "/etc/apparmor.d") - expectedProfileName := strings.Replace(filepath.Join(coreInfo.MountDir(), "usr/lib/snapd/snap-confine")[1:], "/", ".", -1) - expectedProfileGlob := strings.Replace(expectedProfileName, "."+coreInfo.Revision.String()+".", ".*.", -1) + expectedProfileDir := filepath.Join(dirs.GlobalRootDir, "/var/lib/snapd/apparmor/profiles") + expectedProfileName := "snap-confine.core.111" + expectedProfileGlob := "snap-confine.core.*" expectedProfileText := fmt.Sprintf(`#include <tunables/global> %s/usr/lib/snapd/snap-confine (attach_disconnected) { # We run privileged, so be fanatical about what we include and don't use @@ -639,7 +643,42 @@ func (s *backendSuite) TestSnapConfineProfile(c *C) { c.Assert(expectedProfileName, testutil.Contains, coreInfo.Revision.String()) // Compute the profile and see if it matches. - dir, glob, content, err := apparmor.SnapConfineFromCoreProfile(coreInfo) + dir, glob, content, err := apparmor.SnapConfineFromSnapProfile(coreInfo) + c.Assert(err, IsNil) + c.Assert(dir, Equals, expectedProfileDir) + c.Assert(glob, Equals, expectedProfileGlob) + c.Assert(content, DeepEquals, map[string]*osutil.FileState{ + expectedProfileName: { + Content: []byte(expectedProfileText), + Mode: 0644, + }, + }) +} + +func (s *backendSuite) TestSnapConfineProfileFromSnapdSnap(c *C) { + restore := release.MockOnClassic(false) + defer restore() + dirs.SetRootDir(s.RootDir) + + snapdInfo := snaptest.MockInfo(c, snapdYaml, &snap.SideInfo{Revision: snap.R(222)}) + s.writeVanillaSnapConfineProfile(c, snapdInfo) + + // We expect to see the same profile, just anchored at a different directory. + expectedProfileDir := filepath.Join(dirs.GlobalRootDir, "/var/lib/snapd/apparmor/profiles") + expectedProfileName := "snap-confine.snapd.222" + expectedProfileGlob := "snap-confine.snapd.*" + expectedProfileText := fmt.Sprintf(`#include <tunables/global> +%s/usr/lib/snapd/snap-confine (attach_disconnected) { + # We run privileged, so be fanatical about what we include and don't use + # any abstractions + /etc/ld.so.cache r, +} +`, snapdInfo.MountDir()) + + c.Assert(expectedProfileName, testutil.Contains, snapdInfo.Revision.String()) + + // Compute the profile and see if it matches. + dir, glob, content, err := apparmor.SnapConfineFromSnapProfile(snapdInfo) c.Assert(err, IsNil) c.Assert(dir, Equals, expectedProfileDir) c.Assert(glob, Equals, expectedProfileGlob) @@ -660,8 +699,8 @@ func (s *backendSuite) TestSetupHostSnapConfineApparmorForReexecCleans(c *C) { coreInfo := snaptest.MockInfo(c, coreYaml, &snap.SideInfo{Revision: snap.R(111)}) s.writeVanillaSnapConfineProfile(c, coreInfo) - canaryName := strings.Replace(filepath.Join(dirs.SnapMountDir, "/core/2718/usr/lib/snapd/snap-confine"), "/", ".", -1)[1:] - canary := filepath.Join(dirs.SystemApparmorDir, canaryName) + canaryName := "snap-confine.core.2718" + canary := filepath.Join(dirs.SnapAppArmorDir, canaryName) err := os.MkdirAll(filepath.Dir(canary), 0755) c.Assert(err, IsNil) err = ioutil.WriteFile(canary, nil, 0644) @@ -689,10 +728,10 @@ func (s *backendSuite) TestSetupHostSnapConfineApparmorForReexecWritesNew(c *C) // for this snap-confine on core s.InstallSnap(c, interfaces.ConfinementOptions{}, coreYaml, 111) - newAA, err := filepath.Glob(filepath.Join(dirs.SystemApparmorDir, "*")) + newAA, err := filepath.Glob(filepath.Join(dirs.SnapAppArmorDir, "*")) c.Assert(err, IsNil) c.Assert(newAA, HasLen, 1) - c.Check(newAA[0], Matches, `.*/etc/apparmor.d/.*.snap.core.111.usr.lib.snapd.snap-confine`) + c.Check(newAA[0], Matches, `.*/var/lib/snapd/apparmor/profiles/snap-confine.core.111`) // This is the key, rewriting "/usr/lib/snapd/snap-confine c.Check(newAA[0], testutil.FileContains, "/snap/core/111/usr/lib/snapd/snap-confine (attach_disconnected) {") @@ -706,7 +745,7 @@ func (s *backendSuite) TestSetupHostSnapConfineApparmorForReexecWritesNew(c *C) `, dirs.SnapMountDir)) c.Check(s.parserCmd.Calls(), DeepEquals, [][]string{ - {"apparmor_parser", "--replace", "--write-cache", "-O", "no-expr-simplify", fmt.Sprintf("--cache-loc=%s", dirs.SystemApparmorCacheDir), "--quiet", newAA[0]}, + {"apparmor_parser", "--replace", "--write-cache", "-O", "no-expr-simplify", fmt.Sprintf("--cache-loc=%s", dirs.AppArmorCacheDir), "--quiet", newAA[0]}, }) // snap-confine directory was created diff --git a/interfaces/apparmor/export_test.go b/interfaces/apparmor/export_test.go index 791f56b4ff..c7ec573e15 100644 --- a/interfaces/apparmor/export_test.go +++ b/interfaces/apparmor/export_test.go @@ -26,9 +26,10 @@ import ( ) var ( - SnapConfineFromCoreProfile = snapConfineFromCoreProfile - ProfileGlobs = profileGlobs + ChopTree = chopTree NsProfile = nsProfile + ProfileGlobs = profileGlobs + SnapConfineFromSnapProfile = snapConfineFromSnapProfile ) // MockIsHomeUsingNFS mocks the real implementation of osutil.IsHomeUsingNFS diff --git a/interfaces/apparmor/spec.go b/interfaces/apparmor/spec.go index 0fde838356..b25ea81ad7 100644 --- a/interfaces/apparmor/spec.go +++ b/interfaces/apparmor/spec.go @@ -28,6 +28,7 @@ import ( "github.com/snapcore/snapd/interfaces" "github.com/snapcore/snapd/snap" + "github.com/snapcore/snapd/strutil" ) // Specification assists in collecting apparmor entries associated with an interface. @@ -173,6 +174,92 @@ func isProbablyPresent(path string) bool { return path == "/" || path == "/snap" || path == "/var" || path == "/var/snap" || path == "/tmp" || path == "/usr" || path == "/etc" } +// chopTree takes a path and depth and returns two lists of apparmor path expressions. +// +// The returned lists of expressions are referred to as left and right. +// +// The left list describes directories at depth up to and including +// assumedPrefixDepth and can be used to grant read permission to them (by +// appending the string "r, " to each element). This corresponds to an +// assumption about those directories being present in the system and being +// just traversed. Note that depth is defined as the number of directories +// traversed, including the root directory. +// +// The right list describes the remaining directories and the leaf entry +// (either file or directory) and is somewhat subtle. At each depth level the +// expression describes all the files and directories at that level. Coupled +// with the string "rw ," it can be used to create a rule that allows write +// access to any file therein, but not deeper. +// +// For example, with path: "/foo/bar/froz/baz" and depth 3 the result is: +// []string{"/", "/foo/", "/foo/bar/"} and []string{"/foo/bar/*", +// "/foo/bar/*/", "/foo/bar/froz/*", "/foo/bar/froz/*/"}. Coupled with the +// aforementioned constants this translates to the following apparmor rules: +// +// / r, +// /foo/ r, +// /foo/bar/ r, +// +// /foo/bar/* rw, +// /foo/bar/*/ rw, +// /foo/bar/froz/* rw, +// /foo/bar/froz/*/ rw, +// +// Those rules are useful for constructing the apparmor profile for a writable +// mimic that needs to be present in a specific directory (e.g. in +// /foo/bar/froz/baz) assuming that part of that directory already exists (e.g. +// /foo/bar/) but may need to be created earlier (e.g. in /foo/bar/froz). +// +// The mimic works by mounting a tmpfs over the mimicked directory and then +// re-creating empty files and directories as mount points for the subsequent +// bind-mount operations to latch onto. This is why the right list of +// expressions use * and */, this allows the expressions to capture files and +// directories at a specific path. +func chopTree(path string, assumedPrefixDepth int) (left, right []string, err error) { + // NOTE: This implementation works around a bug in apparmor parser: + // https://bugs.launchpad.net/apparmor/+bug/1769971 + // + // Due to the nature of apparmor path expressions we need to distinguish + // directories and files. The path expression denoting a directory must end + // with a trailing slash, that denoting a file must not. + // + // The iterator requires golang-clean paths which never have a trailing + // slash. We want to allow clean paths with an optional trailing slash. + isDir := strings.HasSuffix(path, "/") + cleanPath := filepath.Clean(path) + if (isDir && cleanPath+"/" != path) || (!isDir && cleanPath != path) { + return nil, nil, fmt.Errorf("cannot chop unclean path: %q", path) + } + + // Iterate over the path and construct left and right. + iter, _ := strutil.NewPathIterator(cleanPath) + for iter.Next() { + if iter.Depth() <= assumedPrefixDepth { + // The left hand side is the part that is assumed to exist. + // We mostly enumerate those directories as-is except for the final + // entry that we re-create the trailing slash if the original path + // was a "directory" path. + if iter.CurrentPath() == iter.Path() && isDir { + left = append(left, iter.CurrentPath()+"/") + } else { + left = append(left, iter.CurrentPath()) + } + } else { + // The right hand side rules should not allow creation of the root + // directory as that itself is meaningless. + if iter.Depth() > 1 { + // The right hand side replaces the final component with a "*" + // and "*/", meaning any file and any directory, respectively. + right = append(right, iter.CurrentBase()+"*") + right = append(right, iter.CurrentBase()+"*/") + } + } + } + // Note, for completeness we could append the full path but that is + // guaranteed to be captured by one of the two expressions above. + return left, right, nil +} + // WritableFileProfile writes a profile for snap-update-ns for making given file writable. func WritableFileProfile(buf *bytes.Buffer, path string) { if path == "/" { diff --git a/interfaces/apparmor/spec_test.go b/interfaces/apparmor/spec_test.go index f4fa9af953..51ebe176d8 100644 --- a/interfaces/apparmor/spec_test.go +++ b/interfaces/apparmor/spec_test.go @@ -179,6 +179,7 @@ func (s *specSuite) TestApparmorSnippetsFromLayout(c *C) { "# Layout path: /var/tmp\n/var/tmp{,/**} mrwklix,", }, }) + updateNS := s.spec.UpdateNS() profile0 := ` # Layout /etc/foo.conf: bind-file $SNAP/foo.conf mount options=(bind, rw) /snap/vanguard/42/foo.conf -> /etc/foo.conf, @@ -210,6 +211,8 @@ func (s *specSuite) TestApparmorSnippetsFromLayout(c *C) { /tmp/.snap/snap/ rw, /tmp/.snap/ rw, ` + c.Assert(updateNS[0], Equals, profile0) + profile1 := ` # Layout /usr/foo: bind $SNAP/usr/foo mount options=(rbind, rw) /snap/vanguard/42/usr/foo/ -> /usr/foo/, umount /usr/foo/, @@ -242,6 +245,8 @@ func (s *specSuite) TestApparmorSnippetsFromLayout(c *C) { /tmp/.snap/snap/ rw, /tmp/.snap/ rw, ` + c.Assert(updateNS[1], Equals, profile1) + profile2 := ` # Layout /var/cache/mylink: symlink $SNAP_DATA/link/target /var/cache/mylink rw, # Writable mimic /var/cache @@ -258,6 +263,8 @@ func (s *specSuite) TestApparmorSnippetsFromLayout(c *C) { /tmp/.snap/var/ rw, /tmp/.snap/ rw, ` + c.Assert(updateNS[2], Equals, profile2) + profile3 := ` # Layout /var/tmp: type tmpfs, mode: 01777 mount fstype=tmpfs tmpfs -> /var/tmp/, umount /var/tmp/, @@ -273,10 +280,79 @@ func (s *specSuite) TestApparmorSnippetsFromLayout(c *C) { /tmp/.snap/var/ rw, /tmp/.snap/ rw, ` - updateNS := s.spec.UpdateNS() - c.Assert(updateNS[0], Equals, profile0) - c.Assert(updateNS[1], Equals, profile1) - c.Assert(updateNS[2], Equals, profile2) c.Assert(updateNS[3], Equals, profile3) c.Assert(updateNS, DeepEquals, []string{profile0, profile1, profile2, profile3}) } + +func (s *specSuite) TestChopTree(c *C) { + for _, tc := range []struct { + p string // path + d int // depth + l, r []string // left and right path expressions + e string // error pattern, if non-empty + }{ + // Test case from the documentation of the function. + {p: "/foo/bar/froz/baz/", d: 3, // Assume first three directories exist + l: []string{"/", "/foo/", "/foo/bar/"}, + // Assume that /foo/bar/froz and beyond may be missing + r: []string{"/foo/bar/*", "/foo/bar/*/", "/foo/bar/froz/*", "/foo/bar/froz/*/"}}, + + // Exhaustive test cases for directory paths. + + {p: "/foo/bar/froz/", d: 0, // Assume that no directories exist (and '/' does not have 'w') + r: []string{"/*", "/*/", "/foo/*", "/foo/*/", "/foo/bar/*", "/foo/bar/*/"}}, + {p: "/foo/bar/froz/", d: 1, // Assume that the root directory exists + l: []string{"/"}, + r: []string{"/*", "/*/", "/foo/*", "/foo/*/", "/foo/bar/*", "/foo/bar/*/"}}, + {p: "/foo/bar/froz/", d: 2, // Assume that /foo/ exists. + l: []string{"/", "/foo/"}, + r: []string{"/foo/*", "/foo/*/", "/foo/bar/*", "/foo/bar/*/"}}, + {p: "/foo/bar/froz/", d: 3, // Assume that /foo/bar/ exists. + l: []string{"/", "/foo/", "/foo/bar/"}, + r: []string{"/foo/bar/*", "/foo/bar/*/"}}, + {p: "/foo/bar/froz/", d: 4, // Assume that /foo/bar/froz/ exists. + l: []string{"/", "/foo/", "/foo/bar/", "/foo/bar/froz/"}}, + + // Exhaustive test cases for file paths. + + {p: "/foo/bar/froz", d: 0, // Assume that no directories exist (and '/' does not have 'w') + r: []string{"/*", "/*/", "/foo/*", "/foo/*/", "/foo/bar/*", "/foo/bar/*/"}}, + {p: "/foo/bar/froz", d: 1, // Assume that the root directory exists + l: []string{"/"}, + r: []string{"/*", "/*/", "/foo/*", "/foo/*/", "/foo/bar/*", "/foo/bar/*/"}}, + {p: "/foo/bar/froz", d: 2, // Assume that /foo/ exists. + l: []string{"/", "/foo/"}, + r: []string{"/foo/*", "/foo/*/", "/foo/bar/*", "/foo/bar/*/"}}, + {p: "/foo/bar/froz", d: 3, // Assume that /foo/bar/ exists. + l: []string{"/", "/foo/", "/foo/bar/"}, + r: []string{"/foo/bar/*", "/foo/bar/*/"}}, + {p: "/foo/bar/froz", d: 4, // Assume that /foo/bar/froz exists. + l: []string{"/", "/foo/", "/foo/bar/", "/foo/bar/froz"}}, + + // Assumed prefix depth larger than actual path depth is harmless. + {p: "/foo/bar/froz/", d: 5, + l: []string{"/", "/foo/", "/foo/bar/", "/foo/bar/froz/"}}, + {p: "/foo/bar/froz", d: 5, + l: []string{"/", "/foo/", "/foo/bar/", "/foo/bar/froz"}}, + + // Unclean paths are not allowed. + {p: "/foo/../bar", d: 1, e: "cannot chop unclean path: .*"}, + {p: "/foo//bar", d: 1, e: "cannot chop unclean path: .*"}, + {p: "foo/../bar", d: 1, e: "cannot chop unclean path: .*"}, + {p: "foo//bar", d: 1, e: "cannot chop unclean path: .*"}, + + // https://twitter.com/thebox193/status/654457902208557056 + {p: "/foo/bar/froz/", d: -1, + r: []string{"/*", "/*/", "/foo/*", "/foo/*/", "/foo/bar/*", "/foo/bar/*/"}}, + } { + l, r, err := apparmor.ChopTree(tc.p, tc.d) + comment := Commentf("test case: %#v", tc) + if tc.e == "" { + c.Assert(err, IsNil, comment) + c.Assert(l, DeepEquals, tc.l, comment) + c.Assert(r, DeepEquals, tc.r, comment) + } else { + c.Assert(err, ErrorMatches, tc.e, comment) + } + } +} diff --git a/interfaces/apparmor/template_vars.go b/interfaces/apparmor/template_vars.go index 69cd064708..c27da2e891 100644 --- a/interfaces/apparmor/template_vars.go +++ b/interfaces/apparmor/template_vars.go @@ -31,7 +31,8 @@ import ( // apparmor template and by apparmor snippets. func templateVariables(info *snap.Info, securityTag string) string { var buf bytes.Buffer - fmt.Fprintf(&buf, "@{SNAP_NAME}=\"%s\"\n", info.Name()) + // TODO parallel-install: use of proper instance/store name + fmt.Fprintf(&buf, "@{SNAP_NAME}=\"%s\"\n", info.InstanceName()) fmt.Fprintf(&buf, "@{SNAP_REVISION}=\"%s\"\n", info.Revision) fmt.Fprintf(&buf, "@{PROFILE_DBUS}=\"%s\"\n", dbus.SafePath(securityTag)) diff --git a/interfaces/builtin/content.go b/interfaces/builtin/content.go index 33f6f29e80..16815706a6 100644 --- a/interfaces/builtin/content.go +++ b/interfaces/builtin/content.go @@ -174,7 +174,8 @@ func resolveSpecialVariable(path string, snapInfo *snap.Info) string { // inside the mount namespace snap-confine creates and there we will // always have a /snap directory available regardless if the system // we're running on supports this or not. - return strings.Replace(path, "$SNAP", filepath.Join(dirs.CoreSnapMountDir, snapInfo.Name(), snapInfo.Revision.String()), 1) + // TODO parallel-install: use of proper instance/store name + return strings.Replace(path, "$SNAP", filepath.Join(dirs.CoreSnapMountDir, snapInfo.InstanceName(), snapInfo.Revision.String()), 1) } if strings.HasPrefix(path, "$SNAP_DATA/") || path == "$SNAP_DATA" { return strings.Replace(path, "$SNAP_DATA", snapInfo.DataDir(), 1) @@ -183,7 +184,8 @@ func resolveSpecialVariable(path string, snapInfo *snap.Info) string { return strings.Replace(path, "$SNAP_COMMON", snapInfo.CommonDataDir(), 1) } // NOTE: assume $SNAP by default if nothing else is provided, for compatibility - return filepath.Join(filepath.Join(dirs.CoreSnapMountDir, snapInfo.Name(), snapInfo.Revision.String()), path) + // TODO parallel-install: use of proper instance/store name + return filepath.Join(filepath.Join(dirs.CoreSnapMountDir, snapInfo.InstanceName(), snapInfo.Revision.String()), path) } func sourceTarget(plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot, relSrc string) (string, string) { diff --git a/interfaces/builtin/content_test.go b/interfaces/builtin/content_test.go index e78ecd3375..abb72da567 100644 --- a/interfaces/builtin/content_test.go +++ b/interfaces/builtin/content_test.go @@ -569,6 +569,8 @@ slots: /var/snap/consumer/common/ rw, /var/snap/consumer/ rw, ` + c.Assert(updateNS[0], Equals, profile0) + 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/, umount /var/snap/consumer/common/import/write-data/, @@ -582,6 +584,8 @@ slots: /var/snap/consumer/common/ rw, /var/snap/consumer/ rw, ` + c.Assert(updateNS[1], Equals, profile1) + 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/, @@ -596,6 +600,8 @@ slots: /var/snap/consumer/common/ rw, /var/snap/consumer/ rw, ` + c.Assert(updateNS[2], Equals, profile2) + 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/, @@ -610,6 +616,8 @@ slots: /var/snap/consumer/common/ rw, /var/snap/consumer/ rw, ` + c.Assert(updateNS[3], Equals, profile3) + 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/, @@ -635,10 +643,6 @@ slots: /var/snap/consumer/common/ rw, /var/snap/consumer/ rw, ` - c.Assert(updateNS[0], Equals, profile0) - c.Assert(updateNS[1], Equals, profile1) - c.Assert(updateNS[2], Equals, profile2) - c.Assert(updateNS[3], Equals, profile3) c.Assert(updateNS[4], Equals, profile4) c.Assert(updateNS, DeepEquals, []string{profile0, profile1, profile2, profile3, profile4}) } diff --git a/interfaces/builtin/desktop.go b/interfaces/builtin/desktop.go index 09c7e75646..9e266a81b8 100644 --- a/interfaces/builtin/desktop.go +++ b/interfaces/builtin/desktop.go @@ -240,7 +240,8 @@ func (iface *desktopInterface) AppArmorConnectedPlug(spec *apparmor.Specificatio // Allow mounting document portal var buf bytes.Buffer fmt.Fprintf(&buf, " # Mount the document portal\n") - fmt.Fprintf(&buf, " mount options=(bind) /run/user/[0-9]*/doc/by-app/snap.%s/ -> /run/user/[0-9]*/doc/,\n", plug.Snap().Name()) + // TODO parallel-install: use of proper instance/store name + fmt.Fprintf(&buf, " mount options=(bind) /run/user/[0-9]*/doc/by-app/snap.%s/ -> /run/user/[0-9]*/doc/,\n", plug.Snap().InstanceName()) fmt.Fprintf(&buf, " umount /run/user/[0-9]*/doc/,\n\n") spec.AddUpdateNS(buf.String()) @@ -265,7 +266,7 @@ func (iface *desktopInterface) AppArmorConnectedPlug(spec *apparmor.Specificatio } func (iface *desktopInterface) MountConnectedPlug(spec *mount.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { - appId := "snap." + plug.Snap().Name() + appId := "snap." + plug.Snap().InstanceName() spec.AddUserMountEntry(osutil.MountEntry{ Name: "$XDG_RUNTIME_DIR/doc/by-app/" + appId, Dir: "$XDG_RUNTIME_DIR/doc", diff --git a/interfaces/builtin/export_test.go b/interfaces/builtin/export_test.go index 0efc5ce9b7..1626bc848a 100644 --- a/interfaces/builtin/export_test.go +++ b/interfaces/builtin/export_test.go @@ -66,7 +66,7 @@ func MockPlug(c *C, yaml string, si *snap.SideInfo, plugName string) *snap.PlugI if plugInfo, ok := info.Plugs[plugName]; ok { return plugInfo } - panic(fmt.Sprintf("cannot find plug %q in snap %q", plugName, info.Name())) + panic(fmt.Sprintf("cannot find plug %q in snap %q", plugName, info.InstanceName())) } func MockSlot(c *C, yaml string, si *snap.SideInfo, slotName string) *snap.SlotInfo { @@ -74,7 +74,7 @@ func MockSlot(c *C, yaml string, si *snap.SideInfo, slotName string) *snap.SlotI if slotInfo, ok := info.Slots[slotName]; ok { return slotInfo } - panic(fmt.Sprintf("cannot find slot %q in snap %q", slotName, info.Name())) + panic(fmt.Sprintf("cannot find slot %q in snap %q", slotName, info.InstanceName())) } func MockConnectedPlug(c *C, yaml string, si *snap.SideInfo, plugName string) (*interfaces.ConnectedPlug, *snap.PlugInfo) { @@ -82,7 +82,7 @@ func MockConnectedPlug(c *C, yaml string, si *snap.SideInfo, plugName string) (* if plugInfo, ok := info.Plugs[plugName]; ok { return interfaces.NewConnectedPlug(plugInfo, nil), plugInfo } - panic(fmt.Sprintf("cannot find plug %q in snap %q", plugName, info.Name())) + panic(fmt.Sprintf("cannot find plug %q in snap %q", plugName, info.InstanceName())) } func MockConnectedSlot(c *C, yaml string, si *snap.SideInfo, slotName string) (*interfaces.ConnectedSlot, *snap.SlotInfo) { @@ -90,7 +90,7 @@ func MockConnectedSlot(c *C, yaml string, si *snap.SideInfo, slotName string) (* if slotInfo, ok := info.Slots[slotName]; ok { return interfaces.NewConnectedSlot(slotInfo, nil), slotInfo } - panic(fmt.Sprintf("cannot find slot %q in snap %q", slotName, info.Name())) + panic(fmt.Sprintf("cannot find slot %q in snap %q", slotName, info.InstanceName())) } func MockOsGetenv(mock func(string) string) (restore func()) { diff --git a/interfaces/builtin/gpio.go b/interfaces/builtin/gpio.go index 9b9fdfc3d3..980a52aea7 100644 --- a/interfaces/builtin/gpio.go +++ b/interfaces/builtin/gpio.go @@ -108,7 +108,7 @@ func (iface *gpioInterface) SystemdConnectedSlot(spec *systemd.Specification, pl return err } - serviceName := interfaces.InterfaceServiceName(slot.Snap().Name(), fmt.Sprintf("gpio-%d", gpioNum)) + serviceName := interfaces.InterfaceServiceName(slot.Snap().InstanceName(), fmt.Sprintf("gpio-%d", gpioNum)) service := &systemd.Service{ Type: "oneshot", RemainAfterExit: true, diff --git a/interfaces/builtin/spi.go b/interfaces/builtin/spi.go index c37b1f29a8..db238c5675 100644 --- a/interfaces/builtin/spi.go +++ b/interfaces/builtin/spi.go @@ -73,7 +73,7 @@ func (iface *spiInterface) BeforePrepareSlot(slot *snap.SlotInfo) error { if err := sanitizeSlotReservedForOSOrGadget(iface, slot); err != nil { return err } - _, err := iface.path(&interfaces.SlotRef{Snap: slot.Snap.Name(), Name: slot.Name}, slot) + _, err := iface.path(&interfaces.SlotRef{Snap: slot.Snap.InstanceName(), Name: slot.Name}, slot) return err } diff --git a/interfaces/builtin/thumbnailer_service.go b/interfaces/builtin/thumbnailer_service.go index a15622613b..53111fa9f6 100644 --- a/interfaces/builtin/thumbnailer_service.go +++ b/interfaces/builtin/thumbnailer_service.go @@ -127,7 +127,8 @@ func (iface *thumbnailerServiceInterface) AppArmorPermanentSlot(spec *apparmor.S func (iface *thumbnailerServiceInterface) AppArmorConnectedSlot(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { snippet := thumbnailerServiceConnectedSlotAppArmor old := "###PLUG_SNAP_NAME###" - new := plug.Snap().Name() + // TODO parallel-install: use of proper instance/store name + new := plug.Snap().InstanceName() snippet = strings.Replace(snippet, old, new, -1) old = "###PLUG_SECURITY_TAGS###" diff --git a/interfaces/builtin/ubuntu_download_manager.go b/interfaces/builtin/ubuntu_download_manager.go index c184c0dd83..b44cd0c021 100644 --- a/interfaces/builtin/ubuntu_download_manager.go +++ b/interfaces/builtin/ubuntu_download_manager.go @@ -230,7 +230,8 @@ func (iface *ubuntuDownloadManagerInterface) AppArmorConnectedSlot(spec *apparmo new := plugAppLabelExpr(plug) snippet := strings.Replace(downloadConnectedSlotAppArmor, old, new, -1) old = "###PLUG_NAME###" - new = plug.Snap().Name() + // TODO parallel-install: use of proper instance/store name + new = plug.Snap().InstanceName() snippet = strings.Replace(snippet, old, new, -1) spec.AddSnippet(snippet) return nil diff --git a/interfaces/builtin/unity7.go b/interfaces/builtin/unity7.go index 9e31dd9191..fd28fe9303 100644 --- a/interfaces/builtin/unity7.go +++ b/interfaces/builtin/unity7.go @@ -639,7 +639,8 @@ func (iface *unity7Interface) AppArmorConnectedPlug(spec *apparmor.Specification // but we don't care about that here because the rule above already // does that) to '_'. Since we know that the desktop filename starts // with the snap name, perform this conversion on the snap name. - new := strings.Replace(plug.Snap().Name(), "-", "_", -1) + // TODO parallel-install: use of proper instance/store name + new := strings.Replace(plug.Snap().InstanceName(), "-", "_", -1) old := "###UNITY_SNAP_NAME###" snippet := strings.Replace(unity7ConnectedPlugAppArmor, old, new, -1) spec.AddSnippet(snippet) diff --git a/interfaces/builtin/utils.go b/interfaces/builtin/utils.go index 4b60cb3126..fd7a849af7 100644 --- a/interfaces/builtin/utils.go +++ b/interfaces/builtin/utils.go @@ -40,7 +40,8 @@ const UsbMaxInterfaces = 32 // - "snap.$snap.*" if all apps are bound to the slot func appLabelExpr(apps map[string]*snap.AppInfo, snap *snap.Info) string { var buf bytes.Buffer - fmt.Fprintf(&buf, `"snap.%s.`, snap.Name()) + // TODO parallel-install: use of proper instance/store name + fmt.Fprintf(&buf, `"snap.%s.`, snap.InstanceName()) if len(apps) == 1 { for appName := range apps { buf.WriteString(appName) diff --git a/interfaces/builtin/utils_test.go b/interfaces/builtin/utils_test.go index 0a032c0e75..aceaaa0dd8 100644 --- a/interfaces/builtin/utils_test.go +++ b/interfaces/builtin/utils_test.go @@ -79,7 +79,7 @@ func MockConnectedPlug(c *C, yaml string, si *snap.SideInfo, plugName string) (* if plugInfo, ok := info.Plugs[plugName]; ok { return interfaces.NewConnectedPlug(plugInfo, nil), plugInfo } - panic(fmt.Sprintf("cannot find plug %q in snap %q", plugName, info.Name())) + panic(fmt.Sprintf("cannot find plug %q in snap %q", plugName, info.InstanceName())) } func MockConnectedSlot(c *C, yaml string, si *snap.SideInfo, slotName string) (*interfaces.ConnectedSlot, *snap.SlotInfo) { @@ -87,5 +87,5 @@ func MockConnectedSlot(c *C, yaml string, si *snap.SideInfo, slotName string) (* if slotInfo, ok := info.Slots[slotName]; ok { return interfaces.NewConnectedSlot(slotInfo, nil), slotInfo } - panic(fmt.Sprintf("cannot find slot %q in snap %q", slotName, info.Name())) + panic(fmt.Sprintf("cannot find slot %q in snap %q", slotName, info.InstanceName())) } diff --git a/interfaces/builtin/wayland.go b/interfaces/builtin/wayland.go index dff8886388..6b2711eeba 100644 --- a/interfaces/builtin/wayland.go +++ b/interfaces/builtin/wayland.go @@ -128,7 +128,8 @@ func (iface *waylandInterface) AppArmorConnectedPlug(spec *apparmor.Specificatio func (iface *waylandInterface) AppArmorConnectedSlot(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { if !release.OnClassic { old := "###PLUG_SECURITY_TAGS###" - new := "snap." + plug.Snap().Name() // forms the snap-specific subdirectory name of /run/user/*/ used for XDG_RUNTIME_DIR + // TODO parallel-install: use of proper instance/store name + new := "snap." + plug.Snap().InstanceName() // forms the snap-specific subdirectory name of /run/user/*/ used for XDG_RUNTIME_DIR snippet := strings.Replace(waylandConnectedSlotAppArmor, old, new, -1) spec.AddSnippet(snippet) } diff --git a/interfaces/connection.go b/interfaces/connection.go index 362cc7a389..9990672b00 100644 --- a/interfaces/connection.go +++ b/interfaces/connection.go @@ -151,7 +151,7 @@ func (plug *ConnectedPlug) SecurityTags() []string { // StaticAttr returns a static attribute with the given key, or error if attribute doesn't exist. func (plug *ConnectedPlug) StaticAttr(key string, val interface{}) error { - return getAttribute(plug.Snap().Name(), plug.Interface(), plug.staticAttrs, nil, key, val) + return getAttribute(plug.Snap().InstanceName(), plug.Interface(), plug.staticAttrs, nil, key, val) } // StaticAttrs returns all static attributes. @@ -168,7 +168,7 @@ func (plug *ConnectedPlug) DynamicAttrs() map[string]interface{} { // attribute if dynamic one doesn't exist. Error is returned if neither dynamic nor static // attribute exist. func (plug *ConnectedPlug) Attr(key string, val interface{}) error { - return getAttribute(plug.Snap().Name(), plug.Interface(), plug.staticAttrs, plug.dynamicAttrs, key, val) + return getAttribute(plug.Snap().InstanceName(), plug.Interface(), plug.staticAttrs, plug.dynamicAttrs, key, val) } func (plug *ConnectedPlug) Lookup(path string) (interface{}, bool) { @@ -189,7 +189,7 @@ func (plug *ConnectedPlug) SetAttr(key string, value interface{}) error { // Ref returns the PlugRef for this plug. func (plug *ConnectedPlug) Ref() *PlugRef { - return &PlugRef{Snap: plug.Snap().Name(), Name: plug.Name()} + return &PlugRef{Snap: plug.Snap().InstanceName(), Name: plug.Name()} } // Interface returns the name of the interface for this slot. @@ -224,7 +224,7 @@ func (slot *ConnectedSlot) SecurityTags() []string { // StaticAttr returns a static attribute with the given key, or error if attribute doesn't exist. func (slot *ConnectedSlot) StaticAttr(key string, val interface{}) error { - return getAttribute(slot.Snap().Name(), slot.Interface(), slot.staticAttrs, nil, key, val) + return getAttribute(slot.Snap().InstanceName(), slot.Interface(), slot.staticAttrs, nil, key, val) } // StaticAttrs returns all static attributes. @@ -241,7 +241,7 @@ func (slot *ConnectedSlot) DynamicAttrs() map[string]interface{} { // attribute if dynamic one doesn't exist. Error is returned if neither dynamic nor static // attribute exist. func (slot *ConnectedSlot) Attr(key string, val interface{}) error { - return getAttribute(slot.Snap().Name(), slot.Interface(), slot.staticAttrs, slot.dynamicAttrs, key, val) + return getAttribute(slot.Snap().InstanceName(), slot.Interface(), slot.staticAttrs, slot.dynamicAttrs, key, val) } func (slot *ConnectedSlot) Lookup(path string) (interface{}, bool) { @@ -262,7 +262,7 @@ func (slot *ConnectedSlot) SetAttr(key string, value interface{}) error { // Ref returns the SlotRef for this slot. func (slot *ConnectedSlot) Ref() *SlotRef { - return &SlotRef{Snap: slot.Snap().Name(), Name: slot.Name()} + return &SlotRef{Snap: slot.Snap().InstanceName(), Name: slot.Name()} } // Interface returns the name of the interface for this connection. diff --git a/interfaces/core.go b/interfaces/core.go index 81b9568687..9efffd78a1 100644 --- a/interfaces/core.go +++ b/interfaces/core.go @@ -31,7 +31,7 @@ import ( func BeforePreparePlug(iface Interface, plugInfo *snap.PlugInfo) error { if iface.Name() != plugInfo.Interface { return fmt.Errorf("cannot sanitize plug %q (interface %q) using interface %q", - PlugRef{Snap: plugInfo.Snap.Name(), Name: plugInfo.Name}, plugInfo.Interface, iface.Name()) + PlugRef{Snap: plugInfo.Snap.InstanceName(), Name: plugInfo.Name}, plugInfo.Interface, iface.Name()) } var err error if iface, ok := iface.(PlugSanitizer); ok { @@ -55,7 +55,7 @@ func (ref PlugRef) String() string { func BeforePrepareSlot(iface Interface, slotInfo *snap.SlotInfo) error { if iface.Name() != slotInfo.Interface { return fmt.Errorf("cannot sanitize slot %q (interface %q) using interface %q", - SlotRef{Snap: slotInfo.Snap.Name(), Name: slotInfo.Name}, slotInfo.Interface, iface.Name()) + SlotRef{Snap: slotInfo.Snap.InstanceName(), Name: slotInfo.Name}, slotInfo.Interface, iface.Name()) } var err error if iface, ok := iface.(SlotSanitizer); ok { @@ -100,8 +100,8 @@ type ConnRef struct { // NewConnRef creates a connection reference for given plug and slot func NewConnRef(plug *snap.PlugInfo, slot *snap.SlotInfo) *ConnRef { return &ConnRef{ - PlugRef: PlugRef{Snap: plug.Snap.Name(), Name: plug.Name}, - SlotRef: SlotRef{Snap: slot.Snap.Name(), Name: slot.Name}, + PlugRef: PlugRef{Snap: plug.Snap.InstanceName(), Name: plug.Name}, + SlotRef: SlotRef{Snap: slot.Snap.InstanceName(), Name: slot.Name}, } } diff --git a/interfaces/dbus/backend.go b/interfaces/dbus/backend.go index 08477438e1..f59e61b75a 100644 --- a/interfaces/dbus/backend.go +++ b/interfaces/dbus/backend.go @@ -78,7 +78,7 @@ func setupDbusServiceForUserd(snapInfo *snap.Info) error { // // DBus has no concept of a complain mode so confinment type is ignored. func (b *Backend) Setup(snapInfo *snap.Info, opts interfaces.ConfinementOptions, repo *interfaces.Repository) error { - snapName := snapInfo.Name() + snapName := snapInfo.InstanceName() // Get the snippets that apply to this snap spec, err := repo.SnapSpecification(b.Name(), snapName) if err != nil { diff --git a/interfaces/ifacetest/backendtest.go b/interfaces/ifacetest/backendtest.go index 091e5635b9..3aa33417e6 100644 --- a/interfaces/ifacetest/backendtest.go +++ b/interfaces/ifacetest/backendtest.go @@ -162,7 +162,7 @@ func (s *BackendSuite) UpdateSnap(c *C, oldSnapInfo *snap.Info, opts interfaces. newSnapInfo := snaptest.MockInfo(c, snapYaml, &snap.SideInfo{ Revision: snap.R(revision), }) - c.Assert(newSnapInfo.Name(), Equals, oldSnapInfo.Name()) + c.Assert(newSnapInfo.InstanceName(), Equals, oldSnapInfo.InstanceName()) s.removePlugsSlots(c, oldSnapInfo) s.addPlugsSlots(c, newSnapInfo) err := s.Backend.Setup(newSnapInfo, opts, s.Repo) @@ -172,7 +172,7 @@ func (s *BackendSuite) UpdateSnap(c *C, oldSnapInfo *snap.Info, opts interfaces. // RemoveSnap "removes" an "installed" snap. func (s *BackendSuite) RemoveSnap(c *C, snapInfo *snap.Info) { - err := s.Backend.Remove(snapInfo.Name()) + err := s.Backend.Remove(snapInfo.InstanceName()) c.Assert(err, IsNil) s.removePlugsSlots(c, snapInfo) } @@ -189,12 +189,12 @@ func (s *BackendSuite) addPlugsSlots(c *C, snapInfo *snap.Info) { } func (s *BackendSuite) removePlugsSlots(c *C, snapInfo *snap.Info) { - for _, plug := range s.Repo.Plugs(snapInfo.Name()) { - err := s.Repo.RemovePlug(plug.Snap.Name(), plug.Name) + for _, plug := range s.Repo.Plugs(snapInfo.InstanceName()) { + err := s.Repo.RemovePlug(plug.Snap.InstanceName(), plug.Name) c.Assert(err, IsNil) } - for _, slot := range s.Repo.Slots(snapInfo.Name()) { - err := s.Repo.RemoveSlot(slot.Snap.Name(), slot.Name) + for _, slot := range s.Repo.Slots(snapInfo.InstanceName()) { + err := s.Repo.RemoveSlot(slot.Snap.InstanceName(), slot.Name) c.Assert(err, IsNil) } } diff --git a/interfaces/json.go b/interfaces/json.go index bc9dce12d5..aceeda2741 100644 --- a/interfaces/json.go +++ b/interfaces/json.go @@ -59,7 +59,7 @@ func (info *Info) MarshalJSON() ([]byte, error) { plugs := make([]*plugJSON, 0, len(info.Plugs)) for _, plug := range info.Plugs { plugs = append(plugs, &plugJSON{ - Snap: plug.Snap.Name(), + Snap: plug.Snap.InstanceName(), Name: plug.Name, Attrs: plug.Attrs, Label: plug.Label, @@ -68,7 +68,7 @@ func (info *Info) MarshalJSON() ([]byte, error) { slots := make([]*slotJSON, 0, len(info.Slots)) for _, slot := range info.Slots { slots = append(slots, &slotJSON{ - Snap: slot.Snap.Name(), + Snap: slot.Snap.InstanceName(), Name: slot.Name, Attrs: slot.Attrs, Label: slot.Label, diff --git a/interfaces/kmod/backend.go b/interfaces/kmod/backend.go index 3896b561ff..5a01fc0e95 100644 --- a/interfaces/kmod/backend.go +++ b/interfaces/kmod/backend.go @@ -67,7 +67,7 @@ func (b *Backend) Name() interfaces.SecuritySystem { // // If the method fails it should be re-tried (with a sensible strategy) by the caller. func (b *Backend) Setup(snapInfo *snap.Info, confinement interfaces.ConfinementOptions, repo *interfaces.Repository) error { - snapName := snapInfo.Name() + snapName := snapInfo.InstanceName() // Get the snippets that apply to this snap spec, err := repo.SnapSpecification(b.Name(), snapName) if err != nil { @@ -121,7 +121,7 @@ func deriveContent(spec *Specification, snapInfo *snap.Info) (map[string]*osutil buffer.WriteString(module) buffer.WriteRune('\n') } - content[fmt.Sprintf("%s.conf", snap.SecurityTag(snapInfo.Name()))] = &osutil.FileState{ + content[fmt.Sprintf("%s.conf", snap.SecurityTag(snapInfo.InstanceName()))] = &osutil.FileState{ Content: buffer.Bytes(), Mode: 0644, } diff --git a/interfaces/mount/backend.go b/interfaces/mount/backend.go index 34cbccc211..7d18b0ce4a 100644 --- a/interfaces/mount/backend.go +++ b/interfaces/mount/backend.go @@ -56,7 +56,7 @@ func (b *Backend) Name() interfaces.SecuritySystem { // Setup creates mount mount profile files specific to a given snap. func (b *Backend) Setup(snapInfo *snap.Info, confinement interfaces.ConfinementOptions, repo *interfaces.Repository) error { // Record all changes to the mount system for this snap. - snapName := snapInfo.Name() + snapName := snapInfo.InstanceName() spec, err := repo.SnapSpecification(b.Name(), snapName) if err != nil { return fmt.Errorf("cannot obtain mount security snippets for snap %q: %s", snapName, err) @@ -107,7 +107,7 @@ func addMountProfile(content map[string]*osutil.FileState, fname string, entries // deriveContent computes .fstab tables based on requests made to the specification. func deriveContent(spec *Specification, snapInfo *snap.Info) map[string]*osutil.FileState { content := make(map[string]*osutil.FileState, 2) - snapName := snapInfo.Name() + snapName := snapInfo.InstanceName() // Add the per-snap fstab file. // This file is read by snap-update-ns in the global pass. addMountProfile(content, fmt.Sprintf("snap.%s.fstab", snapName), spec.MountEntries()) diff --git a/interfaces/repo.go b/interfaces/repo.go index 48172c7cce..5a6741847f 100644 --- a/interfaces/repo.go +++ b/interfaces/repo.go @@ -262,7 +262,7 @@ func (r *Repository) AddPlug(plug *snap.PlugInfo) error { r.m.Lock() defer r.m.Unlock() - snapName := plug.Snap.Name() + snapName := plug.Snap.InstanceName() // Reject snaps with invalid names if err := snap.ValidateName(snapName); err != nil { @@ -357,7 +357,7 @@ func (r *Repository) AddSlot(slot *snap.SlotInfo) error { r.m.Lock() defer r.m.Unlock() - snapName := slot.Snap.Name() + snapName := slot.Snap.InstanceName() // Reject snaps with invalid names if err := snap.ValidateName(snapName); err != nil { @@ -601,12 +601,12 @@ func (r *Repository) Connect(ref *ConnRef, plugDynamicAttrs, slotDynamicAttrs ma if policyCheck != nil { if i, ok := iface.(plugValidator); ok { if err := i.BeforeConnectPlug(cplug); err != nil { - return nil, fmt.Errorf("cannot connect plug %q of snap %q: %s", plug.Name, plug.Snap.Name(), err) + return nil, fmt.Errorf("cannot connect plug %q of snap %q: %s", plug.Name, plug.Snap.InstanceName(), err) } } if i, ok := iface.(slotValidator); ok { if err := i.BeforeConnectSlot(cslot); err != nil { - return nil, fmt.Errorf("cannot connect slot %q of snap %q: %s", slot.Name, slot.Snap.Name(), err) + return nil, fmt.Errorf("cannot connect slot %q of snap %q: %s", slot.Name, slot.Snap.InstanceName(), err) } } @@ -890,7 +890,7 @@ func (r *Repository) AddSnap(snapInfo *snap.Info) error { r.m.Lock() defer r.m.Unlock() - snapName := snapInfo.Name() + snapName := snapInfo.InstanceName() if r.plugs[snapName] != nil || r.slots[snapName] != nil { return fmt.Errorf("cannot register interfaces for snap %q more than once", snapName) @@ -980,7 +980,7 @@ func (r *Repository) DisconnectSnap(snapName string) ([]string, error) { result := make([]string, 0, len(seen)) for info := range seen { - result = append(result, info.Name()) + result = append(result, info.InstanceName()) } sort.Strings(result) return result, nil diff --git a/interfaces/repo_test.go b/interfaces/repo_test.go index 8946306ba6..2102f6c216 100644 --- a/interfaces/repo_test.go +++ b/interfaces/repo_test.go @@ -217,7 +217,7 @@ func (s *RepositorySuite) TestAddPlug(c *C) { err := s.testRepo.AddPlug(s.plug) c.Assert(err, IsNil) c.Assert(s.testRepo.AllPlugs(""), HasLen, 1) - c.Assert(s.testRepo.Plug(s.plug.Snap.Name(), s.plug.Name), DeepEquals, s.plug) + c.Assert(s.testRepo.Plug(s.plug.Snap.InstanceName(), s.plug.Name), DeepEquals, s.plug) } func (s *RepositorySuite) TestAddPlugClashingPlug(c *C) { @@ -226,7 +226,7 @@ func (s *RepositorySuite) TestAddPlugClashingPlug(c *C) { err = s.testRepo.AddPlug(s.plug) c.Assert(err, ErrorMatches, `snap "consumer" has plugs conflicting on name "plug"`) c.Assert(s.testRepo.AllPlugs(""), HasLen, 1) - c.Assert(s.testRepo.Plug(s.plug.Snap.Name(), s.plug.Name), DeepEquals, s.plug) + c.Assert(s.testRepo.Plug(s.plug.Snap.InstanceName(), s.plug.Name), DeepEquals, s.plug) } func (s *RepositorySuite) TestAddPlugClashingSlot(c *C) { @@ -246,7 +246,7 @@ func (s *RepositorySuite) TestAddPlugClashingSlot(c *C) { err = s.testRepo.AddPlug(plug) c.Assert(err, ErrorMatches, `snap "snap" has plug and slot conflicting on name "clashing"`) c.Assert(s.testRepo.AllSlots(""), HasLen, 1) - c.Assert(s.testRepo.Slot(slot.Snap.Name(), slot.Name), DeepEquals, slot) + c.Assert(s.testRepo.Slot(slot.Snap.InstanceName(), slot.Name), DeepEquals, slot) } func (s *RepositorySuite) TestAddPlugFailsWithInvalidSnapName(c *C) { @@ -282,8 +282,8 @@ func (s *RepositorySuite) TestAddPlugFailsWithUnknownInterface(c *C) { func (s *RepositorySuite) TestPlug(c *C) { err := s.testRepo.AddPlug(s.plug) c.Assert(err, IsNil) - c.Assert(s.emptyRepo.Plug(s.plug.Snap.Name(), s.plug.Name), IsNil) - c.Assert(s.testRepo.Plug(s.plug.Snap.Name(), s.plug.Name), DeepEquals, s.plug) + c.Assert(s.emptyRepo.Plug(s.plug.Snap.InstanceName(), s.plug.Name), IsNil) + c.Assert(s.testRepo.Plug(s.plug.Snap.InstanceName(), s.plug.Name), DeepEquals, s.plug) } func (s *RepositorySuite) TestPlugSearch(c *C) { @@ -316,13 +316,13 @@ plugs: func (s *RepositorySuite) TestRemovePlugSucceedsWhenPlugExistsAndDisconnected(c *C) { err := s.testRepo.AddPlug(s.plug) c.Assert(err, IsNil) - err = s.testRepo.RemovePlug(s.plug.Snap.Name(), s.plug.Name) + err = s.testRepo.RemovePlug(s.plug.Snap.InstanceName(), s.plug.Name) c.Assert(err, IsNil) c.Assert(s.testRepo.AllPlugs(""), HasLen, 0) } func (s *RepositorySuite) TestRemovePlugFailsWhenPlugDoesntExist(c *C) { - err := s.emptyRepo.RemovePlug(s.plug.Snap.Name(), s.plug.Name) + err := s.emptyRepo.RemovePlug(s.plug.Snap.InstanceName(), s.plug.Name) c.Assert(err, ErrorMatches, `cannot remove plug "plug" from snap "consumer", no such plug`) } @@ -335,10 +335,10 @@ func (s *RepositorySuite) TestRemovePlugFailsWhenPlugIsConnected(c *C) { _, err = s.testRepo.Connect(connRef, nil, nil, nil) c.Assert(err, IsNil) // Removing a plug used by a slot returns an appropriate error - err = s.testRepo.RemovePlug(s.plug.Snap.Name(), s.plug.Name) + err = s.testRepo.RemovePlug(s.plug.Snap.InstanceName(), s.plug.Name) c.Assert(err, ErrorMatches, `cannot remove plug "plug" from snap "consumer", it is still connected`) // The plug is still there - slot := s.testRepo.Plug(s.plug.Snap.Name(), s.plug.Name) + slot := s.testRepo.Plug(s.plug.Snap.InstanceName(), s.plug.Name) c.Assert(slot, Not(IsNil)) } @@ -477,12 +477,12 @@ slots: func (s *RepositorySuite) TestSlotSucceedsWhenSlotExists(c *C) { err := s.testRepo.AddSlot(s.slot) c.Assert(err, IsNil) - slot := s.testRepo.Slot(s.slot.Snap.Name(), s.slot.Name) + slot := s.testRepo.Slot(s.slot.Snap.InstanceName(), s.slot.Name) c.Assert(slot, DeepEquals, s.slot) } func (s *RepositorySuite) TestSlotFailsWhenSlotDoesntExist(c *C) { - slot := s.testRepo.Slot(s.slot.Snap.Name(), s.slot.Name) + slot := s.testRepo.Slot(s.slot.Snap.InstanceName(), s.slot.Name) c.Assert(slot, IsNil) } @@ -541,13 +541,13 @@ func (s *RepositorySuite) TestAddSlotClashingPlug(c *C) { err = s.testRepo.AddSlot(slot) c.Assert(err, ErrorMatches, `snap "snap" has plug and slot conflicting on name "clashing"`) c.Assert(s.testRepo.AllPlugs(""), HasLen, 1) - c.Assert(s.testRepo.Plug(plug.Snap.Name(), plug.Name), DeepEquals, plug) + c.Assert(s.testRepo.Plug(plug.Snap.InstanceName(), plug.Name), DeepEquals, plug) } func (s *RepositorySuite) TestAddSlotStoresCorrectData(c *C) { err := s.testRepo.AddSlot(s.slot) c.Assert(err, IsNil) - slot := s.testRepo.Slot(s.slot.Snap.Name(), s.slot.Name) + slot := s.testRepo.Slot(s.slot.Snap.InstanceName(), s.slot.Name) // The added slot has the same data c.Assert(slot, DeepEquals, s.slot) } @@ -558,16 +558,16 @@ func (s *RepositorySuite) TestRemoveSlotSuccedsWhenSlotExistsAndDisconnected(c * err := s.testRepo.AddSlot(s.slot) c.Assert(err, IsNil) // Removing a vacant slot simply works - err = s.testRepo.RemoveSlot(s.slot.Snap.Name(), s.slot.Name) + err = s.testRepo.RemoveSlot(s.slot.Snap.InstanceName(), s.slot.Name) c.Assert(err, IsNil) // The slot is gone now - slot := s.testRepo.Slot(s.slot.Snap.Name(), s.slot.Name) + slot := s.testRepo.Slot(s.slot.Snap.InstanceName(), s.slot.Name) c.Assert(slot, IsNil) } func (s *RepositorySuite) TestRemoveSlotFailsWhenSlotDoesntExist(c *C) { // Removing a slot that doesn't exist returns an appropriate error - err := s.testRepo.RemoveSlot(s.slot.Snap.Name(), s.slot.Name) + err := s.testRepo.RemoveSlot(s.slot.Snap.InstanceName(), s.slot.Name) c.Assert(err, Not(IsNil)) c.Assert(err, ErrorMatches, `cannot remove slot "slot" from snap "producer", no such slot`) } @@ -581,10 +581,10 @@ func (s *RepositorySuite) TestRemoveSlotFailsWhenSlotIsConnected(c *C) { _, err = s.testRepo.Connect(connRef, nil, nil, nil) c.Assert(err, IsNil) // Removing a slot occupied by a plug returns an appropriate error - err = s.testRepo.RemoveSlot(s.slot.Snap.Name(), s.slot.Name) + err = s.testRepo.RemoveSlot(s.slot.Snap.InstanceName(), s.slot.Name) c.Assert(err, ErrorMatches, `cannot remove slot "slot" from snap "producer", it is still connected`) // The slot is still there - slot := s.testRepo.Slot(s.slot.Snap.Name(), s.slot.Name) + slot := s.testRepo.Slot(s.slot.Snap.InstanceName(), s.slot.Name) c.Assert(slot, Not(IsNil)) } @@ -1149,10 +1149,10 @@ func (s *RepositorySuite) TestConnectSucceeds(c *C) { // Disconnect fails if any argument is empty func (s *RepositorySuite) TestDisconnectFailsOnEmptyArgs(c *C) { - err1 := s.testRepo.Disconnect(s.plug.Snap.Name(), s.plug.Name, s.slot.Snap.Name(), "") - err2 := s.testRepo.Disconnect(s.plug.Snap.Name(), s.plug.Name, "", s.slot.Name) - err3 := s.testRepo.Disconnect(s.plug.Snap.Name(), "", s.slot.Snap.Name(), s.slot.Name) - err4 := s.testRepo.Disconnect("", s.plug.Name, s.slot.Snap.Name(), s.slot.Name) + err1 := s.testRepo.Disconnect(s.plug.Snap.InstanceName(), s.plug.Name, s.slot.Snap.InstanceName(), "") + err2 := s.testRepo.Disconnect(s.plug.Snap.InstanceName(), s.plug.Name, "", s.slot.Name) + err3 := s.testRepo.Disconnect(s.plug.Snap.InstanceName(), "", s.slot.Snap.InstanceName(), s.slot.Name) + err4 := s.testRepo.Disconnect("", s.plug.Name, s.slot.Snap.InstanceName(), s.slot.Name) c.Assert(err1, ErrorMatches, `cannot disconnect, slot name is empty`) c.Assert(err2, ErrorMatches, `cannot disconnect, slot snap name is empty`) c.Assert(err3, ErrorMatches, `cannot disconnect, plug name is empty`) @@ -1162,14 +1162,14 @@ func (s *RepositorySuite) TestDisconnectFailsOnEmptyArgs(c *C) { // Disconnect fails if plug doesn't exist func (s *RepositorySuite) TestDisconnectFailsWithoutPlug(c *C) { c.Assert(s.testRepo.AddSlot(s.slot), IsNil) - err := s.testRepo.Disconnect(s.plug.Snap.Name(), s.plug.Name, s.slot.Snap.Name(), s.slot.Name) + err := s.testRepo.Disconnect(s.plug.Snap.InstanceName(), s.plug.Name, s.slot.Snap.InstanceName(), s.slot.Name) c.Assert(err, ErrorMatches, `snap "consumer" has no plug named "plug"`) } // Disconnect fails if slot doesn't exist func (s *RepositorySuite) TestDisconnectFailsWithutSlot(c *C) { c.Assert(s.testRepo.AddPlug(s.plug), IsNil) - err := s.testRepo.Disconnect(s.plug.Snap.Name(), s.plug.Name, s.slot.Snap.Name(), s.slot.Name) + err := s.testRepo.Disconnect(s.plug.Snap.InstanceName(), s.plug.Name, s.slot.Snap.InstanceName(), s.slot.Name) c.Assert(err, ErrorMatches, `snap "producer" has no slot named "slot"`) } @@ -1177,7 +1177,7 @@ func (s *RepositorySuite) TestDisconnectFailsWithutSlot(c *C) { func (s *RepositorySuite) TestDisconnectFailsWhenNotConnected(c *C) { c.Assert(s.testRepo.AddPlug(s.plug), IsNil) c.Assert(s.testRepo.AddSlot(s.slot), IsNil) - err := s.testRepo.Disconnect(s.plug.Snap.Name(), s.plug.Name, s.slot.Snap.Name(), s.slot.Name) + err := s.testRepo.Disconnect(s.plug.Snap.InstanceName(), s.plug.Name, s.slot.Snap.InstanceName(), s.slot.Name) c.Assert(err, ErrorMatches, `cannot disconnect consumer:plug from producer:slot, it is not connected`) } @@ -1189,7 +1189,7 @@ func (s *RepositorySuite) TestDisconnectSucceeds(c *C) { c.Assert(err, IsNil) _, err = s.testRepo.Connect(NewConnRef(s.plug, s.slot), nil, nil, nil) c.Assert(err, IsNil) - err = s.testRepo.Disconnect(s.plug.Snap.Name(), s.plug.Name, s.slot.Snap.Name(), s.slot.Name) + err = s.testRepo.Disconnect(s.plug.Snap.InstanceName(), s.plug.Name, s.slot.Snap.InstanceName(), s.slot.Name) c.Assert(err, IsNil) c.Assert(s.testRepo.Interfaces(), DeepEquals, &Interfaces{ Plugs: []*snap.PlugInfo{s.plug}, @@ -1207,14 +1207,14 @@ func (s *RepositorySuite) TestConnectedFailsWithEmptySnapName(c *C) { // Connected fails if plug or slot name is empty func (s *RepositorySuite) TestConnectedFailsWithEmptyPlugSlotName(c *C) { - _, err := s.testRepo.Connected(s.plug.Snap.Name(), "") + _, err := s.testRepo.Connected(s.plug.Snap.InstanceName(), "") c.Check(err, ErrorMatches, "plug or slot name is empty") } // Connected fails if plug or slot doesn't exist func (s *RepositorySuite) TestConnectedFailsWithoutPlugOrSlot(c *C) { - _, err1 := s.testRepo.Connected(s.plug.Snap.Name(), s.plug.Name) - _, err2 := s.testRepo.Connected(s.slot.Snap.Name(), s.slot.Name) + _, err1 := s.testRepo.Connected(s.plug.Snap.InstanceName(), s.plug.Name) + _, err2 := s.testRepo.Connected(s.slot.Snap.InstanceName(), s.slot.Name) c.Check(err1, ErrorMatches, `snap "consumer" has no plug or slot named "plug"`) c.Check(err2, ErrorMatches, `snap "producer" has no plug or slot named "slot"`) } @@ -1226,11 +1226,11 @@ func (s *RepositorySuite) TestConnectedFindsConnections(c *C) { _, err := s.testRepo.Connect(NewConnRef(s.plug, s.slot), nil, nil, nil) c.Assert(err, IsNil) - conns, err := s.testRepo.Connected(s.plug.Snap.Name(), s.plug.Name) + conns, err := s.testRepo.Connected(s.plug.Snap.InstanceName(), s.plug.Name) c.Assert(err, IsNil) c.Check(conns, DeepEquals, []*ConnRef{NewConnRef(s.plug, s.slot)}) - conns, err = s.testRepo.Connected(s.slot.Snap.Name(), s.slot.Name) + conns, err = s.testRepo.Connected(s.slot.Snap.InstanceName(), s.slot.Name) c.Assert(err, IsNil) c.Check(conns, DeepEquals, []*ConnRef{NewConnRef(s.plug, s.slot)}) } @@ -1259,11 +1259,11 @@ func (s *RepositorySuite) TestConnections(c *C) { _, err := s.testRepo.Connect(NewConnRef(s.plug, s.slot), nil, nil, nil) c.Assert(err, IsNil) - conns, err := s.testRepo.Connections(s.plug.Snap.Name()) + conns, err := s.testRepo.Connections(s.plug.Snap.InstanceName()) c.Assert(err, IsNil) c.Check(conns, DeepEquals, []*ConnRef{NewConnRef(s.plug, s.slot)}) - conns, err = s.testRepo.Connections(s.slot.Snap.Name()) + conns, err = s.testRepo.Connections(s.slot.Snap.InstanceName()) c.Assert(err, IsNil) c.Check(conns, DeepEquals, []*ConnRef{NewConnRef(s.plug, s.slot)}) @@ -1306,7 +1306,7 @@ func (s *RepositorySuite) TestInterfacesSmokeTest(c *C) { Connections: []*ConnRef{NewConnRef(s.plug, s.slot)}, }) // After disconnecting the connections become empty - err = s.testRepo.Disconnect(s.plug.Snap.Name(), s.plug.Name, s.slot.Snap.Name(), s.slot.Name) + err = s.testRepo.Disconnect(s.plug.Snap.InstanceName(), s.plug.Name, s.slot.Snap.InstanceName(), s.slot.Name) c.Assert(err, IsNil) ifaces = s.testRepo.Interfaces() c.Assert(ifaces, DeepEquals, &Interfaces{ @@ -1348,11 +1348,11 @@ func (s *RepositorySuite) TestSnapSpecification(c *C) { c.Assert(repo.AddSlot(s.slot), IsNil) // Snaps should get static security now - spec, err := repo.SnapSpecification(testSecurity, s.plug.Snap.Name()) + spec, err := repo.SnapSpecification(testSecurity, s.plug.Snap.InstanceName()) c.Assert(err, IsNil) c.Check(spec.(*ifacetest.Specification).Snippets, DeepEquals, []string{"static plug snippet"}) - spec, err = repo.SnapSpecification(testSecurity, s.slot.Snap.Name()) + spec, err = repo.SnapSpecification(testSecurity, s.slot.Snap.InstanceName()) c.Assert(err, IsNil) c.Check(spec.(*ifacetest.Specification).Snippets, DeepEquals, []string{"static slot snippet"}) @@ -1362,14 +1362,14 @@ func (s *RepositorySuite) TestSnapSpecification(c *C) { c.Assert(err, IsNil) // Snaps should get static and connection-specific security now - spec, err = repo.SnapSpecification(testSecurity, s.plug.Snap.Name()) + spec, err = repo.SnapSpecification(testSecurity, s.plug.Snap.InstanceName()) c.Assert(err, IsNil) c.Check(spec.(*ifacetest.Specification).Snippets, DeepEquals, []string{ "static plug snippet", "connection-specific plug snippet", }) - spec, err = repo.SnapSpecification(testSecurity, s.slot.Snap.Name()) + spec, err = repo.SnapSpecification(testSecurity, s.slot.Snap.InstanceName()) c.Assert(err, IsNil) c.Check(spec.(*ifacetest.Specification).Snippets, DeepEquals, []string{ "static slot snippet", @@ -1399,11 +1399,11 @@ func (s *RepositorySuite) TestSnapSpecificationFailureWithConnectionSnippets(c * _, err := repo.Connect(connRef, nil, nil, nil) c.Assert(err, IsNil) - spec, err := repo.SnapSpecification(testSecurity, s.plug.Snap.Name()) + spec, err := repo.SnapSpecification(testSecurity, s.plug.Snap.InstanceName()) c.Assert(err, ErrorMatches, "cannot compute snippet for consumer") c.Assert(spec, IsNil) - spec, err = repo.SnapSpecification(testSecurity, s.slot.Snap.Name()) + spec, err = repo.SnapSpecification(testSecurity, s.slot.Snap.InstanceName()) c.Assert(err, ErrorMatches, "cannot compute snippet for provider") c.Assert(spec, IsNil) } @@ -1429,11 +1429,11 @@ func (s *RepositorySuite) TestSnapSpecificationFailureWithPermanentSnippets(c *C _, err := repo.Connect(connRef, nil, nil, nil) c.Assert(err, IsNil) - spec, err := repo.SnapSpecification(testSecurity, s.plug.Snap.Name()) + spec, err := repo.SnapSpecification(testSecurity, s.plug.Snap.InstanceName()) c.Assert(err, ErrorMatches, "cannot compute snippet for consumer") c.Assert(spec, IsNil) - spec, err = repo.SnapSpecification(testSecurity, s.slot.Snap.Name()) + spec, err = repo.SnapSpecification(testSecurity, s.slot.Snap.InstanceName()) c.Assert(err, ErrorMatches, "cannot compute snippet for provider") c.Assert(spec, IsNil) } @@ -1473,13 +1473,13 @@ slots: candidateSlots := repo.AutoConnectCandidateSlots("consumer", "auto", policyCheck) c.Assert(candidateSlots, HasLen, 1) - c.Check(candidateSlots[0].Snap.Name(), Equals, "producer") + c.Check(candidateSlots[0].Snap.InstanceName(), Equals, "producer") c.Check(candidateSlots[0].Interface, Equals, "auto") c.Check(candidateSlots[0].Name, Equals, "auto") candidatePlugs := repo.AutoConnectCandidatePlugs("producer", "auto", policyCheck) c.Assert(candidatePlugs, HasLen, 1) - c.Check(candidatePlugs[0].Snap.Name(), Equals, "consumer") + c.Check(candidatePlugs[0].Snap.InstanceName(), Equals, "consumer") c.Check(candidatePlugs[0].Interface, Equals, "auto") c.Check(candidatePlugs[0].Name, Equals, "auto") } @@ -1530,13 +1530,13 @@ plugs: // Both can auto-connect candidateSlots := repo.AutoConnectCandidateSlots("consumer1", "auto", policyCheck) c.Assert(candidateSlots, HasLen, 1) - c.Check(candidateSlots[0].Snap.Name(), Equals, "producer") + c.Check(candidateSlots[0].Snap.InstanceName(), Equals, "producer") c.Check(candidateSlots[0].Interface, Equals, "auto") c.Check(candidateSlots[0].Name, Equals, "auto") candidateSlots = repo.AutoConnectCandidateSlots("consumer2", "auto", policyCheck) c.Assert(candidateSlots, HasLen, 1) - c.Check(candidateSlots[0].Snap.Name(), Equals, "producer") + c.Check(candidateSlots[0].Snap.InstanceName(), Equals, "producer") c.Check(candidateSlots[0].Interface, Equals, "auto") c.Check(candidateSlots[0].Name, Equals, "auto") diff --git a/interfaces/seccomp/backend.go b/interfaces/seccomp/backend.go index 40de971199..d71af0ab6f 100644 --- a/interfaces/seccomp/backend.go +++ b/interfaces/seccomp/backend.go @@ -93,7 +93,7 @@ func (b *Backend) Name() interfaces.SecuritySystem { // This method should be called after changing plug, slots, connections between // them or application present in the snap. func (b *Backend) Setup(snapInfo *snap.Info, opts interfaces.ConfinementOptions, repo *interfaces.Repository) error { - snapName := snapInfo.Name() + snapName := snapInfo.InstanceName() // Get the snippets that apply to this snap spec, err := repo.SnapSpecification(b.Name(), snapName) if err != nil { diff --git a/interfaces/sorting.go b/interfaces/sorting.go index b4ce1e79fd..b344a0772b 100644 --- a/interfaces/sorting.go +++ b/interfaces/sorting.go @@ -69,8 +69,8 @@ type byPlugSnapAndName []*snap.PlugInfo func (c byPlugSnapAndName) Len() int { return len(c) } func (c byPlugSnapAndName) Swap(i, j int) { c[i], c[j] = c[j], c[i] } func (c byPlugSnapAndName) Less(i, j int) bool { - if c[i].Snap.Name() != c[j].Snap.Name() { - return c[i].Snap.Name() < c[j].Snap.Name() + if c[i].Snap.InstanceName() != c[j].Snap.InstanceName() { + return c[i].Snap.InstanceName() < c[j].Snap.InstanceName() } return c[i].Name < c[j].Name } @@ -80,8 +80,8 @@ type bySlotSnapAndName []*snap.SlotInfo func (c bySlotSnapAndName) Len() int { return len(c) } func (c bySlotSnapAndName) Swap(i, j int) { c[i], c[j] = c[j], c[i] } func (c bySlotSnapAndName) Less(i, j int) bool { - if c[i].Snap.Name() != c[j].Snap.Name() { - return c[i].Snap.Name() < c[j].Snap.Name() + if c[i].Snap.InstanceName() != c[j].Snap.InstanceName() { + return c[i].Snap.InstanceName() < c[j].Snap.InstanceName() } return c[i].Name < c[j].Name } @@ -143,8 +143,8 @@ type byPlugInfo []*snap.PlugInfo func (c byPlugInfo) Len() int { return len(c) } func (c byPlugInfo) Swap(i, j int) { c[i], c[j] = c[j], c[i] } func (c byPlugInfo) Less(i, j int) bool { - if c[i].Snap.Name() != c[j].Snap.Name() { - return c[i].Snap.Name() < c[j].Snap.Name() + if c[i].Snap.InstanceName() != c[j].Snap.InstanceName() { + return c[i].Snap.InstanceName() < c[j].Snap.InstanceName() } return c[i].Name < c[j].Name } @@ -154,8 +154,8 @@ type bySlotInfo []*snap.SlotInfo func (c bySlotInfo) Len() int { return len(c) } func (c bySlotInfo) Swap(i, j int) { c[i], c[j] = c[j], c[i] } func (c bySlotInfo) Less(i, j int) bool { - if c[i].Snap.Name() != c[j].Snap.Name() { - return c[i].Snap.Name() < c[j].Snap.Name() + if c[i].Snap.InstanceName() != c[j].Snap.InstanceName() { + return c[i].Snap.InstanceName() < c[j].Snap.InstanceName() } return c[i].Name < c[j].Name } diff --git a/interfaces/systemd/backend.go b/interfaces/systemd/backend.go index 01c3b7c47f..3677618e14 100644 --- a/interfaces/systemd/backend.go +++ b/interfaces/systemd/backend.go @@ -54,7 +54,7 @@ func (b *Backend) Name() interfaces.SecuritySystem { // them or application present in the snap. func (b *Backend) Setup(snapInfo *snap.Info, confinement interfaces.ConfinementOptions, repo *interfaces.Repository) error { // Record all the extra systemd services for this snap. - snapName := snapInfo.Name() + snapName := snapInfo.InstanceName() // Get the services that apply to this snap spec, err := repo.SnapSpecification(b.Name(), snapName) if err != nil { diff --git a/interfaces/udev/backend.go b/interfaces/udev/backend.go index b90070b494..2a9e026457 100644 --- a/interfaces/udev/backend.go +++ b/interfaces/udev/backend.go @@ -63,7 +63,7 @@ func snapRulesFilePath(snapName string) string { // // If the method fails it should be re-tried (with a sensible strategy) by the caller. func (b *Backend) Setup(snapInfo *snap.Info, opts interfaces.ConfinementOptions, repo *interfaces.Repository) error { - snapName := snapInfo.Name() + snapName := snapInfo.InstanceName() spec, err := repo.SnapSpecification(b.Name(), snapName) if err != nil { return fmt.Errorf("cannot obtain udev specification for snap %q: %s", snapName, err) @@ -75,7 +75,7 @@ func (b *Backend) Setup(snapInfo *snap.Info, opts interfaces.ConfinementOptions, return fmt.Errorf("cannot create directory for udev rules %q: %s", dir, err) } - rulesFilePath := snapRulesFilePath(snapInfo.Name()) + rulesFilePath := snapRulesFilePath(snapInfo.InstanceName()) if len(content) == 0 { // Make sure that the rules file gets removed when we don't have any diff --git a/overlord/assertstate/assertstate.go b/overlord/assertstate/assertstate.go index deb46886dc..ef7b10ef0e 100644 --- a/overlord/assertstate/assertstate.go +++ b/overlord/assertstate/assertstate.go @@ -152,7 +152,7 @@ func RefreshSnapDeclarations(s *state.State, userID int) error { continue } if err := snapasserts.FetchSnapDeclaration(f, info.SnapID); err != nil { - return fmt.Errorf("cannot refresh snap-declaration for %q: %v", info.Name(), err) + return fmt.Errorf("cannot refresh snap-declaration for %q: %v", info.InstanceName(), err) } } return nil @@ -251,7 +251,7 @@ func ValidateRefreshes(s *state.State, snapInfos []*snap.Info, ignoreValidation } err := doFetch(s, userID, fetching) if err != nil { - errs = append(errs, fmt.Errorf("cannot refresh %q to revision %s: %v", candInfo.Name(), candInfo.Revision, err)) + errs = append(errs, fmt.Errorf("cannot refresh %q to revision %s: %v", candInfo.InstanceName(), candInfo.Revision, err)) continue } @@ -267,7 +267,7 @@ func ValidateRefreshes(s *state.State, snapInfos []*snap.Info, ignoreValidation } } if revoked != nil { - errs = append(errs, fmt.Errorf("cannot refresh %q to revision %s: validation by %q (id %q) revoked", candInfo.Name(), candInfo.Revision, gatingNames[revoked.SnapID()], revoked.SnapID())) + errs = append(errs, fmt.Errorf("cannot refresh %q to revision %s: validation by %q (id %q) revoked", candInfo.InstanceName(), candInfo.Revision, gatingNames[revoked.SnapID()], revoked.SnapID())) continue } @@ -346,7 +346,7 @@ func AutoAliases(s *state.State, info *snap.Info) (map[string]string, error) { } decl, err := SnapDeclaration(s, info.SnapID) if err != nil { - return nil, fmt.Errorf("internal error: cannot find snap-declaration for installed snap %q: %v", info.Name(), err) + return nil, fmt.Errorf("internal error: cannot find snap-declaration for installed snap %q: %v", info.InstanceName(), err) } explicitAliases := decl.Aliases() if len(explicitAliases) != 0 { diff --git a/overlord/devicestate/devicemgr.go b/overlord/devicestate/devicemgr.go index 451dd36fec..8887ade766 100644 --- a/overlord/devicestate/devicemgr.go +++ b/overlord/devicestate/devicemgr.go @@ -281,7 +281,7 @@ func (m *DeviceManager) ensureOperational() error { if gadgetInfo != nil && gadgetInfo.Hooks["prepare-device"] != nil { summary := i18n.G("Run prepare-device hook") hooksup := &hookstate.HookSetup{ - Snap: gadgetInfo.Name(), + Snap: gadgetInfo.InstanceName(), Hook: "prepare-device", } prepareDevice = hookstate.HookTask(m.state, summary, hooksup, nil) diff --git a/overlord/devicestate/devicestate.go b/overlord/devicestate/devicestate.go index 4a3d41e0a3..1fd9a252a8 100644 --- a/overlord/devicestate/devicestate.go +++ b/overlord/devicestate/devicestate.go @@ -160,14 +160,14 @@ func checkGadgetOrKernel(st *state.State, snapInfo, curInfo *snap.Info, flags sn if snapInfo.SnapID != "" { snapDecl, err := assertstate.SnapDeclaration(st, snapInfo.SnapID) if err != nil { - return fmt.Errorf("internal error: cannot find snap declaration for %q: %v", snapInfo.Name(), err) + return fmt.Errorf("internal error: cannot find snap declaration for %q: %v", snapInfo.InstanceName(), err) } publisher := snapDecl.PublisherID() if publisher != "canonical" && publisher != model.BrandID() { - return fmt.Errorf("cannot install %s %q published by %q for model by %q", kind, snapInfo.Name(), publisher, model.BrandID()) + return fmt.Errorf("cannot install %s %q published by %q for model by %q", kind, snapInfo.InstanceName(), publisher, model.BrandID()) } } else { - logger.Noticef("installing unasserted %s %q", kind, snapInfo.Name()) + logger.Noticef("installing unasserted %s %q", kind, snapInfo.InstanceName()) } currentSnap, err := currentInfo(st) @@ -185,8 +185,9 @@ func checkGadgetOrKernel(st *state.State, snapInfo, curInfo *snap.Info, flags sn return fmt.Errorf("cannot install %s snap on classic if not requested by the model", kind) } - if snapInfo.Name() != expectedName { - return fmt.Errorf("cannot install %s %q, model assertion requests %q", kind, snapInfo.Name(), expectedName) + // TODO parallel-install: use instance name, instance name must match the store name + if snapInfo.InstanceName() != expectedName { + return fmt.Errorf("cannot install %s %q, model assertion requests %q", kind, snapInfo.InstanceName(), expectedName) } return nil @@ -259,7 +260,7 @@ func CanManageRefreshes(st *state.State) bool { for _, plugInfo := range info.Plugs { if plugInfo.Interface == "snapd-control" && plugInfo.Attrs["refresh-schedule"] == "managed" { - snapName := info.Name() + snapName := info.InstanceName() plugName := plugInfo.Name if interfaceConnected(st, snapName, plugName) { return true diff --git a/overlord/devicestate/devicestate_test.go b/overlord/devicestate/devicestate_test.go index bec19018a0..c93d089c4e 100644 --- a/overlord/devicestate/devicestate_test.go +++ b/overlord/devicestate/devicestate_test.go @@ -2121,8 +2121,8 @@ func makeMockRepoWithConnectedSnaps(c *C, st *state.State, info11, core11 *snap. err = repo.AddSnap(core11) c.Assert(err, IsNil) _, err = repo.Connect(&interfaces.ConnRef{ - PlugRef: interfaces.PlugRef{Snap: info11.Name(), Name: ifname}, - SlotRef: interfaces.SlotRef{Snap: core11.Name(), Name: ifname}, + PlugRef: interfaces.PlugRef{Snap: info11.InstanceName(), Name: ifname}, + SlotRef: interfaces.SlotRef{Snap: core11.InstanceName(), Name: ifname}, }, nil, nil, nil) c.Assert(err, IsNil) conns, err := repo.Connected("snap-with-snapd-control", "snapd-control") @@ -2134,7 +2134,7 @@ func makeMockRepoWithConnectedSnaps(c *C, st *state.State, info11, core11 *snap. func (s *deviceMgrSuite) makeSnapDeclaration(c *C, st *state.State, info *snap.Info) { decl, err := s.storeSigning.Sign(asserts.SnapDeclarationType, map[string]interface{}{ "series": "16", - "snap-name": info.Name(), + "snap-name": info.StoreName(), "snap-id": info.SideInfo.SnapID, "publisher-id": "canonical", "timestamp": time.Now().UTC().Format(time.RFC3339), diff --git a/overlord/devicestate/firstboot_test.go b/overlord/devicestate/firstboot_test.go index 2130b02ba9..4bef3b9158 100644 --- a/overlord/devicestate/firstboot_test.go +++ b/overlord/devicestate/firstboot_test.go @@ -279,7 +279,7 @@ func (s *FirstBootTestSuite) TestPopulateFromSeedErrorsOnState(c *C) { func (s *FirstBootTestSuite) makeAssertedSnap(c *C, snapYaml string, files [][]string, revision snap.Revision, developerID string) (snapFname string, snapDecl *asserts.SnapDeclaration, snapRev *asserts.SnapRevision) { info, err := snap.InfoFromSnapYaml([]byte(snapYaml)) c.Assert(err, IsNil) - snapName := info.Name() + snapName := info.InstanceName() mockSnapFile := snaptest.MakeTestSnapWithFiles(c, snapYaml, files) snapFname = filepath.Base(mockSnapFile) @@ -1163,6 +1163,15 @@ snaps: err = s.overlord.Settle(settleTimeout) st.Lock() c.Assert(err, IsNil) + + // at this point snapd is "restarting", pretend the restart has + // happened + c.Assert(chg.Status(), Equals, state.DoingStatus) + state.MockRestarting(st, state.RestartUnset) + st.Unlock() + err = s.overlord.Settle(settleTimeout) + st.Lock() + c.Assert(err, IsNil) c.Assert(chg.Status(), Equals, state.DoneStatus) // verify diff --git a/overlord/devicestate/handlers.go b/overlord/devicestate/handlers.go index 6e296a8186..28050610ba 100644 --- a/overlord/devicestate/handlers.go +++ b/overlord/devicestate/handlers.go @@ -360,7 +360,7 @@ func getSerialRequestConfig(t *state.Task) (*serialRequestConfig, error) { if err != nil { return nil, fmt.Errorf("cannot find gadget snap and its name: %v", err) } - gadgetName = gadgetInfo.Name() + gadgetName = gadgetInfo.InstanceName() tr = config.NewTransaction(t.State()) err = tr.GetMaybe(gadgetName, "device-service.url", &svcURL) diff --git a/overlord/hookstate/ctlcmd/services_test.go b/overlord/hookstate/ctlcmd/services_test.go index b8442bcf57..36f7d5fa85 100644 --- a/overlord/hookstate/ctlcmd/services_test.go +++ b/overlord/hookstate/ctlcmd/services_test.go @@ -143,22 +143,22 @@ func (s *servicectlSuite) SetUpTest(c *C) { info2 := snaptest.MockSnap(c, string(otherSnapYaml), &snap.SideInfo{ Revision: snap.R(1), }) - snapstate.Set(s.st, info1.Name(), &snapstate.SnapState{ + snapstate.Set(s.st, info1.InstanceName(), &snapstate.SnapState{ Active: true, Sequence: []*snap.SideInfo{ { - RealName: info1.Name(), + RealName: info1.StoreName(), Revision: info1.Revision, SnapID: "test-snap-id", }, }, Current: info1.Revision, }) - snapstate.Set(s.st, info2.Name(), &snapstate.SnapState{ + snapstate.Set(s.st, info2.InstanceName(), &snapstate.SnapState{ Active: true, Sequence: []*snap.SideInfo{ { - RealName: info2.Name(), + RealName: info2.StoreName(), Revision: info2.Revision, SnapID: "other-snap-id", }, diff --git a/overlord/ifacestate/handlers.go b/overlord/ifacestate/handlers.go index fcc1eaddf5..a8beb0b83b 100644 --- a/overlord/ifacestate/handlers.go +++ b/overlord/ifacestate/handlers.go @@ -103,7 +103,7 @@ func (m *InterfaceManager) doSetupProfiles(task *state.Task, tomb *tomb.Tomb) er func (m *InterfaceManager) setupProfilesForSnap(task *state.Task, _ *tomb.Tomb, snapInfo *snap.Info, opts interfaces.ConfinementOptions) error { addImplicitSlots(snapInfo) - snapName := snapInfo.Name() + snapName := snapInfo.InstanceName() // The snap may have been updated so perform the following operation to // ensure that we are always working on the correct state: @@ -146,7 +146,7 @@ func (m *InterfaceManager) setupProfilesForSnap(task *state.Task, _ *tomb.Tomb, affectedSet[name] = true } // The principal snap was already handled above. - delete(affectedSet, snapInfo.Name()) + delete(affectedSet, snapInfo.InstanceName()) affectedSnaps := make([]string, 0, len(affectedSet)) for name := range affectedSet { affectedSnaps = append(affectedSnaps, name) @@ -611,9 +611,9 @@ func (m *InterfaceManager) doAutoConnect(task *state.Task, _ *tomb.Tomb) error { // go with those from the new core snap. if len(candidates) == 2 { switch { - case candidates[0].Snap.Name() == "ubuntu-core" && candidates[1].Snap.Name() == "core": + case candidates[0].Snap.InstanceName() == "ubuntu-core" && candidates[1].Snap.InstanceName() == "core": candidates = candidates[1:2] - case candidates[1].Snap.Name() == "ubuntu-core" && candidates[0].Snap.Name() == "core": + case candidates[1].Snap.InstanceName() == "ubuntu-core" && candidates[0].Snap.InstanceName() == "core": candidates = candidates[0:1] } } @@ -634,7 +634,7 @@ func (m *InterfaceManager) doAutoConnect(task *state.Task, _ *tomb.Tomb) error { continue } - ignore, err := findSymmetricAutoconnect(st, plug.Snap.Name(), slot.Snap.Name(), task) + ignore, err := findSymmetricAutoconnect(st, plug.Snap.InstanceName(), slot.Snap.InstanceName(), task) if err != nil { return err } @@ -644,9 +644,9 @@ func (m *InterfaceManager) doAutoConnect(task *state.Task, _ *tomb.Tomb) error { } const auto = true - if err := checkConnectConflicts(st, plug.Snap.Name(), slot.Snap.Name(), auto); err != nil { + if err := checkConnectConflicts(st, plug.Snap.InstanceName(), slot.Snap.InstanceName(), auto); err != nil { if _, retry := err.(*state.Retry); retry { - task.Logf("auto-connect of snap %q will be retried because of %q - %q conflict", snapName, plug.Snap.Name(), slot.Snap.Name()) + task.Logf("auto-connect of snap %q will be retried because of %q - %q conflict", snapName, plug.Snap.InstanceName(), slot.Snap.InstanceName()) return err // will retry } return fmt.Errorf("auto-connect conflict check failed: %s", err) @@ -664,7 +664,7 @@ func (m *InterfaceManager) doAutoConnect(task *state.Task, _ *tomb.Tomb) error { // make sure slot is the only viable // connection for plug, same check as if we were // considering auto-connections from plug - candSlots := m.repo.AutoConnectCandidateSlots(plug.Snap.Name(), plug.Name, autochecker.check) + candSlots := m.repo.AutoConnectCandidateSlots(plug.Snap.InstanceName(), plug.Name, autochecker.check) if len(candSlots) != 1 || candSlots[0].String() != slot.String() { crefs := make([]string, len(candSlots)) @@ -686,7 +686,7 @@ func (m *InterfaceManager) doAutoConnect(task *state.Task, _ *tomb.Tomb) error { continue } - ignore, err := findSymmetricAutoconnect(st, plug.Snap.Name(), slot.Snap.Name(), task) + ignore, err := findSymmetricAutoconnect(st, plug.Snap.InstanceName(), slot.Snap.InstanceName(), task) if err != nil { return err } @@ -696,9 +696,9 @@ func (m *InterfaceManager) doAutoConnect(task *state.Task, _ *tomb.Tomb) error { } const auto = true - if err := checkConnectConflicts(st, plug.Snap.Name(), slot.Snap.Name(), auto); err != nil { + if err := checkConnectConflicts(st, plug.Snap.InstanceName(), slot.Snap.InstanceName(), auto); err != nil { if _, retry := err.(*state.Retry); retry { - task.Logf("auto-connect of snap %q will be retried because of %q - %q conflict", snapName, plug.Snap.Name(), slot.Snap.Name()) + task.Logf("auto-connect of snap %q will be retried because of %q - %q conflict", snapName, plug.Snap.InstanceName(), slot.Snap.InstanceName()) return err // will retry } return fmt.Errorf("auto-connect conflict check failed: %s", err) diff --git a/overlord/ifacestate/helpers.go b/overlord/ifacestate/helpers.go index 8e52a570ee..c5431989fb 100644 --- a/overlord/ifacestate/helpers.go +++ b/overlord/ifacestate/helpers.go @@ -107,7 +107,7 @@ func (m *InterfaceManager) addSnaps() error { for _, snapInfo := range snaps { addImplicitSlots(snapInfo) if err := m.repo.AddSnap(snapInfo); err != nil { - logger.Noticef("cannot add snap %q to interface repository: %s", snapInfo.Name(), err) + logger.Noticef("cannot add snap %q to interface repository: %s", snapInfo.InstanceName(), err) } } return nil @@ -139,7 +139,7 @@ func (m *InterfaceManager) regenerateAllSecurityProfiles() error { // For each snap: for _, snapInfo := range snaps { - snapName := snapInfo.Name() + snapName := snapInfo.InstanceName() // Get the state of the snap so we can compute the confinement option var snapst snapstate.SnapState if err := snapstate.Get(m.state, snapName, &snapst); err != nil { @@ -285,7 +285,7 @@ func (m *InterfaceManager) reloadConnections(snapName string) ([]string, error) func (m *InterfaceManager) setupSnapSecurity(task *state.Task, snapInfo *snap.Info, opts interfaces.ConfinementOptions) error { st := task.State() - snapName := snapInfo.Name() + snapName := snapInfo.InstanceName() for _, backend := range m.repo.Backends() { st.Unlock() @@ -362,7 +362,7 @@ func (c *autoConnectChecker) check(plug *interfaces.ConnectedPlug, slot *interfa var err error plugDecl, err = c.snapDeclaration(plug.Snap().SnapID) if err != nil { - logger.Noticef("error: cannot find snap declaration for %q: %v", plug.Snap().Name(), err) + logger.Noticef("error: cannot find snap declaration for %q: %v", plug.Snap().InstanceName(), err) return false, nil } } @@ -372,7 +372,7 @@ func (c *autoConnectChecker) check(plug *interfaces.ConnectedPlug, slot *interfa var err error slotDecl, err = c.snapDeclaration(slot.Snap().SnapID) if err != nil { - logger.Noticef("error: cannot find snap declaration for %q: %v", slot.Snap().Name(), err) + logger.Noticef("error: cannot find snap declaration for %q: %v", slot.Snap().InstanceName(), err) return false, nil } } @@ -411,7 +411,7 @@ func (c *connectChecker) check(plug *interfaces.ConnectedPlug, slot *interfaces. var err error plugDecl, err = assertstate.SnapDeclaration(c.st, plug.Snap().SnapID) if err != nil { - return false, fmt.Errorf("cannot find snap declaration for %q: %v", plug.Snap().Name(), err) + return false, fmt.Errorf("cannot find snap declaration for %q: %v", plug.Snap().InstanceName(), err) } } @@ -420,7 +420,7 @@ func (c *connectChecker) check(plug *interfaces.ConnectedPlug, slot *interfaces. var err error slotDecl, err = assertstate.SnapDeclaration(c.st, slot.Snap().SnapID) if err != nil { - return false, fmt.Errorf("cannot find snap declaration for %q: %v", slot.Snap().Name(), err) + return false, fmt.Errorf("cannot find snap declaration for %q: %v", slot.Snap().InstanceName(), err) } } @@ -483,7 +483,7 @@ func snapsWithSecurityProfiles(st *state.State) ([]*snap.Info, error) { } seen := make(map[string]bool, len(infos)) for _, info := range infos { - seen[info.Name()] = true + seen[info.InstanceName()] = true } for _, t := range st.Tasks() { if t.Kind() != "link-snap" || t.Status().Ready() { diff --git a/overlord/ifacestate/ifacestate.go b/overlord/ifacestate/ifacestate.go index d1eda9a5e9..4eb8330dd8 100644 --- a/overlord/ifacestate/ifacestate.go +++ b/overlord/ifacestate/ifacestate.go @@ -296,7 +296,7 @@ func CheckInterfaces(st *state.State, snapInfo *snap.Info) error { snapDecl, err := assertstate.SnapDeclaration(st, snapInfo.SnapID) if err != nil { - return fmt.Errorf("cannot find snap declaration for %q: %v", snapInfo.Name(), err) + return fmt.Errorf("cannot find snap declaration for %q: %v", snapInfo.InstanceName(), err) } ic := policy.InstallCandidate{ diff --git a/overlord/ifacestate/ifacestate_test.go b/overlord/ifacestate/ifacestate_test.go index b1db199967..b20346e832 100644 --- a/overlord/ifacestate/ifacestate_test.go +++ b/overlord/ifacestate/ifacestate_test.go @@ -749,8 +749,8 @@ func (s *interfaceManagerSuite) testDisconnect(c *C, plugSnap, plugName, slotSna // Ensure that the backend was used to setup security of both snaps c.Assert(s.secBackend.SetupCalls, HasLen, 2) c.Assert(s.secBackend.RemoveCalls, HasLen, 0) - c.Check(s.secBackend.SetupCalls[0].SnapInfo.Name(), Equals, "consumer") - c.Check(s.secBackend.SetupCalls[1].SnapInfo.Name(), Equals, "producer") + c.Check(s.secBackend.SetupCalls[0].SnapInfo.InstanceName(), Equals, "consumer") + c.Check(s.secBackend.SetupCalls[1].SnapInfo.InstanceName(), Equals, "producer") c.Check(s.secBackend.SetupCalls[0].Options, Equals, interfaces.ConfinementOptions{}) c.Check(s.secBackend.SetupCalls[1].Options, Equals, interfaces.ConfinementOptions{}) @@ -862,7 +862,7 @@ func (s *interfaceManagerSuite) mockSnap(c *C, yamlText string) *snap.Info { Revision: snap.R(1), } snapInfo := snaptest.MockSnap(c, yamlText, sideInfo) - sideInfo.RealName = snapInfo.Name() + sideInfo.RealName = snapInfo.StoreName() a, err := s.db.FindMany(asserts.SnapDeclarationType, map[string]string{ "snap-name": sideInfo.RealName, @@ -880,7 +880,7 @@ func (s *interfaceManagerSuite) mockSnap(c *C, yamlText string) *snap.Info { defer s.state.Unlock() // Put a side info into the state - snapstate.Set(s.state, snapInfo.Name(), &snapstate.SnapState{ + snapstate.Set(s.state, snapInfo.InstanceName(), &snapstate.SnapState{ Active: true, Sequence: []*snap.SideInfo{sideInfo}, Current: sideInfo.Revision, @@ -891,17 +891,17 @@ func (s *interfaceManagerSuite) mockSnap(c *C, yamlText string) *snap.Info { func (s *interfaceManagerSuite) mockUpdatedSnap(c *C, yamlText string, revision int) *snap.Info { sideInfo := &snap.SideInfo{Revision: snap.R(revision)} snapInfo := snaptest.MockSnap(c, yamlText, sideInfo) - sideInfo.RealName = snapInfo.Name() + sideInfo.RealName = snapInfo.StoreName() s.state.Lock() defer s.state.Unlock() // Put the new revision (stored in SideInfo) into the state var snapst snapstate.SnapState - err := snapstate.Get(s.state, snapInfo.Name(), &snapst) + err := snapstate.Get(s.state, snapInfo.InstanceName(), &snapst) c.Assert(err, IsNil) snapst.Sequence = append(snapst.Sequence, sideInfo) - snapstate.Set(s.state, snapInfo.Name(), &snapst) + snapstate.Set(s.state, snapInfo.InstanceName(), &snapst) return snapInfo } @@ -1059,7 +1059,7 @@ func (s *interfaceManagerSuite) TestDoSetupSnapSecurityHonorsUndesiredFlag(c *C) // Run the setup-snap-security task and let it finish. change := s.addSetupSnapSecurityChange(c, &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ - RealName: snapInfo.Name(), + RealName: snapInfo.StoreName(), Revision: snapInfo.Revision, }, }) @@ -1103,7 +1103,7 @@ func (s *interfaceManagerSuite) TestDoSetupSnapSecurityAutoConnectsPlugs(c *C) { // Run the setup-snap-security task and let it finish. change := s.addSetupSnapSecurityChange(c, &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ - RealName: snapInfo.Name(), + RealName: snapInfo.StoreName(), Revision: snapInfo.Revision, }, }) @@ -1151,7 +1151,7 @@ func (s *interfaceManagerSuite) TestDoSetupSnapSecurityAutoConnectsSlots(c *C) { // Run the setup-snap-security task and let it finish. change := s.addSetupSnapSecurityChange(c, &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ - RealName: snapInfo.Name(), + RealName: snapInfo.StoreName(), Revision: snapInfo.Revision, }, }) @@ -1204,7 +1204,7 @@ func (s *interfaceManagerSuite) TestDoSetupSnapSecurityAutoConnectsSlotsMultiple // Run the setup-snap-security task and let it finish. change := s.addSetupSnapSecurityChange(c, &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ - RealName: snapInfo.Name(), + RealName: snapInfo.StoreName(), Revision: snapInfo.Revision, }, }) @@ -1266,7 +1266,7 @@ func (s *interfaceManagerSuite) TestDoSetupSnapSecurityNoAutoConnectSlotsIfAlter // Run the setup-snap-security task and let it finish. change := s.addSetupSnapSecurityChange(c, &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ - RealName: snapInfo.Name(), + RealName: snapInfo.StoreName(), Revision: snapInfo.Revision, }, }) @@ -1337,7 +1337,7 @@ slots: // Run the setup-snap-security task and let it finish. change := s.addSetupSnapSecurityChange(c, &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ - RealName: snapInfo.Name(), + RealName: snapInfo.StoreName(), SnapID: snapInfo.SnapID, Revision: snapInfo.Revision, }, @@ -1384,7 +1384,7 @@ func (s *interfaceManagerSuite) TestDoSetupSnapSecuirtyKeepsExistingConnectionSt // Run the setup-snap-security task and let it finish. change := s.addSetupSnapSecurityChange(c, &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ - RealName: snapInfo.Name(), + RealName: snapInfo.StoreName(), Revision: snapInfo.Revision, }, }) @@ -1430,7 +1430,7 @@ func (s *interfaceManagerSuite) TestDoSetupSnapSecuirtyIgnoresStrayConnection(c // Run the setup-snap-security task and let it finish. change := s.addSetupSnapSecurityChange(c, &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ - RealName: snapInfo.Name(), + RealName: snapInfo.StoreName(), Revision: snapInfo.Revision, }, }) @@ -1459,7 +1459,7 @@ func (s *interfaceManagerSuite) TestDoSetupProfilesAddsImplicitSlots(c *C) { // Run the setup-profiles task and let it finish. change := s.addSetupSnapSecurityChange(c, &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ - RealName: snapInfo.Name(), + RealName: snapInfo.StoreName(), Revision: snapInfo.Revision, }, }) @@ -1473,7 +1473,7 @@ func (s *interfaceManagerSuite) TestDoSetupProfilesAddsImplicitSlots(c *C) { // Ensure that we have slots on the OS snap. repo := mgr.Repository() - slots := repo.Slots(snapInfo.Name()) + slots := repo.Slots(snapInfo.InstanceName()) // NOTE: This is not an exact test as it duplicates functionality elsewhere // and is was a pain to update each time. This is correctly handled by the // implicit slot tests in snap/implicit_test.go @@ -1484,13 +1484,13 @@ func (s *interfaceManagerSuite) TestDoSetupSnapSecuirtyReloadsConnectionsWhenInv s.mockIfaces(c, &ifacetest.TestInterface{InterfaceName: "test"}, &ifacetest.TestInterface{InterfaceName: "test2"}) snapInfo := s.mockSnap(c, consumerYaml) s.mockSnap(c, producerYaml) - s.testDoSetupSnapSecuirtyReloadsConnectionsWhenInvokedOn(c, snapInfo.Name(), snapInfo.Revision) + s.testDoSetupSnapSecuirtyReloadsConnectionsWhenInvokedOn(c, snapInfo.InstanceName(), snapInfo.Revision) // Ensure that the backend was used to setup security of both snaps c.Assert(s.secBackend.SetupCalls, HasLen, 2) c.Assert(s.secBackend.RemoveCalls, HasLen, 0) - c.Check(s.secBackend.SetupCalls[0].SnapInfo.Name(), Equals, "consumer") - c.Check(s.secBackend.SetupCalls[1].SnapInfo.Name(), Equals, "producer") + c.Check(s.secBackend.SetupCalls[0].SnapInfo.InstanceName(), Equals, "consumer") + c.Check(s.secBackend.SetupCalls[1].SnapInfo.InstanceName(), Equals, "producer") c.Check(s.secBackend.SetupCalls[0].Options, Equals, interfaces.ConfinementOptions{}) c.Check(s.secBackend.SetupCalls[1].Options, Equals, interfaces.ConfinementOptions{}) @@ -1500,13 +1500,13 @@ func (s *interfaceManagerSuite) TestDoSetupSnapSecuirtyReloadsConnectionsWhenInv s.mockIfaces(c, &ifacetest.TestInterface{InterfaceName: "test"}, &ifacetest.TestInterface{InterfaceName: "test2"}) s.mockSnap(c, consumerYaml) snapInfo := s.mockSnap(c, producerYaml) - s.testDoSetupSnapSecuirtyReloadsConnectionsWhenInvokedOn(c, snapInfo.Name(), snapInfo.Revision) + s.testDoSetupSnapSecuirtyReloadsConnectionsWhenInvokedOn(c, snapInfo.InstanceName(), snapInfo.Revision) // Ensure that the backend was used to setup security of both snaps c.Assert(s.secBackend.SetupCalls, HasLen, 2) c.Assert(s.secBackend.RemoveCalls, HasLen, 0) - c.Check(s.secBackend.SetupCalls[0].SnapInfo.Name(), Equals, "producer") - c.Check(s.secBackend.SetupCalls[1].SnapInfo.Name(), Equals, "consumer") + c.Check(s.secBackend.SetupCalls[0].SnapInfo.InstanceName(), Equals, "producer") + c.Check(s.secBackend.SetupCalls[1].SnapInfo.InstanceName(), Equals, "consumer") c.Check(s.secBackend.SetupCalls[0].Options, Equals, interfaces.ConfinementOptions{}) c.Check(s.secBackend.SetupCalls[1].Options, Equals, interfaces.ConfinementOptions{}) @@ -1558,7 +1558,7 @@ func (s *interfaceManagerSuite) TestSetupProfilesHonorsDevMode(c *C) { // Note that the task will see SnapSetup.Flags equal to DeveloperMode. change := s.addSetupSnapSecurityChange(c, &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ - RealName: snapInfo.Name(), + RealName: snapInfo.StoreName(), Revision: snapInfo.Revision, }, Flags: snapstate.Flags{DevMode: true}, @@ -1574,7 +1574,7 @@ func (s *interfaceManagerSuite) TestSetupProfilesHonorsDevMode(c *C) { // The snap was setup with DevModeConfinement c.Assert(s.secBackend.SetupCalls, HasLen, 1) c.Assert(s.secBackend.RemoveCalls, HasLen, 0) - c.Check(s.secBackend.SetupCalls[0].SnapInfo.Name(), Equals, "snap") + c.Check(s.secBackend.SetupCalls[0].SnapInfo.InstanceName(), Equals, "snap") c.Check(s.secBackend.SetupCalls[0].Options, Equals, interfaces.ConfinementOptions{DevMode: true}) } @@ -1609,7 +1609,7 @@ func (s *interfaceManagerSuite) TestSetupProfilesUsesFreshSnapInfo(c *C) { // Run the setup-profiles task for the new revision and let it finish. change := s.addSetupSnapSecurityChange(c, &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ - RealName: newSnapInfo.Name(), + RealName: newSnapInfo.StoreName(), Revision: newSnapInfo.Revision, }, }) @@ -1626,10 +1626,10 @@ func (s *interfaceManagerSuite) TestSetupProfilesUsesFreshSnapInfo(c *C) { c.Assert(s.secBackend.SetupCalls, HasLen, 2) c.Assert(s.secBackend.RemoveCalls, HasLen, 0) // The sample snap was setup, with the correct new revision. - c.Check(s.secBackend.SetupCalls[0].SnapInfo.Name(), Equals, newSnapInfo.Name()) + c.Check(s.secBackend.SetupCalls[0].SnapInfo.InstanceName(), Equals, newSnapInfo.InstanceName()) c.Check(s.secBackend.SetupCalls[0].SnapInfo.Revision, Equals, newSnapInfo.Revision) // The OS snap was setup (because it was affected). - c.Check(s.secBackend.SetupCalls[1].SnapInfo.Name(), Equals, coreSnapInfo.Name()) + c.Check(s.secBackend.SetupCalls[1].SnapInfo.InstanceName(), Equals, coreSnapInfo.InstanceName()) c.Check(s.secBackend.SetupCalls[1].SnapInfo.Revision, Equals, coreSnapInfo.Revision) } @@ -1647,7 +1647,7 @@ func (s *interfaceManagerSuite) TestAutoConnectSetupSecurityForConnectedSlots(c // Run the setup-snap-security task and let it finish. change := s.addSetupSnapSecurityChange(c, &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ - RealName: snapInfo.Name(), + RealName: snapInfo.StoreName(), Revision: snapInfo.Revision, }, }) @@ -1664,10 +1664,10 @@ func (s *interfaceManagerSuite) TestAutoConnectSetupSecurityForConnectedSlots(c c.Assert(s.secBackend.SetupCalls, HasLen, 3) c.Assert(s.secBackend.RemoveCalls, HasLen, 0) // The sample snap was setup, with the correct new revision. - c.Check(s.secBackend.SetupCalls[0].SnapInfo.Name(), Equals, snapInfo.Name()) + c.Check(s.secBackend.SetupCalls[0].SnapInfo.InstanceName(), Equals, snapInfo.InstanceName()) c.Check(s.secBackend.SetupCalls[0].SnapInfo.Revision, Equals, snapInfo.Revision) // The OS snap was setup (because its connected to sample snap). - c.Check(s.secBackend.SetupCalls[1].SnapInfo.Name(), Equals, coreSnapInfo.Name()) + c.Check(s.secBackend.SetupCalls[1].SnapInfo.InstanceName(), Equals, coreSnapInfo.InstanceName()) c.Check(s.secBackend.SetupCalls[1].SnapInfo.Revision, Equals, coreSnapInfo.Revision) } @@ -1823,7 +1823,7 @@ func (s *interfaceManagerSuite) TestDoRemove(c *C) { // Security of the related snap was configured c.Check(s.secBackend.SetupCalls, HasLen, 1) - c.Check(s.secBackend.SetupCalls[0].SnapInfo.Name(), Equals, "producer") + c.Check(s.secBackend.SetupCalls[0].SnapInfo.InstanceName(), Equals, "producer") // Connection state was left intact var conns map[string]interface{} @@ -1906,8 +1906,8 @@ func (s *interfaceManagerSuite) TestConnectSetsUpSecurity(c *C) { c.Assert(s.secBackend.SetupCalls, HasLen, 2) c.Assert(s.secBackend.RemoveCalls, HasLen, 0) - c.Check(s.secBackend.SetupCalls[0].SnapInfo.Name(), Equals, "producer") - c.Check(s.secBackend.SetupCalls[1].SnapInfo.Name(), Equals, "consumer") + c.Check(s.secBackend.SetupCalls[0].SnapInfo.InstanceName(), Equals, "producer") + c.Check(s.secBackend.SetupCalls[1].SnapInfo.InstanceName(), Equals, "consumer") c.Check(s.secBackend.SetupCalls[0].Options, Equals, interfaces.ConfinementOptions{}) c.Check(s.secBackend.SetupCalls[1].Options, Equals, interfaces.ConfinementOptions{}) @@ -1951,8 +1951,8 @@ func (s *interfaceManagerSuite) TestDisconnectSetsUpSecurity(c *C) { c.Assert(s.secBackend.SetupCalls, HasLen, 2) c.Assert(s.secBackend.RemoveCalls, HasLen, 0) - c.Check(s.secBackend.SetupCalls[0].SnapInfo.Name(), Equals, "consumer") - c.Check(s.secBackend.SetupCalls[1].SnapInfo.Name(), Equals, "producer") + c.Check(s.secBackend.SetupCalls[0].SnapInfo.InstanceName(), Equals, "consumer") + c.Check(s.secBackend.SetupCalls[1].SnapInfo.InstanceName(), Equals, "producer") c.Check(s.secBackend.SetupCalls[0].Options, Equals, interfaces.ConfinementOptions{}) c.Check(s.secBackend.SetupCalls[1].Options, Equals, interfaces.ConfinementOptions{}) @@ -2107,15 +2107,15 @@ func (s *interfaceManagerSuite) TestSetupProfilesDevModeMultiple(c *C) { }) c.Assert(err, IsNil) connRef := &interfaces.ConnRef{ - PlugRef: interfaces.PlugRef{Snap: siP.Name(), Name: "plug"}, - SlotRef: interfaces.SlotRef{Snap: siC.Name(), Name: "slot"}, + PlugRef: interfaces.PlugRef{Snap: siP.InstanceName(), Name: "plug"}, + SlotRef: interfaces.SlotRef{Snap: siC.InstanceName(), Name: "slot"}, } _, err = repo.Connect(connRef, nil, nil, nil) c.Assert(err, IsNil) change := s.addSetupSnapSecurityChange(c, &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ - RealName: siC.Name(), + RealName: siC.StoreName(), Revision: siC.Revision, }, Flags: snapstate.Flags{DevMode: true}, @@ -2132,9 +2132,9 @@ func (s *interfaceManagerSuite) TestSetupProfilesDevModeMultiple(c *C) { // The first snap is setup in devmode, the second is not c.Assert(s.secBackend.SetupCalls, HasLen, 2) c.Assert(s.secBackend.RemoveCalls, HasLen, 0) - c.Check(s.secBackend.SetupCalls[0].SnapInfo.Name(), Equals, siC.Name()) + c.Check(s.secBackend.SetupCalls[0].SnapInfo.InstanceName(), Equals, siC.InstanceName()) c.Check(s.secBackend.SetupCalls[0].Options, Equals, interfaces.ConfinementOptions{DevMode: true}) - c.Check(s.secBackend.SetupCalls[1].SnapInfo.Name(), Equals, siP.Name()) + c.Check(s.secBackend.SetupCalls[1].SnapInfo.InstanceName(), Equals, siP.InstanceName()) c.Check(s.secBackend.SetupCalls[1].Options, Equals, interfaces.ConfinementOptions{}) } @@ -2223,13 +2223,13 @@ func (s *interfaceManagerSuite) TestUndoSetupProfilesOnInstall(c *C) { // install. snapInfo := s.mockSnap(c, sampleSnapYaml) s.state.Lock() - snapstate.Set(s.state, snapInfo.Name(), nil) + snapstate.Set(s.state, snapInfo.InstanceName(), nil) s.state.Unlock() // Add a change that undoes "setup-snap-security" change := s.addSetupSnapSecurityChange(c, &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ - RealName: snapInfo.Name(), + RealName: snapInfo.StoreName(), Revision: snapInfo.Revision, }, }) @@ -2253,7 +2253,7 @@ func (s *interfaceManagerSuite) TestUndoSetupProfilesOnInstall(c *C) { // undo task removed the security profile from the system. c.Assert(s.secBackend.SetupCalls, HasLen, 0) c.Assert(s.secBackend.RemoveCalls, HasLen, 1) - c.Check(s.secBackend.RemoveCalls, DeepEquals, []string{snapInfo.Name()}) + c.Check(s.secBackend.RemoveCalls, DeepEquals, []string{snapInfo.InstanceName()}) } // Test that setup-snap-security gets undone correctly when a snap is refreshed @@ -2269,7 +2269,7 @@ func (s *interfaceManagerSuite) TestUndoSetupProfilesOnRefresh(c *C) { // Add a change that undoes "setup-snap-security" change := s.addSetupSnapSecurityChange(c, &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ - RealName: snapInfo.Name(), + RealName: snapInfo.StoreName(), Revision: snapInfo.Revision, }, }) @@ -2292,7 +2292,7 @@ func (s *interfaceManagerSuite) TestUndoSetupProfilesOnRefresh(c *C) { // setup the security of the snap we had in the state. c.Assert(s.secBackend.SetupCalls, HasLen, 1) c.Assert(s.secBackend.RemoveCalls, HasLen, 0) - c.Check(s.secBackend.SetupCalls[0].SnapInfo.Name(), Equals, snapInfo.Name()) + c.Check(s.secBackend.SetupCalls[0].SnapInfo.InstanceName(), Equals, snapInfo.InstanceName()) c.Check(s.secBackend.SetupCalls[0].SnapInfo.Revision, Equals, snapInfo.Revision) c.Check(s.secBackend.SetupCalls[0].Options, Equals, interfaces.ConfinementOptions{}) } @@ -2459,7 +2459,7 @@ func (s *interfaceManagerSuite) TestAutoConnectDuringCoreTransition(c *C) { // Run the setup-snap-security task and let it finish. change := s.addSetupSnapSecurityChange(c, &snapstate.SnapSetup{ SideInfo: &snap.SideInfo{ - RealName: snapInfo.Name(), + RealName: snapInfo.StoreName(), Revision: snapInfo.Revision, }, }) @@ -2954,7 +2954,7 @@ func (s *interfaceManagerSuite) TestSnapsWithSecurityProfiles(c *C) { c.Check(infos, HasLen, 3) got := make(map[string]snap.Revision) for _, info := range infos { - got[info.Name()] = info.Revision + got[info.InstanceName()] = info.Revision } c.Check(got, DeepEquals, map[string]snap.Revision{ "snap0": snap.R(10), diff --git a/overlord/managers_test.go b/overlord/managers_test.go index c350689019..ce2a246218 100644 --- a/overlord/managers_test.go +++ b/overlord/managers_test.go @@ -449,7 +449,7 @@ func (ms *mgrsSuite) makeStoreTestSnap(c *C, snapYaml string, revno string) (pat c.Assert(err, IsNil) headers := map[string]interface{}{ - "snap-id": fakeSnapID(info.Name()), + "snap-id": fakeSnapID(info.StoreName()), "snap-sha3-384": snapDigest, "snap-size": fmt.Sprintf("%d", size), "snap-revision": revno, @@ -642,7 +642,7 @@ func (ms *mgrsSuite) serveSnap(snapPath, revno string) { if err != nil { panic(err) } - name := info.Name() + name := info.StoreName() ms.serveIDtoName[fakeSnapID(name)] = name ms.serveSnapPath[name] = snapPath ms.serveRevision[name] = revno @@ -1165,7 +1165,7 @@ func (ms *mgrsSuite) installLocalTestSnap(c *C, snapYamlContent string) *snap.In c.Assert(err, IsNil) // store current state - snapName := info.Name() + snapName := info.InstanceName() var snapst snapstate.SnapState snapstate.Get(st, snapName, &snapst) diff --git a/overlord/servicestate/servicestate.go b/overlord/servicestate/servicestate.go index 51c8d064c2..965e13178c 100644 --- a/overlord/servicestate/servicestate.go +++ b/overlord/servicestate/servicestate.go @@ -79,7 +79,7 @@ func Control(st *state.State, appInfos []*snap.AppInfo, inst *Instruction, conte names := make([]string, len(appInfos)) for i, svc := range appInfos { svcs = append(svcs, svc.ServiceName()) - snapName := svc.Snap.Name() + snapName := svc.Snap.InstanceName() names[i] = snapName + "." + svc.Name if snapName != lastName { snapNames = append(snapNames, snapName) diff --git a/overlord/snapshotstate/backend/backend.go b/overlord/snapshotstate/backend/backend.go index 7b2a9baa7a..8118084b3a 100644 --- a/overlord/snapshotstate/backend/backend.go +++ b/overlord/snapshotstate/backend/backend.go @@ -161,7 +161,7 @@ func Save(ctx context.Context, id uint64, si *snap.Info, cfg map[string]interfac snapshot := &client.Snapshot{ SetID: id, - Snap: si.Name(), + Snap: si.InstanceName(), Revision: si.Revision, Version: si.Version, Time: time.Now(), diff --git a/overlord/snapshotstate/backend/backend_test.go b/overlord/snapshotstate/backend/backend_test.go index 12678e2699..50edecf3d3 100644 --- a/overlord/snapshotstate/backend/backend_test.go +++ b/overlord/snapshotstate/backend/backend_test.go @@ -445,7 +445,7 @@ func (s *snapshotSuite) TestHappyRoundtrip(c *check.C) { shw, err := backend.Save(context.TODO(), shID, info, cfg, []string{"snapuser"}) c.Assert(err, check.IsNil) c.Check(shw.SetID, check.Equals, shID) - c.Check(shw.Snap, check.Equals, info.Name()) + c.Check(shw.Snap, check.Equals, info.InstanceName()) c.Check(shw.Version, check.Equals, info.Version) c.Check(shw.Revision, check.Equals, info.Revision) c.Check(shw.Conf, check.DeepEquals, cfg) @@ -461,7 +461,7 @@ func (s *snapshotSuite) TestHappyRoundtrip(c *check.C) { defer shr.Close() c.Check(shr.SetID, check.Equals, shID) - c.Check(shr.Snap, check.Equals, info.Name()) + c.Check(shr.Snap, check.Equals, info.InstanceName()) c.Check(shr.Version, check.Equals, info.Version) c.Check(shr.Revision, check.Equals, info.Revision) c.Check(shr.Conf, check.DeepEquals, cfg) diff --git a/overlord/snapstate/aliasesv2.go b/overlord/snapstate/aliasesv2.go index 762a186a41..e330335d0b 100644 --- a/overlord/snapstate/aliasesv2.go +++ b/overlord/snapstate/aliasesv2.go @@ -547,6 +547,7 @@ func Alias(st *state.State, snapName, app, alias string) (*state.TaskSet, error) } snapsup := &SnapSetup{ + // TODO parallel-install: verify use of instance name SideInfo: &snap.SideInfo{RealName: snapName}, } @@ -568,7 +569,7 @@ func manualAlias(info *snap.Info, curAliases map[string]*AliasTarget, target, al } else { reason = fmt.Sprintf("target application %q is a daemon", target) } - return nil, fmt.Errorf("cannot enable alias %q for %q, %s", alias, info.Name(), reason) + return nil, fmt.Errorf("cannot enable alias %q for %q, %s", alias, info.InstanceName(), reason) } newAliases = make(map[string]*AliasTarget, len(curAliases)) for alias, aliasTarget := range curAliases { @@ -603,6 +604,7 @@ func DisableAllAliases(st *state.State, snapName string) (*state.TaskSet, error) } snapsup := &SnapSetup{ + // TODO parallel-install: verify use of instance name SideInfo: &snap.SideInfo{RealName: snapName}, } @@ -686,6 +688,7 @@ func Prefer(st *state.State, name string) (*state.TaskSet, error) { } snapsup := &SnapSetup{ + // TODO parallel-install: verify use of instance name SideInfo: &snap.SideInfo{RealName: name}, } diff --git a/overlord/snapstate/aliasesv2_test.go b/overlord/snapstate/aliasesv2_test.go index b14e5e6aa0..433168b1d3 100644 --- a/overlord/snapstate/aliasesv2_test.go +++ b/overlord/snapstate/aliasesv2_test.go @@ -145,7 +145,7 @@ func (s *snapmgrTestSuite) TestApplyAliasesChangeMulti(c *C) { func (s *snapmgrTestSuite) TestAutoAliasesDelta(c *C) { snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - c.Check(info.Name(), Equals, "alias-snap") + c.Check(info.InstanceName(), Equals, "alias-snap") return map[string]string{ "alias1": "cmd1", "alias2": "cmd2", @@ -188,8 +188,8 @@ func (s *snapmgrTestSuite) TestAutoAliasesDelta(c *C) { func (s *snapmgrTestSuite) TestAutoAliasesDeltaAll(c *C) { seen := make(map[string]bool) snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - seen[info.Name()] = true - if info.Name() == "alias-snap" { + seen[info.InstanceName()] = true + if info.InstanceName() == "alias-snap" { return map[string]string{ "alias1": "cmd1", "alias2": "cmd2", @@ -237,7 +237,7 @@ func (s *snapmgrTestSuite) TestAutoAliasesDeltaAll(c *C) { func (s *snapmgrTestSuite) TestAutoAliasesDeltaOverManual(c *C) { snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - c.Check(info.Name(), Equals, "alias-snap") + c.Check(info.InstanceName(), Equals, "alias-snap") return map[string]string{ "alias1": "cmd1", "alias2": "cmd2", @@ -274,7 +274,7 @@ func (s *snapmgrTestSuite) TestRefreshAliases(c *C) { defer s.state.Unlock() snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - c.Check(info.Name(), Equals, "alias-snap") + c.Check(info.InstanceName(), Equals, "alias-snap") return map[string]string{ "alias1": "cmd1", "alias2": "cmd2", diff --git a/overlord/snapstate/backend/backend_test.go b/overlord/snapstate/backend/backend_test.go index f06ca48276..9a62c76a94 100644 --- a/overlord/snapstate/backend/backend_test.go +++ b/overlord/snapstate/backend/backend_test.go @@ -72,7 +72,7 @@ apps: c.Assert(err, IsNil) c.Assert(snapf, FitsTypeOf, &squashfs.Snap{}) - c.Check(info.Name(), Equals, "hello") + c.Check(info.InstanceName(), Equals, "hello") } func (s *backendSuite) TestOpenSnapFilebSideInfo(c *C) { @@ -93,7 +93,7 @@ slots: c.Assert(err, IsNil) // check side info - c.Check(info.Name(), Equals, "blessed") + c.Check(info.InstanceName(), Equals, "blessed") c.Check(info.Revision, Equals, snap.R(42)) c.Check(info.SideInfo, DeepEquals, si) diff --git a/overlord/snapstate/backend/copydata.go b/overlord/snapstate/backend/copydata.go index 471b798aaf..62670f2471 100644 --- a/overlord/snapstate/backend/copydata.go +++ b/overlord/snapstate/backend/copydata.go @@ -56,7 +56,7 @@ func (b Backend) UndoCopySnapData(newInfo *snap.Info, oldInfo *snap.Info, meter } err1 := b.RemoveSnapData(newInfo) if err1 != nil { - logger.Noticef("Cannot remove data directories for %q: %v", newInfo.Name(), err1) + logger.Noticef("Cannot remove data directories for %q: %v", newInfo.InstanceName(), err1) } var err2 error @@ -64,12 +64,12 @@ func (b Backend) UndoCopySnapData(newInfo *snap.Info, oldInfo *snap.Info, meter // first install, remove created common data dir err2 = b.RemoveSnapCommonData(newInfo) if err2 != nil { - logger.Noticef("Cannot remove common data directories for %q: %v", newInfo.Name(), err2) + logger.Noticef("Cannot remove common data directories for %q: %v", newInfo.InstanceName(), err2) } } else { err2 = b.untrashData(newInfo) if err2 != nil { - logger.Noticef("Cannot restore original data for %q while undoing: %v", newInfo.Name(), err2) + logger.Noticef("Cannot restore original data for %q while undoing: %v", newInfo.InstanceName(), err2) } } @@ -80,7 +80,7 @@ func (b Backend) UndoCopySnapData(newInfo *snap.Info, oldInfo *snap.Info, meter func (b Backend) ClearTrashedData(oldSnap *snap.Info) { dirs, err := snapDataDirs(oldSnap) if err != nil { - logger.Noticef("Cannot remove previous data for %q: %v", oldSnap.Name(), err) + logger.Noticef("Cannot remove previous data for %q: %v", oldSnap.InstanceName(), err) return } diff --git a/overlord/snapstate/backend/link.go b/overlord/snapstate/backend/link.go index 77ed9c3062..6806d10701 100644 --- a/overlord/snapstate/backend/link.go +++ b/overlord/snapstate/backend/link.go @@ -61,7 +61,7 @@ func updateCurrentSymlinks(info *snap.Info) error { // LinkSnap makes the snap available by generating wrappers and setting the current symlinks. func (b Backend) LinkSnap(info *snap.Info, model *asserts.Model) error { if info.Revision.Unset() { - return fmt.Errorf("cannot link snap %q with unset revision", info.Name()) + return fmt.Errorf("cannot link snap %q with unset revision", info.InstanceName()) } if err := generateWrappers(info); err != nil { @@ -74,7 +74,7 @@ func (b Backend) LinkSnap(info *snap.Info, model *asserts.Model) error { if model.Base() != "" { bootBase = model.Base() } - switch info.Name() { + switch info.InstanceName() { case model.Kernel(), bootBase: if err := boot.SetNextBoot(info); err != nil { return err @@ -116,17 +116,17 @@ func generateWrappers(s *snap.Info) error { func removeGeneratedWrappers(s *snap.Info, meter progress.Meter) error { err1 := wrappers.RemoveSnapBinaries(s) if err1 != nil { - logger.Noticef("Cannot remove binaries for %q: %v", s.Name(), err1) + logger.Noticef("Cannot remove binaries for %q: %v", s.InstanceName(), err1) } err2 := wrappers.RemoveSnapServices(s, meter) if err2 != nil { - logger.Noticef("Cannot remove services for %q: %v", s.Name(), err2) + logger.Noticef("Cannot remove services for %q: %v", s.InstanceName(), err2) } err3 := wrappers.RemoveSnapDesktopFiles(s) if err3 != nil { - logger.Noticef("Cannot remove desktop files for %q: %v", s.Name(), err3) + logger.Noticef("Cannot remove desktop files for %q: %v", s.InstanceName(), err3) } return firstErr(err1, err2, err3) diff --git a/overlord/snapstate/backend/mountunit.go b/overlord/snapstate/backend/mountunit.go index 41ca04dd99..af1b661b41 100644 --- a/overlord/snapstate/backend/mountunit.go +++ b/overlord/snapstate/backend/mountunit.go @@ -37,7 +37,7 @@ func addMountUnit(s *snap.Info, meter progress.Meter) error { whereDir := dirs.StripRootDir(s.MountDir()) sysd := systemd.New(dirs.GlobalRootDir, meter) - mountUnitName, err := sysd.WriteMountUnitFile(s.Name(), s.Revision.String(), squashfsPath, whereDir, "squashfs") + mountUnitName, err := sysd.WriteMountUnitFile(s.InstanceName(), s.Revision.String(), squashfsPath, whereDir, "squashfs") if err != nil { return err } diff --git a/overlord/snapstate/backend_test.go b/overlord/snapstate/backend_test.go index 5f50cd6db6..56f49ed437 100644 --- a/overlord/snapstate/backend_test.go +++ b/overlord/snapstate/backend_test.go @@ -612,7 +612,7 @@ apps: func (f *fakeSnappyBackend) ClearTrashedData(si *snap.Info) { f.ops = append(f.ops, fakeOp{ op: "cleanup-trash", - name: si.Name(), + name: si.InstanceName(), revno: si.Revision, }) } diff --git a/overlord/snapstate/booted_test.go b/overlord/snapstate/booted_test.go index d06d9b7ba1..3a02a64cb2 100644 --- a/overlord/snapstate/booted_test.go +++ b/overlord/snapstate/booted_test.go @@ -28,7 +28,6 @@ import ( . "gopkg.in/check.v1" - "github.com/snapcore/snapd/asserts" "github.com/snapcore/snapd/boot/boottest" "github.com/snapcore/snapd/dirs" "github.com/snapcore/snapd/overlord" @@ -84,9 +83,7 @@ func (bs *bootedSuite) SetUpTest(c *C) { snapstate.AutoAliases = func(*state.State, *snap.Info) (map[string]string, error) { return nil, nil } - snapstate.Model = func(*state.State) (*asserts.Model, error) { - return nil, nil - } + snapstate.MockModel() } func (bs *bootedSuite) TearDownTest(c *C) { diff --git a/overlord/snapstate/check_snap.go b/overlord/snapstate/check_snap.go index d6583857ff..a041da5fc4 100644 --- a/overlord/snapstate/check_snap.go +++ b/overlord/snapstate/check_snap.go @@ -58,7 +58,7 @@ func checkAssumes(si *snap.Info) error { if release.OnClassic { hint = "try to update snapd and refresh the core snap" } - return fmt.Errorf("snap %q assumes unsupported features: %s (%s)", si.Name(), strings.Join(missing, ", "), hint) + return fmt.Errorf("snap %q assumes unsupported features: %s (%s)", si.InstanceName(), strings.Join(missing, ", "), hint) } return nil } @@ -137,11 +137,11 @@ func validateFlagsForInfo(info *snap.Info, snapst *SnapState, flags Flags) error return nil } return &SnapNeedsDevModeError{ - Snap: info.Name(), + Snap: info.InstanceName(), } case snap.ClassicConfinement: if !release.OnClassic { - return &SnapNeedsClassicSystemError{Snap: info.Name()} + return &SnapNeedsClassicSystemError{Snap: info.InstanceName()} } if flags.Classic { @@ -153,7 +153,7 @@ func validateFlagsForInfo(info *snap.Info, snapst *SnapState, flags Flags) error } return &SnapNeedsClassicError{ - Snap: info.Name(), + Snap: info.InstanceName(), } default: return fmt.Errorf("unknown confinement %q", c) @@ -170,7 +170,7 @@ func validateInfoAndFlags(info *snap.Info, snapst *SnapState, flags Flags) error // verify we have a valid architecture if !arch.IsSupportedArchitecture(info.Architectures) { - return fmt.Errorf("snap %q supported architectures (%s) are incompatible with this system (%s)", info.Name(), strings.Join(info.Architectures, ", "), arch.UbuntuArchitecture()) + return fmt.Errorf("snap %q supported architectures (%s) are incompatible with this system (%s)", info.InstanceName(), strings.Join(info.Architectures, ", "), arch.UbuntuArchitecture()) } // check assumes @@ -263,13 +263,14 @@ func checkCoreName(st *state.State, snapInfo, curInfo *snap.Info, flags Flags) e // transition we will end up with not connected interface // connections in the "core" snap. But the transition will // kick in automatically quickly so an extra flag is overkill. - if snapInfo.Name() == "core" && core.Name() == "ubuntu-core" { + // TODO parallel-install: use instance name + if snapInfo.InstanceName() == "core" && core.InstanceName() == "ubuntu-core" { return nil } // but generally do not allow to have two cores installed - if core.Name() != snapInfo.Name() { - return fmt.Errorf("cannot install core snap %q when core snap %q is already present", snapInfo.Name(), core.Name()) + if core.InstanceName() != snapInfo.InstanceName() { + return fmt.Errorf("cannot install core snap %q when core snap %q is already present", snapInfo.InstanceName(), core.InstanceName()) } return nil @@ -312,7 +313,7 @@ func checkGadgetOrKernel(st *state.State, snapInfo, curInfo *snap.Info, flags Fl return fmt.Errorf("cannot replace signed %s snap with an unasserted one", kind) } - if currentSnap.Name() != snapInfo.Name() { + if currentSnap.InstanceName() != snapInfo.InstanceName() { return fmt.Errorf("cannot replace %s snap with a different one", kind) } diff --git a/overlord/snapstate/check_snap_test.go b/overlord/snapstate/check_snap_test.go index 2d189c0886..0c137a7a55 100644 --- a/overlord/snapstate/check_snap_test.go +++ b/overlord/snapstate/check_snap_test.go @@ -194,7 +194,7 @@ version: 1.0` checkCbCalled := false checkCb := func(st *state.State, s, cur *snap.Info, flags snapstate.Flags) error { - c.Assert(s.Name(), Equals, "foo") + c.Assert(s.InstanceName(), Equals, "foo") c.Assert(s.SnapID, Equals, "snap-id") checkCbCalled = true return nil diff --git a/overlord/snapstate/export_test.go b/overlord/snapstate/export_test.go index 6980cdff7d..6f3f8a821a 100644 --- a/overlord/snapstate/export_test.go +++ b/overlord/snapstate/export_test.go @@ -21,11 +21,13 @@ package snapstate import ( "errors" + "fmt" "sort" "time" "gopkg.in/tomb.v2" + "github.com/snapcore/snapd/asserts" "github.com/snapcore/snapd/overlord/state" "github.com/snapcore/snapd/snap" ) @@ -193,3 +195,44 @@ func ByKindOrder(snaps ...*snap.Info) []*snap.Info { sort.Sort(byKind(snaps)) return snaps } + +func MockModelWithBase(baseName string) (restore func()) { + return mockModel(baseName) +} + +func MockModel() (restore func()) { + return mockModel("") +} + +func mockModel(baseName string) (restore func()) { + oldModel := Model + + base := "" + if baseName != "" { + base = fmt.Sprintf("\nbase: %s", baseName) + } + mod := fmt.Sprintf(`type: model +authority-id: brand +series: 16 +brand-id: brand +model: baz-3000 +architecture: armhf +gadget: brand-gadget +kernel: kernel%s +timestamp: 2018-01-01T08:00:00+00:00 +sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij + +AXNpZw== +`, base) + a, err := asserts.Decode([]byte(mod)) + if err != nil { + panic(err) + } + + Model = func(*state.State) (*asserts.Model, error) { + return a.(*asserts.Model), nil + } + return func() { + Model = oldModel + } +} diff --git a/overlord/snapstate/handlers.go b/overlord/snapstate/handlers.go index ae70ebae73..42971472ff 100644 --- a/overlord/snapstate/handlers.go +++ b/overlord/snapstate/handlers.go @@ -821,17 +821,39 @@ func (m *SnapManager) doLinkSnap(t *state.Task, _ *tomb.Tomb) error { return nil } -// maybeRestart will schedule a reboot or restart as needed for the just linked -// snap with info if it's a core or kernel snap. +// maybeRestart will schedule a reboot or restart as needed for the +// just linked snap with info if it's a core or snapd or kernel snap. func maybeRestart(t *state.Task, info *snap.Info) { st := t.State() - if release.OnClassic && info.Type == snap.TypeOS { - t.Logf("Requested daemon restart.") - st.RequestRestart(state.RestartDaemon) + + // TODO: once classic uses the snapd snap we need to restart + // here too + if release.OnClassic { + if info.Type == snap.TypeOS { + t.Logf("Requested daemon restart.") + st.RequestRestart(state.RestartDaemon) + } + return } - if !release.OnClassic && boot.KernelOsBaseRebootRequired(info) { + + // On a core system we may need a full reboot if + // core/base or the kernel changes. + if boot.ChangeRequiresReboot(info) { t.Logf("Requested system restart.") st.RequestRestart(state.RestartSystem) + return + } + + // On core systems that use a base snap we need to restart + // snapd when the snapd snap changes. + model, err := Model(st) + if err != nil { + logger.Noticef("cannot get model assertion: %v", model) + return + } + if model.Base() != "" && info.InstanceName() == "snapd" { + t.Logf("Requested daemon restart (snapd snap).") + st.RequestRestart(state.RestartDaemon) } } diff --git a/overlord/snapstate/handlers_aliasesv2_test.go b/overlord/snapstate/handlers_aliasesv2_test.go index 4c640b5ada..c131649a01 100644 --- a/overlord/snapstate/handlers_aliasesv2_test.go +++ b/overlord/snapstate/handlers_aliasesv2_test.go @@ -34,7 +34,7 @@ func (s *snapmgrTestSuite) TestDoSetAutoAliases(c *C) { defer s.state.Unlock() snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - c.Check(info.Name(), Equals, "alias-snap") + c.Check(info.InstanceName(), Equals, "alias-snap") return map[string]string{ "alias1": "cmd1", "alias2": "cmd2", @@ -89,7 +89,7 @@ func (s *snapmgrTestSuite) TestDoSetAutoAliasesFirstInstall(c *C) { defer s.state.Unlock() snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - c.Check(info.Name(), Equals, "alias-snap") + c.Check(info.InstanceName(), Equals, "alias-snap") return map[string]string{ "alias1": "cmd1", "alias2": "cmd2", @@ -139,7 +139,7 @@ func (s *snapmgrTestSuite) TestDoUndoSetAutoAliases(c *C) { defer s.state.Unlock() snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - c.Check(info.Name(), Equals, "alias-snap") + c.Check(info.InstanceName(), Equals, "alias-snap") return map[string]string{ "alias1": "cmd1", "alias2": "cmd2", @@ -200,7 +200,7 @@ func (s *snapmgrTestSuite) TestDoSetAutoAliasesConflict(c *C) { defer s.state.Unlock() snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - c.Check(info.Name(), Equals, "alias-snap") + c.Check(info.InstanceName(), Equals, "alias-snap") return map[string]string{ "alias1": "cmd1", "alias2": "cmd2", @@ -256,7 +256,7 @@ func (s *snapmgrTestSuite) TestDoUndoSetAutoAliasesConflict(c *C) { defer s.state.Unlock() snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - c.Check(info.Name(), Equals, "alias-snap") + c.Check(info.InstanceName(), Equals, "alias-snap") return map[string]string{ "alias1": "cmd1", "alias2": "cmd2", @@ -353,7 +353,7 @@ func (s *snapmgrTestSuite) TestDoSetAutoAliasesFirstInstallUnaliased(c *C) { defer s.state.Unlock() snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - c.Check(info.Name(), Equals, "alias-snap") + c.Check(info.InstanceName(), Equals, "alias-snap") return map[string]string{ "alias1": "cmd1", "alias2": "cmd2", @@ -404,7 +404,7 @@ func (s *snapmgrTestSuite) TestDoUndoSetAutoAliasesFirstInstallUnaliased(c *C) { defer s.state.Unlock() snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - c.Check(info.Name(), Equals, "alias-snap") + c.Check(info.InstanceName(), Equals, "alias-snap") return map[string]string{ "alias1": "cmd1", "alias2": "cmd2", @@ -938,7 +938,7 @@ func (s *snapmgrTestSuite) TestDoRefreshAliases(c *C) { defer s.state.Unlock() snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - c.Check(info.Name(), Equals, "alias-snap") + c.Check(info.InstanceName(), Equals, "alias-snap") return map[string]string{ "alias1": "cmd1", "alias2": "cmd2", @@ -1011,7 +1011,7 @@ func (s *snapmgrTestSuite) TestDoUndoRefreshAliases(c *C) { defer s.state.Unlock() snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - c.Check(info.Name(), Equals, "alias-snap") + c.Check(info.InstanceName(), Equals, "alias-snap") return map[string]string{ "alias1": "cmd1", "alias2": "cmd2", @@ -1101,7 +1101,7 @@ func (s *snapmgrTestSuite) TestDoUndoRefreshAliasesFromEmpty(c *C) { defer s.state.Unlock() snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - c.Check(info.Name(), Equals, "alias-snap") + c.Check(info.InstanceName(), Equals, "alias-snap") return map[string]string{ "alias1": "cmd1", "alias2": "cmd2", @@ -1176,7 +1176,7 @@ func (s *snapmgrTestSuite) TestDoRefreshAliasesPending(c *C) { defer s.state.Unlock() snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - c.Check(info.Name(), Equals, "alias-snap") + c.Check(info.InstanceName(), Equals, "alias-snap") return map[string]string{ "alias1": "cmd1", "alias2": "cmd2", @@ -1235,7 +1235,7 @@ func (s *snapmgrTestSuite) TestDoUndoRefreshAliasesPending(c *C) { defer s.state.Unlock() snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - c.Check(info.Name(), Equals, "alias-snap") + c.Check(info.InstanceName(), Equals, "alias-snap") return map[string]string{ "alias1": "cmd1", "alias2": "cmd2", @@ -1300,7 +1300,7 @@ func (s *snapmgrTestSuite) TestDoRefreshAliasesConflict(c *C) { defer s.state.Unlock() snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - c.Check(info.Name(), Equals, "alias-snap") + c.Check(info.InstanceName(), Equals, "alias-snap") return map[string]string{ "alias1": "cmd1", "alias2": "cmd2", @@ -1354,7 +1354,7 @@ func (s *snapmgrTestSuite) TestDoUndoRefreshAliasesConflict(c *C) { defer s.state.Unlock() snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - c.Check(info.Name(), Equals, "alias-snap") + c.Check(info.InstanceName(), Equals, "alias-snap") return map[string]string{ "alias1": "cmd1", "alias2": "cmd2", diff --git a/overlord/snapstate/handlers_link_test.go b/overlord/snapstate/handlers_link_test.go index 70a165d259..d4ad443131 100644 --- a/overlord/snapstate/handlers_link_test.go +++ b/overlord/snapstate/handlers_link_test.go @@ -82,6 +82,8 @@ func (s *linkSnapSuite) SetUpTest(c *C) { resetReadInfo() dirs.SetRootDir("/") } + + snapstate.MockModel() } func (s *linkSnapSuite) TearDownTest(c *C) { @@ -359,6 +361,118 @@ func (s *linkSnapSuite) TestDoLinkSnapSuccessCoreRestarts(c *C) { c.Check(t.Log()[0], Matches, `.*INFO Requested daemon restart\.`) } +func (s *linkSnapSuite) TestDoLinkSnapSuccessSnapdRestartsOnCoreWithBase(c *C) { + restore := release.MockOnClassic(false) + defer restore() + + restore = snapstate.MockModelWithBase("core18") + defer restore() + + s.state.Lock() + si := &snap.SideInfo{ + RealName: "snapd", + Revision: snap.R(22), + } + t := s.state.NewTask("link-snap", "test") + t.Set("snap-setup", &snapstate.SnapSetup{ + SideInfo: si, + }) + s.state.NewChange("dummy", "...").AddTask(t) + + s.state.Unlock() + + s.snapmgr.Ensure() + s.snapmgr.Wait() + + s.state.Lock() + defer s.state.Unlock() + + var snapst snapstate.SnapState + err := snapstate.Get(s.state, "snapd", &snapst) + c.Assert(err, IsNil) + + typ, err := snapst.Type() + c.Check(err, IsNil) + c.Check(typ, Equals, snap.TypeApp) + + c.Check(t.Status(), Equals, state.DoneStatus) + c.Check(s.stateBackend.restartRequested, DeepEquals, []state.RestartType{state.RestartDaemon}) + c.Check(t.Log(), HasLen, 1) + c.Check(t.Log()[0], Matches, `.*INFO Requested daemon restart \(snapd snap\)\.`) +} + +func (s *linkSnapSuite) TestDoLinkSnapSuccessSnapdNoRestartWithoutBase(c *C) { + restore := release.MockOnClassic(false) + defer restore() + + s.state.Lock() + si := &snap.SideInfo{ + RealName: "snapd", + Revision: snap.R(22), + } + t := s.state.NewTask("link-snap", "test") + t.Set("snap-setup", &snapstate.SnapSetup{ + SideInfo: si, + }) + s.state.NewChange("dummy", "...").AddTask(t) + + s.state.Unlock() + + s.snapmgr.Ensure() + s.snapmgr.Wait() + + s.state.Lock() + defer s.state.Unlock() + + var snapst snapstate.SnapState + err := snapstate.Get(s.state, "snapd", &snapst) + c.Assert(err, IsNil) + + typ, err := snapst.Type() + c.Check(err, IsNil) + c.Check(typ, Equals, snap.TypeApp) + + c.Check(t.Status(), Equals, state.DoneStatus) + c.Check(s.stateBackend.restartRequested, IsNil) + c.Check(t.Log(), HasLen, 0) +} + +func (s *linkSnapSuite) TestDoLinkSnapSuccessSnapdNoRestartOnClassic(c *C) { + restore := release.MockOnClassic(true) + defer restore() + + s.state.Lock() + si := &snap.SideInfo{ + RealName: "snapd", + Revision: snap.R(22), + } + t := s.state.NewTask("link-snap", "test") + t.Set("snap-setup", &snapstate.SnapSetup{ + SideInfo: si, + }) + s.state.NewChange("dummy", "...").AddTask(t) + + s.state.Unlock() + + s.snapmgr.Ensure() + s.snapmgr.Wait() + + s.state.Lock() + defer s.state.Unlock() + + var snapst snapstate.SnapState + err := snapstate.Get(s.state, "snapd", &snapst) + c.Assert(err, IsNil) + + typ, err := snapst.Type() + c.Check(err, IsNil) + c.Check(typ, Equals, snap.TypeApp) + + c.Check(t.Status(), Equals, state.DoneStatus) + c.Check(s.stateBackend.restartRequested, IsNil) + c.Check(t.Log(), HasLen, 0) +} + func (s *linkSnapSuite) TestDoUndoLinkSnapSequenceDidNotHaveCandidate(c *C) { s.state.Lock() defer s.state.Unlock() diff --git a/overlord/snapstate/snapstate.go b/overlord/snapstate/snapstate.go index e978814b2f..e3ec6936ce 100644 --- a/overlord/snapstate/snapstate.go +++ b/overlord/snapstate/snapstate.go @@ -78,6 +78,9 @@ func doInstall(st *state.State, snapst *SnapState, snapsup *SnapSetup, flags int } } + // TODO parallel-install: block parallel installation of core, kernel, + // gadget and snapd snaps + if err := CheckChangeConflict(st, snapsup.Name(), nil, snapst); err != nil { return nil, err } @@ -757,14 +760,14 @@ func doUpdate(st *state.State, names []string, updates []*snap.Info, params func if err := validateInfoAndFlags(update, snapst, flags); err != nil { if refreshAll { - logger.Noticef("cannot update %q: %v", update.Name(), err) + logger.Noticef("cannot update %q: %v", update.InstanceName(), err) continue } return nil, nil, err } if err := validateFeatureFlags(st, update); err != nil { if refreshAll { - logger.Noticef("cannot update %q: %v", update.Name(), err) + logger.Noticef("cannot update %q: %v", update.InstanceName(), err) continue } return nil, nil, err @@ -790,7 +793,7 @@ func doUpdate(st *state.State, names []string, updates []*snap.Info, params func if err != nil { if refreshAll { // doing "refresh all", just skip this snap - logger.Noticef("cannot refresh snap %q: %v", update.Name(), err) + logger.Noticef("cannot refresh snap %q: %v", update.InstanceName(), err) continue } return nil, nil, err @@ -804,7 +807,7 @@ func doUpdate(st *state.State, names []string, updates []*snap.Info, params func // prereq types come first in updates, we // also assume bases don't have hooks, otherwise // they would need to wait on core - prereqs[update.Name()] = ts + prereqs[update.InstanceName()] = ts } else { // prereqs were processed already, wait for // them as necessary for the other kind of @@ -815,7 +818,7 @@ func doUpdate(st *state.State, names []string, updates []*snap.Info, params func } } - scheduleUpdate(update.Name(), ts) + scheduleUpdate(update.InstanceName(), ts) tasksets = append(tasksets, ts) } @@ -934,7 +937,7 @@ func autoAliasesUpdate(st *state.State, names []string, updates []*snap.Info) (c // snaps with updates updating := make(map[string]bool, len(updates)) for _, info := range updates { - updating[info.Name()] = true + updating[info.InstanceName()] = true } // add explicitly auto-aliases only for snaps that are not updated @@ -1293,7 +1296,7 @@ func canRemove(si *snap.Info, snapst *SnapState, removeAll bool) bool { // // Once the ubuntu-core -> core transition has landed for some // time we can remove the two lines below. - if si.Name() == "ubuntu-core" && si.Type == snap.TypeOS { + if si.InstanceName() == "ubuntu-core" && si.Type == snap.TypeOS { return true } @@ -1306,7 +1309,7 @@ func canRemove(si *snap.Info, snapst *SnapState, removeAll bool) bool { // TODO: on classic likely let remove core even if active if it's only snap left. // never remove anything that is used for booting - if boot.InUse(si.Name(), si.Revision) { + if boot.InUse(si.InstanceName(), si.Revision) { return false } @@ -1820,13 +1823,13 @@ func CoreInfo(st *state.State) (*snap.Info, error) { // some systems have two cores: ubuntu-core/core // we always return "core" in this case if len(res) == 2 { - if res[0].Name() == defaultCoreSnapName && res[1].Name() == "ubuntu-core" { + if res[0].InstanceName() == defaultCoreSnapName && res[1].InstanceName() == "ubuntu-core" { return res[0], nil } - if res[0].Name() == "ubuntu-core" && res[1].Name() == defaultCoreSnapName { + if res[0].InstanceName() == "ubuntu-core" && res[1].InstanceName() == defaultCoreSnapName { return res[1], nil } - return nil, fmt.Errorf("unexpected cores %q and %q", res[0].Name(), res[1].Name()) + return nil, fmt.Errorf("unexpected cores %q and %q", res[0].InstanceName(), res[1].InstanceName()) } return nil, fmt.Errorf("unexpected number of cores, got %d", len(res)) @@ -1850,7 +1853,7 @@ func ConfigDefaults(st *state.State, snapName string) (map[string]interface{}, e if err != nil { return nil, err } - isCoreDefaults := core.Name() == snapName + isCoreDefaults := core.InstanceName() == snapName si := snapst.CurrentSideInfo() // core snaps can be addressed even without a snap-id via the special diff --git a/overlord/snapstate/snapstate_test.go b/overlord/snapstate/snapstate_test.go index 74c158f103..bd42dcb7cc 100644 --- a/overlord/snapstate/snapstate_test.go +++ b/overlord/snapstate/snapstate_test.go @@ -3821,7 +3821,7 @@ func (s *snapmgrTestSuite) TestUpdateManyAutoAliasesScenarios(c *C) { }) snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - switch info.Name() { + switch info.InstanceName() { case "some-snap": return map[string]string{"aliasA": "cmdA"}, nil case "other-snap": @@ -3964,7 +3964,7 @@ func (s *snapmgrTestSuite) TestUpdateOneAutoAliasesScenarios(c *C) { }) snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - switch info.Name() { + switch info.InstanceName() { case "some-snap": return map[string]string{"aliasA": "cmdA"}, nil case "other-snap": @@ -6715,7 +6715,7 @@ func (s *snapmgrQuerySuite) TestInfo(c *C) { info, err := snapstate.Info(st, "name1", snap.R(11)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "name1") + c.Check(info.InstanceName(), Equals, "name1") c.Check(info.Revision, Equals, snap.R(11)) c.Check(info.Summary(), Equals, "s11") c.Check(info.Version, Equals, "1.1") @@ -6734,7 +6734,7 @@ func (s *snapmgrQuerySuite) TestSnapStateCurrentInfo(c *C) { info, err := snapst.CurrentInfo() c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "name1") + c.Check(info.InstanceName(), Equals, "name1") c.Check(info.Revision, Equals, snap.R(12)) c.Check(info.Summary(), Equals, "s12") c.Check(info.Version, Equals, "1.2") @@ -6756,7 +6756,7 @@ func (s *snapmgrQuerySuite) TestCurrentInfo(c *C) { info, err := snapstate.CurrentInfo(st, "name1") c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "name1") + c.Check(info.InstanceName(), Equals, "name1") c.Check(info.Revision, Equals, snap.R(12)) } @@ -6779,7 +6779,7 @@ func (s *snapmgrQuerySuite) TestActiveInfos(c *C) { c.Check(infos, HasLen, 1) - c.Check(infos[0].Name(), Equals, "name1") + c.Check(infos[0].InstanceName(), Equals, "name1") c.Check(infos[0].Revision, Equals, snap.R(12)) c.Check(infos[0].Summary(), Equals, "s12") c.Check(infos[0].Version, Equals, "1.2") @@ -6830,7 +6830,7 @@ func (s *snapmgrQuerySuite) TestTypeInfo(c *C) { info, err := x.getInfo(st) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, x.snapName) + c.Check(info.InstanceName(), Equals, x.snapName) c.Check(info.Revision, Equals, snap.R(2)) c.Check(info.Version, Equals, x.snapName) c.Check(info.Type, Equals, x.snapType) @@ -6890,7 +6890,7 @@ func (s *snapmgrQuerySuite) TestTypeInfoCore(c *C) { c.Assert(err, ErrorMatches, t.errMatcher) } else { c.Assert(info, NotNil) - c.Check(info.Name(), Equals, t.expectedSnap, Commentf("(%d) test %q %v", testNr, t.expectedSnap, t.snapNames)) + c.Check(info.InstanceName(), Equals, t.expectedSnap, Commentf("(%d) test %q %v", testNr, t.expectedSnap, t.snapNames)) c.Check(info.Type, Equals, snap.TypeOS) } } @@ -6941,7 +6941,7 @@ func (s *snapmgrQuerySuite) TestAll(c *C) { info12, err := snap.ReadInfo("name1", snapst.CurrentSideInfo()) c.Assert(err, IsNil) - c.Check(info12.Name(), Equals, "name1") + c.Check(info12.InstanceName(), Equals, "name1") c.Check(info12.Revision, Equals, snap.R(12)) c.Check(info12.Summary(), Equals, "s12") c.Check(info12.Version, Equals, "1.2") @@ -6950,7 +6950,7 @@ func (s *snapmgrQuerySuite) TestAll(c *C) { info11, err := snap.ReadInfo("name1", snapst.Sequence[0]) c.Assert(err, IsNil) - c.Check(info11.Name(), Equals, "name1") + c.Check(info11.InstanceName(), Equals, "name1") c.Check(info11.Revision, Equals, snap.R(11)) c.Check(info11.Version, Equals, "1.1") } @@ -8587,7 +8587,7 @@ func (s *snapmgrTestSuite) TestEnsureAliasesV2(c *C) { defer s.state.Unlock() snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - switch info.Name() { + switch info.InstanceName() { case "alias-snap": return map[string]string{ "alias1": "cmd1", @@ -8655,7 +8655,7 @@ func (s *snapmgrTestSuite) TestEnsureAliasesV2SnapDisabled(c *C) { defer s.state.Unlock() snapstate.AutoAliases = func(st *state.State, info *snap.Info) (map[string]string, error) { - switch info.Name() { + switch info.InstanceName() { case "alias-snap": return map[string]string{ "alias1": "cmd1", @@ -9253,7 +9253,7 @@ func (s contentStore) SnapAction(ctx context.Context, currentSnaps []*store.Curr panic("expected to be queried for install of only one snap at a time") } info := snaps[0] - switch info.Name() { + switch info.InstanceName() { case "snap-content-plug": info.Plugs = map[string]*snap.PlugInfo{ "some-plug": { diff --git a/overlord/snapstate/storehelpers.go b/overlord/snapstate/storehelpers.go index 772148e5d9..5aa69c7485 100644 --- a/overlord/snapstate/storehelpers.go +++ b/overlord/snapstate/storehelpers.go @@ -89,7 +89,8 @@ func installInfo(st *state.State, name, channel string, revision snap.Revision, action := &store.SnapAction{ Action: "install", - Name: name, + // TODO parallel-install: verify use of correct name + Name: name, // the desired channel Channel: channel, // the desired revision @@ -153,7 +154,8 @@ func updateInfo(st *state.State, snapst *SnapState, opts *updateInfoOpts, userID if curInfo.SnapID == "" { // amend action.Action = "install" - action.Name = curInfo.Name() + // TODO parallel-install: verify use of correct name + action.Name = curInfo.InstanceName() } theStore := Store(st) @@ -161,7 +163,7 @@ func updateInfo(st *state.State, snapst *SnapState, opts *updateInfoOpts, userID res, err := theStore.SnapAction(context.TODO(), curSnaps, []*store.SnapAction{action}, user, nil) st.Lock() - return singleActionResult(curInfo.Name(), action.Action, res, err) + return singleActionResult(curInfo.InstanceName(), action.Action, res, err) } func preUpdateInfo(st *state.State, snapst *SnapState, amend bool, userID int) (*snap.Info, *auth.UserState, error) { @@ -248,7 +250,7 @@ func updateToRevisionInfo(st *state.State, snapst *SnapState, revision snap.Revi res, err := theStore.SnapAction(context.TODO(), curSnaps, []*store.SnapAction{action}, user, nil) st.Lock() - return singleActionResult(curInfo.Name(), action.Action, res, err) + return singleActionResult(curInfo.InstanceName(), action.Action, res, err) } func currentSnaps(st *state.State) ([]*store.CurrentSnap, error) { diff --git a/snap/broken.go b/snap/broken.go index 21c8ef73ba..d9434e8565 100644 --- a/snap/broken.go +++ b/snap/broken.go @@ -74,7 +74,7 @@ func GuessAppsForBroken(info *Info) map[string]*AppInfo { // was not validated before. To avoid a flag day and any potential issues, // transparently rename the two clashing plugs by appending the "-plug" suffix. func (info *Info) renameClashingCorePlugs() { - if info.Name() == "core" && info.Type == TypeOS { + if info.InstanceName() == "core" && info.Type == TypeOS { for _, plugName := range []string{"network-bind", "core-support"} { info.renamePlug(plugName, plugName+"-plug") } diff --git a/snap/container.go b/snap/container.go index a518d5b899..f6c019b783 100644 --- a/snap/container.go +++ b/snap/container.go @@ -201,7 +201,8 @@ func ValidateContainer(c Container, s *Info, logf func(format string, v ...inter if needsrx[path] || mode.IsDir() { if mode.Perm()&0555 != 0555 { - logf("in snap %q: %q should be world-readable and executable, and isn't: %s", s.Name(), path, mode) + // TODO parallel-install: use of proper instance/store name + logf("in snap %q: %q should be world-readable and executable, and isn't: %s", s.InstanceName(), path, mode) hasBadModes = true } } else { @@ -213,19 +214,22 @@ func ValidateContainer(c Container, s *Info, logf func(format string, v ...inter // more than anything else, not worth it IMHO (as I can't // imagine this happening by accident). if mode&(os.ModeDir|os.ModeNamedPipe|os.ModeSocket|os.ModeDevice) != 0 { - logf("in snap %q: %q should be a regular file (or a symlink) and isn't", s.Name(), path) + // TODO parallel-install: use of proper instance/store name + logf("in snap %q: %q should be a regular file (or a symlink) and isn't", s.InstanceName(), path) hasBadModes = true } } if needsx[path] || strings.HasPrefix(path, "meta/hooks/") { if mode.Perm()&0111 == 0 { - logf("in snap %q: %q should be executable, and isn't: %s", s.Name(), path, mode) + // TODO parallel-install: use of proper instance/store name + logf("in snap %q: %q should be executable, and isn't: %s", s.InstanceName(), path, mode) hasBadModes = true } } else { // in needsr, or under meta but not a hook if mode.Perm()&0444 != 0444 { - logf("in snap %q: %q should be world-readable, and isn't: %s", s.Name(), path, mode) + // TODO parallel-install: use of proper instance/store name + logf("in snap %q: %q should be world-readable, and isn't: %s", s.InstanceName(), path, mode) hasBadModes = true } } @@ -239,7 +243,8 @@ func ValidateContainer(c Container, s *Info, logf func(format string, v ...inter for _, needs := range []map[string]bool{needsx, needsrx, needsr} { for path := range needs { if !seen[path] { - logf("in snap %q: path %q does not exist", s.Name(), path) + // TODO parallel-install: use of proper instance/store name + logf("in snap %q: path %q does not exist", s.InstanceName(), path) } } } diff --git a/snap/info.go b/snap/info.go index 8f52ca4d45..344f4012d1 100644 --- a/snap/info.go +++ b/snap/info.go @@ -38,8 +38,8 @@ import ( // PlaceInfo offers all the information about where a snap and its data are located and exposed in the filesystem. type PlaceInfo interface { - // Name returns the name of the snap. - Name() string + // InstanceName returns the name of the snap. + InstanceName() string // MountDir returns the base directory of the snap. MountDir() string @@ -253,8 +253,15 @@ type ChannelSnapInfo struct { Size int64 `json:"size"` } -// Name returns the blessed name for the snap. -func (s *Info) Name() string { +// InstanceName returns the blessed name of the snap decorated with instance +// key, if any. +func (s *Info) InstanceName() string { + // TODO parallel-install: include instance key + return s.StoreName() +} + +// StoreName returns the global blessed name of the snap. +func (s *Info) StoreName() string { if s.RealName != "" { return s.RealName } @@ -287,12 +294,12 @@ func (s *Info) Description() string { // MountDir returns the base directory of the snap where it gets mounted. func (s *Info) MountDir() string { - return MountDir(s.Name(), s.Revision) + return MountDir(s.InstanceName(), s.Revision) } // MountFile returns the path where the snap file that is mounted is installed. func (s *Info) MountFile() string { - return MountFile(s.Name(), s.Revision) + return MountFile(s.InstanceName(), s.Revision) } // HooksDir returns the directory containing the snap's hooks. @@ -302,42 +309,42 @@ func (s *Info) HooksDir() string { // DataDir returns the data directory of the snap. func (s *Info) DataDir() string { - return filepath.Join(dirs.SnapDataDir, s.Name(), s.Revision.String()) + return filepath.Join(dirs.SnapDataDir, s.InstanceName(), s.Revision.String()) } // UserDataDir returns the user-specific data directory of the snap. func (s *Info) UserDataDir(home string) string { - return filepath.Join(home, dirs.UserHomeSnapDir, s.Name(), s.Revision.String()) + return filepath.Join(home, dirs.UserHomeSnapDir, s.InstanceName(), s.Revision.String()) } // UserCommonDataDir returns the user-specific data directory common across revision of the snap. func (s *Info) UserCommonDataDir(home string) string { - return filepath.Join(home, dirs.UserHomeSnapDir, s.Name(), "common") + return filepath.Join(home, dirs.UserHomeSnapDir, s.InstanceName(), "common") } // CommonDataDir returns the data directory common across revisions of the snap. func (s *Info) CommonDataDir() string { - return filepath.Join(dirs.SnapDataDir, s.Name(), "common") + return filepath.Join(dirs.SnapDataDir, s.InstanceName(), "common") } // DataHomeDir returns the per user data directory of the snap. func (s *Info) DataHomeDir() string { - return filepath.Join(dirs.SnapDataHomeGlob, s.Name(), s.Revision.String()) + return filepath.Join(dirs.SnapDataHomeGlob, s.InstanceName(), s.Revision.String()) } // CommonDataHomeDir returns the per user data directory common across revisions of the snap. func (s *Info) CommonDataHomeDir() string { - return filepath.Join(dirs.SnapDataHomeGlob, s.Name(), "common") + return filepath.Join(dirs.SnapDataHomeGlob, s.InstanceName(), "common") } // UserXdgRuntimeDir returns the XDG_RUNTIME_DIR directory of the snap for a particular user. func (s *Info) UserXdgRuntimeDir(euid sys.UserID) string { - return filepath.Join("/run/user", fmt.Sprintf("%d/snap.%s", euid, s.Name())) + return filepath.Join("/run/user", fmt.Sprintf("%d/snap.%s", euid, s.InstanceName())) } // XdgRuntimeDirs returns the XDG_RUNTIME_DIR directories for all users of the snap. func (s *Info) XdgRuntimeDirs() string { - return filepath.Join(dirs.XdgRuntimeDirGlob, fmt.Sprintf("snap.%s", s.Name())) + return filepath.Join(dirs.XdgRuntimeDirGlob, fmt.Sprintf("snap.%s", s.InstanceName())) } // NeedsDevMode returns whether the snap needs devmode. @@ -372,7 +379,8 @@ func (s *Info) ExpandSnapVariables(path string) string { // inside the mount namespace snap-confine creates and there we will // always have a /snap directory available regardless if the system // we're running on supports this or not. - return filepath.Join(dirs.CoreSnapMountDir, s.Name(), s.Revision.String()) + // TODO parallel-install: use of proper instance/store name + return filepath.Join(dirs.CoreSnapMountDir, s.InstanceName(), s.Revision.String()) case "SNAP_DATA": return s.DataDir() case "SNAP_COMMON": @@ -406,7 +414,7 @@ func BadInterfacesSummary(snapInfo *Info) string { inverted[reason] = append(inverted[reason], name) } var buf bytes.Buffer - fmt.Fprintf(&buf, "snap %q has bad plugs or slots: ", snapInfo.Name()) + fmt.Fprintf(&buf, "snap %q has bad plugs or slots: ", snapInfo.InstanceName()) reasons := make([]string, 0, len(inverted)) for reason := range inverted { reasons = append(reasons, reason) @@ -511,7 +519,7 @@ func getAttribute(snapName string, ifaceName string, attrs map[string]interface{ } func (plug *PlugInfo) Attr(key string, val interface{}) error { - return getAttribute(plug.Snap.Name(), plug.Interface, plug.Attrs, key, val) + return getAttribute(plug.Snap.InstanceName(), plug.Interface, plug.Attrs, key, val) } func (plug *PlugInfo) Lookup(key string) (interface{}, bool) { @@ -533,11 +541,11 @@ func (plug *PlugInfo) SecurityTags() []string { // String returns the representation of the plug as snap:plug string. func (plug *PlugInfo) String() string { - return fmt.Sprintf("%s:%s", plug.Snap.Name(), plug.Name) + return fmt.Sprintf("%s:%s", plug.Snap.InstanceName(), plug.Name) } func (slot *SlotInfo) Attr(key string, val interface{}) error { - return getAttribute(slot.Snap.Name(), slot.Interface, slot.Attrs, key, val) + return getAttribute(slot.Snap.InstanceName(), slot.Interface, slot.Attrs, key, val) } func (slot *SlotInfo) Lookup(key string) (interface{}, bool) { @@ -559,7 +567,7 @@ func (slot *SlotInfo) SecurityTags() []string { // String returns the representation of the slot as snap:slot string. func (slot *SlotInfo) String() string { - return fmt.Sprintf("%s:%s", slot.Snap.Name(), slot.Name) + return fmt.Sprintf("%s:%s", slot.Snap.InstanceName(), slot.Name) } // SlotInfo provides information about a slot. @@ -685,7 +693,7 @@ func (timer *TimerInfo) File() string { } func (app *AppInfo) String() string { - return JoinSnapApp(app.Snap.Name(), app.Name) + return JoinSnapApp(app.Snap.InstanceName(), app.Name) } // SecurityTag returns application-specific security tag. @@ -693,32 +701,33 @@ func (app *AppInfo) String() string { // Security tags are used by various security subsystems as "profile names" and // sometimes also as a part of the file name. func (app *AppInfo) SecurityTag() string { - return AppSecurityTag(app.Snap.Name(), app.Name) + return AppSecurityTag(app.Snap.InstanceName(), app.Name) } // DesktopFile returns the path to the installed optional desktop file for the application. func (app *AppInfo) DesktopFile() string { - return filepath.Join(dirs.SnapDesktopFilesDir, fmt.Sprintf("%s_%s.desktop", app.Snap.Name(), app.Name)) + return filepath.Join(dirs.SnapDesktopFilesDir, fmt.Sprintf("%s_%s.desktop", app.Snap.InstanceName(), app.Name)) } // WrapperPath returns the path to wrapper invoking the app binary. func (app *AppInfo) WrapperPath() string { - return filepath.Join(dirs.SnapBinariesDir, JoinSnapApp(app.Snap.Name(), app.Name)) + return filepath.Join(dirs.SnapBinariesDir, JoinSnapApp(app.Snap.InstanceName(), app.Name)) } // CompleterPath returns the path to the completer snippet for the app binary. func (app *AppInfo) CompleterPath() string { - return filepath.Join(dirs.CompletersDir, JoinSnapApp(app.Snap.Name(), app.Name)) + return filepath.Join(dirs.CompletersDir, JoinSnapApp(app.Snap.InstanceName(), app.Name)) } func (app *AppInfo) launcherCommand(command string) string { if command != "" { command = " " + command } - if app.Name == app.Snap.Name() { + // TODO parallel-install: use of proper instance/store name + if app.Name == app.Snap.InstanceName() { return fmt.Sprintf("/usr/bin/snap run%s %s", command, app.Name) } - return fmt.Sprintf("/usr/bin/snap run%s %s.%s", command, app.Snap.Name(), app.Name) + return fmt.Sprintf("/usr/bin/snap run%s %s.%s", command, app.Snap.InstanceName(), app.Name) } // LauncherCommand returns the launcher command line to use when invoking the app binary. @@ -774,7 +783,7 @@ func (app *AppInfo) IsService() bool { // Security tags are used by various security subsystems as "profile names" and // sometimes also as a part of the file name. func (hook *HookInfo) SecurityTag() string { - return HookSecurityTag(hook.Snap.Name(), hook.Name) + return HookSecurityTag(hook.Snap.InstanceName(), hook.Name) } // Env returns the hook-specific environment overrides diff --git a/snap/info_snap_yaml_test.go b/snap/info_snap_yaml_test.go index 138ccd9d08..5e4598e816 100644 --- a/snap/info_snap_yaml_test.go +++ b/snap/info_snap_yaml_test.go @@ -59,7 +59,7 @@ func (s *InfoSnapYamlTestSuite) TearDownTest(c *C) { func (s *InfoSnapYamlTestSuite) TestSimple(c *C) { info, err := snap.InfoFromSnapYaml(mockYaml) c.Assert(err, IsNil) - c.Assert(info.Name(), Equals, "foo") + c.Assert(info.InstanceName(), Equals, "foo") c.Assert(info.Version, Equals, "1.0") c.Assert(info.Type, Equals, snap.TypeApp) } @@ -111,7 +111,7 @@ plugs: network-client: `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 1) c.Check(info.Slots, HasLen, 0) c.Assert(info.Plugs["network-client"], DeepEquals, &snap.PlugInfo{ @@ -129,7 +129,7 @@ plugs: net: network-client `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 1) c.Check(info.Slots, HasLen, 0) c.Assert(info.Plugs["net"], DeepEquals, &snap.PlugInfo{ @@ -148,7 +148,7 @@ plugs: interface: network-client `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 1) c.Check(info.Slots, HasLen, 0) c.Assert(info.Plugs["net"], DeepEquals, &snap.PlugInfo{ @@ -168,7 +168,7 @@ plugs: ipv6-aware: true `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 1) c.Check(info.Slots, HasLen, 0) c.Assert(info.Plugs["net"], DeepEquals, &snap.PlugInfo{ @@ -193,7 +193,7 @@ plugs: b: B `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 1) c.Check(info.Slots, HasLen, 0) c.Assert(info.Plugs["iface"], DeepEquals, &snap.PlugInfo{ @@ -221,7 +221,7 @@ plugs: attr: 2 `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 1) c.Check(info.Slots, HasLen, 0) c.Assert(info.Plugs["net"], DeepEquals, &snap.PlugInfo{ @@ -242,7 +242,7 @@ apps: app: `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 1) c.Check(info.Slots, HasLen, 0) c.Check(info.Apps, HasLen, 1) @@ -274,7 +274,7 @@ apps: without-plug: `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 1) c.Check(info.Slots, HasLen, 0) c.Check(info.Apps, HasLen, 2) @@ -311,7 +311,7 @@ apps: plugs: ["net"] `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 1) c.Check(info.Slots, HasLen, 0) c.Check(info.Apps, HasLen, 1) @@ -339,7 +339,7 @@ apps: plugs: ["network-client"] `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 1) c.Check(info.Slots, HasLen, 0) c.Check(info.Apps, HasLen, 1) @@ -367,7 +367,7 @@ plugs: ipv6-aware: true `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 1) c.Check(info.Slots, HasLen, 0) c.Check(info.Apps, HasLen, 0) @@ -388,7 +388,7 @@ plugs: label: Disk I/O indicator `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 1) c.Check(info.Slots, HasLen, 0) c.Check(info.Apps, HasLen, 0) @@ -492,7 +492,7 @@ slots: network-client: `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 0) c.Check(info.Slots, HasLen, 1) c.Assert(info.Slots["network-client"], DeepEquals, &snap.SlotInfo{ @@ -510,7 +510,7 @@ slots: net: network-client `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 0) c.Check(info.Slots, HasLen, 1) c.Assert(info.Slots["net"], DeepEquals, &snap.SlotInfo{ @@ -529,7 +529,7 @@ slots: interface: network-client `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 0) c.Check(info.Slots, HasLen, 1) c.Assert(info.Slots["net"], DeepEquals, &snap.SlotInfo{ @@ -549,7 +549,7 @@ slots: ipv6-aware: true `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 0) c.Check(info.Slots, HasLen, 1) c.Assert(info.Slots["net"], DeepEquals, &snap.SlotInfo{ @@ -573,7 +573,7 @@ slots: a: "A" `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 0) c.Check(info.Slots, HasLen, 1) c.Assert(info.Slots["iface"], DeepEquals, &snap.SlotInfo{ @@ -601,7 +601,7 @@ slots: attr: 2 `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 0) c.Check(info.Slots, HasLen, 1) c.Assert(info.Slots["net"], DeepEquals, &snap.SlotInfo{ @@ -622,7 +622,7 @@ apps: app: `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 0) c.Check(info.Slots, HasLen, 1) c.Check(info.Apps, HasLen, 1) @@ -652,7 +652,7 @@ apps: slots: ["net"] `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 0) c.Check(info.Slots, HasLen, 1) c.Check(info.Apps, HasLen, 1) @@ -680,7 +680,7 @@ apps: slots: ["network-client"] `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 0) c.Check(info.Slots, HasLen, 1) c.Check(info.Apps, HasLen, 1) @@ -708,7 +708,7 @@ slots: ipv6-aware: true `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 0) c.Check(info.Slots, HasLen, 1) c.Check(info.Apps, HasLen, 0) @@ -730,7 +730,7 @@ slots: label: Front panel LED (red) `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 0) c.Check(info.Slots, HasLen, 1) c.Check(info.Apps, HasLen, 0) @@ -752,7 +752,7 @@ hooks: test-hook: `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 0) c.Check(info.Slots, HasLen, 1) c.Check(info.Apps, HasLen, 0) @@ -785,7 +785,7 @@ hooks: slots: [test-slot] `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 0) c.Check(info.Slots, HasLen, 1) c.Check(info.Apps, HasLen, 0) @@ -885,7 +885,7 @@ hooks: test-hook: `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 0) c.Check(info.Slots, HasLen, 0) c.Check(info.Apps, HasLen, 0) @@ -913,7 +913,7 @@ hooks: test-hook: `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 0) c.Check(info.Slots, HasLen, 0) c.Check(info.Apps, HasLen, 0) @@ -933,7 +933,7 @@ hooks: foo-hook: `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 0) c.Check(info.Slots, HasLen, 0) c.Check(info.Apps, HasLen, 0) @@ -958,7 +958,7 @@ hooks: plugs: [test-plug] `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 1) c.Check(info.Slots, HasLen, 0) c.Check(info.Apps, HasLen, 0) @@ -992,7 +992,7 @@ hooks: test-hook: `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 1) c.Check(info.Slots, HasLen, 0) c.Check(info.Apps, HasLen, 0) @@ -1028,7 +1028,7 @@ hooks: without-plug: `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 1) c.Check(info.Slots, HasLen, 0) c.Check(info.Apps, HasLen, 0) @@ -1066,7 +1066,7 @@ hooks: plugs: ["test-plug"] `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 1) c.Check(info.Slots, HasLen, 0) c.Check(info.Apps, HasLen, 0) @@ -1103,7 +1103,7 @@ apps: test-app: `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "snap") + c.Check(info.InstanceName(), Equals, "snap") c.Check(info.Plugs, HasLen, 1) c.Check(info.Slots, HasLen, 0) c.Check(info.Apps, HasLen, 1) @@ -1171,7 +1171,7 @@ slots: interface: ptrace `)) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "foo") + c.Check(info.InstanceName(), Equals, "foo") c.Check(info.Version, Equals, "1.2") c.Check(info.Type, Equals, snap.TypeApp) c.Check(info.Epoch.String(), Equals, "1*") diff --git a/snap/info_test.go b/snap/info_test.go index 8761490022..9030a93186 100644 --- a/snap/info_test.go +++ b/snap/info_test.go @@ -88,7 +88,7 @@ func (s *infoSuite) TestSideInfoOverrides(c *C) { SnapID: "snapidsnapidsnapidsnapidsnapidsn", } - c.Check(info.Name(), Equals, "newname") + c.Check(info.InstanceName(), Equals, "newname") c.Check(info.Summary(), Equals, "fixed summary") c.Check(info.Description(), Equals, "fixed desc") c.Check(info.Revision, Equals, snap.R(1)) @@ -186,7 +186,7 @@ func (s *infoSuite) TestReadInfo(c *C) { snapInfo2, err := snap.ReadInfo("sample", si) c.Assert(err, IsNil) - c.Check(snapInfo2.Name(), Equals, "sample") + c.Check(snapInfo2.InstanceName(), Equals, "sample") c.Check(snapInfo2.Revision, Equals, snap.R(42)) c.Check(snapInfo2.Summary(), Equals, "esummary") @@ -203,7 +203,7 @@ func (s *infoSuite) TestReadCurrentInfo(c *C) { snapInfo2, err := snap.ReadCurrentInfo("sample") c.Assert(err, IsNil) - c.Check(snapInfo2.Name(), Equals, "sample") + c.Check(snapInfo2.InstanceName(), Equals, "sample") c.Check(snapInfo2.Revision, Equals, snap.R(42)) c.Check(snapInfo2, DeepEquals, snapInfo1) @@ -217,7 +217,7 @@ func (s *infoSuite) TestInstallDate(c *C) { info := snaptest.MockSnap(c, sampleYaml, si) // not current -> Zero c.Check(info.InstallDate().IsZero(), Equals, true) - c.Check(snap.InstallDate(info.Name()).IsZero(), Equals, true) + c.Check(snap.InstallDate(info.InstanceName()).IsZero(), Equals, true) mountdir := info.MountDir() dir, rev := filepath.Split(mountdir) @@ -231,7 +231,7 @@ func (s *infoSuite) TestInstallDate(c *C) { c.Check(instTime.IsZero(), Equals, false) c.Check(info.InstallDate().Equal(instTime), Equals, true) - c.Check(snap.InstallDate(info.Name()).Equal(instTime), Equals, true) + c.Check(snap.InstallDate(info.InstanceName()).Equal(instTime), Equals, true) } func (s *infoSuite) TestReadInfoNotFound(c *C) { @@ -321,7 +321,7 @@ confinement: devmode` info, err := snap.ReadInfoFromSnapFile(snapf, nil) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "foo") + c.Check(info.InstanceName(), Equals, "foo") c.Check(info.Version, Equals, "1.0") c.Check(info.Type, Equals, snap.TypeApp) c.Check(info.Revision, Equals, snap.R(0)) @@ -343,7 +343,7 @@ confinement: classic` info, err := snap.ReadInfoFromSnapFile(snapf, nil) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "foo") + c.Check(info.InstanceName(), Equals, "foo") c.Check(info.Version, Equals, "1.0") c.Check(info.Type, Equals, snap.TypeApp) c.Check(info.Revision, Equals, snap.R(0)) @@ -363,7 +363,7 @@ type: app` info, err := snap.ReadInfoFromSnapFile(snapf, nil) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "foo") + c.Check(info.InstanceName(), Equals, "foo") c.Check(info.Version, Equals, "1.0") c.Check(info.Type, Equals, snap.TypeApp) c.Check(info.Revision, Equals, snap.R(0)) @@ -386,7 +386,7 @@ type: app` Revision: snap.R(42), }) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "baz") + c.Check(info.InstanceName(), Equals, "baz") c.Check(info.Version, Equals, "1.0") c.Check(info.Type, Equals, snap.TypeApp) c.Check(info.Revision, Equals, snap.R(42)) @@ -570,7 +570,7 @@ func (s *infoSuite) checkInstalledSnapAndSnapFile(c *C, yaml string, contents st sideInfo := &snap.SideInfo{Revision: snap.R(42)} info0 := snaptest.MockSnap(c, yaml, sideInfo) snaptest.PopulateDir(info0.MountDir(), emptyHooks(hooks...)) - info, err := snap.ReadInfo(info0.Name(), sideInfo) + info, err := snap.ReadInfo(info0.InstanceName(), sideInfo) c.Check(err, IsNil) checker(c, info) @@ -731,7 +731,7 @@ func (s *infoSuite) TestAppDesktopFile(c *C) { snapInfo, err := snap.ReadInfo("sample", &snap.SideInfo{}) c.Assert(err, IsNil) - c.Check(snapInfo.Name(), Equals, "sample") + c.Check(snapInfo.InstanceName(), Equals, "sample") c.Check(snapInfo.Apps["app"].DesktopFile(), Matches, `.*/var/lib/snapd/desktop/applications/sample_app.desktop`) c.Check(snapInfo.Apps["sample"].DesktopFile(), Matches, `.*/var/lib/snapd/desktop/applications/sample_sample.desktop`) } diff --git a/snap/pack/pack.go b/snap/pack/pack.go index 5bf9e6e6a7..02bc470d07 100644 --- a/snap/pack/pack.go +++ b/snap/pack/pack.go @@ -250,7 +250,7 @@ func prepare(sourceDir, targetDir, buildDir string) (snapName string, err error) } // build the package - snapName = fmt.Sprintf("%s_%s_%v.snap", info.Name(), info.Version, debArchitecture(info)) + snapName = fmt.Sprintf("%s_%s_%v.snap", info.InstanceName(), info.Version, debArchitecture(info)) if targetDir != "" { snapName = filepath.Join(targetDir, snapName) diff --git a/snap/snapenv/snapenv.go b/snap/snapenv/snapenv.go index 6e021656b1..395b5bc3f3 100644 --- a/snap/snapenv/snapenv.go +++ b/snap/snapenv/snapenv.go @@ -93,16 +93,17 @@ func snapEnv(info *snap.Info) map[string]string { // used by so many other modules, we run into circular dependencies if it's // somewhere more reasonable like the snappy module. func basicEnv(info *snap.Info) map[string]string { + // TODO parallel-install: use of proper instance/store name return map[string]string{ // This uses CoreSnapMountDir because the computed environment // variables are conveyed to the started application process which // shall *either* execute with the new mount namespace where snaps are // always mounted on /snap OR it is a classically confined snap where // /snap is a part of the distribution package. - "SNAP": filepath.Join(dirs.CoreSnapMountDir, info.Name(), info.Revision.String()), + "SNAP": filepath.Join(dirs.CoreSnapMountDir, info.InstanceName(), info.Revision.String()), "SNAP_COMMON": info.CommonDataDir(), "SNAP_DATA": info.DataDir(), - "SNAP_NAME": info.Name(), + "SNAP_NAME": info.InstanceName(), "SNAP_VERSION": info.Version, "SNAP_REVISION": info.Revision.String(), "SNAP_ARCH": arch.UbuntuArchitecture(), @@ -117,6 +118,7 @@ func basicEnv(info *snap.Info) map[string]string { // used by so many other modules, we run into circular dependencies if it's // somewhere more reasonable like the snappy module. func userEnv(info *snap.Info, home string) map[string]string { + // TODO parallel-install: use of proper instance/store name result := map[string]string{ "SNAP_USER_COMMON": info.UserCommonDataDir(home), "SNAP_USER_DATA": info.UserDataDir(home), diff --git a/snap/snaptest/snaptest_test.go b/snap/snaptest/snaptest_test.go index 5ad3ff5817..8c44798430 100644 --- a/snap/snaptest/snaptest_test.go +++ b/snap/snaptest/snaptest_test.go @@ -60,7 +60,7 @@ func (s *snapTestSuite) TearDownTest(c *C) { func (s *snapTestSuite) TestMockSnap(c *C) { snapInfo := snaptest.MockSnap(c, sampleYaml, &snap.SideInfo{Revision: snap.R(42)}) // Data from YAML is used - c.Check(snapInfo.Name(), Equals, "sample") + c.Check(snapInfo.InstanceName(), Equals, "sample") // Data from SideInfo is used c.Check(snapInfo.Revision, Equals, snap.R(42)) // The YAML is placed on disk @@ -75,7 +75,7 @@ func (s *snapTestSuite) TestMockSnap(c *C) { func (s *snapTestSuite) TestMockSnapCurrent(c *C) { snapInfo := snaptest.MockSnapCurrent(c, sampleYaml, &snap.SideInfo{Revision: snap.R(42)}) // Data from YAML is used - c.Check(snapInfo.Name(), Equals, "sample") + c.Check(snapInfo.InstanceName(), Equals, "sample") // Data from SideInfo is used c.Check(snapInfo.Revision, Equals, snap.R(42)) // The YAML is placed on disk @@ -89,7 +89,7 @@ func (s *snapTestSuite) TestMockSnapCurrent(c *C) { func (s *snapTestSuite) TestMockInfo(c *C) { snapInfo := snaptest.MockInfo(c, sampleYaml, &snap.SideInfo{Revision: snap.R(42)}) // Data from YAML is used - c.Check(snapInfo.Name(), Equals, "sample") + c.Check(snapInfo.InstanceName(), Equals, "sample") // Data from SideInfo is used c.Check(snapInfo.Revision, Equals, snap.R(42)) // The YAML is *not* placed on disk @@ -103,7 +103,7 @@ func (s *snapTestSuite) TestMockInfo(c *C) { func (s *snapTestSuite) TestMockInvalidInfo(c *C) { snapInfo := snaptest.MockInvalidInfo(c, sampleYaml+"\nslots:\n network:\n", &snap.SideInfo{Revision: snap.R(42)}) // Data from YAML is used - c.Check(snapInfo.Name(), Equals, "sample") + c.Check(snapInfo.InstanceName(), Equals, "sample") // Data from SideInfo is used c.Check(snapInfo.Revision, Equals, snap.R(42)) // The YAML is *not* placed on disk diff --git a/snap/validate.go b/snap/validate.go index 84a91f003b..f51e253fb7 100644 --- a/snap/validate.go +++ b/snap/validate.go @@ -213,7 +213,8 @@ func validateSocketAddrPath(socket *SocketInfo, fieldName string, path string) e } func validateSocketAddrAbstract(socket *SocketInfo, fieldName string, path string) error { - prefix := fmt.Sprintf("@snap.%s.", socket.App.Snap.Name()) + // TODO parallel-install: use of proper instance/store name, discuss socket activation in parallel install world + prefix := fmt.Sprintf("@snap.%s.", socket.App.Snap.InstanceName()) if !strings.HasPrefix(path, prefix) { return fmt.Errorf("socket %q path for %q must be prefixed with %q", socket.Name, fieldName, prefix) } @@ -258,11 +259,12 @@ func validateSocketAddrNetPort(socket *SocketInfo, fieldName string, port string // Validate verifies the content in the info. func Validate(info *Info) error { - name := info.Name() + name := info.InstanceName() if name == "" { return fmt.Errorf("snap name cannot be empty") } + // TODO parallel-install: use of proper instance/store name, validate instance key if err := ValidateName(name); err != nil { return err } @@ -315,7 +317,7 @@ func Validate(info *Info) error { // validate that bases do not have base fields if info.Type == TypeOS || info.Type == TypeBase { if info.Base != "" { - return fmt.Errorf(`cannot have "base" field on %q snap %q`, info.Type, info.Name()) + return fmt.Errorf(`cannot have "base" field on %q snap %q`, info.Type, info.InstanceName()) } } diff --git a/spread.yaml b/spread.yaml index d5076f4141..39b466c931 100644 --- a/spread.yaml +++ b/spread.yaml @@ -291,6 +291,8 @@ debug-each: | if [ "$SPREAD_DEBUG_EACH" = 1 ]; then # shellcheck source=tests/lib/journalctl.sh . "$TESTSLIB/journalctl.sh" + #shellcheck source=tests/lib/state.sh + . "$TESTSLIB/state.sh" echo '# journal messages for snapd' get_journalctl_log -u snapd @@ -300,6 +302,8 @@ debug-each: | dmesg --ctime | grep type=1326 || true echo '# snap interfaces' snap interfaces || true + echo '# tasks executed on system' + cat "$RUNTIME_STATE_PATH/runs" || true fi rename: diff --git a/store/details.go b/store/details.go index 6812e20dff..d8a35785f7 100644 --- a/store/details.go +++ b/store/details.go @@ -68,24 +68,6 @@ type snapDetails struct { CommonIDs []string `json:"common_ids,omitempty"` } -// channelMap contains -type channelMap struct { - Track string `json:"track"` - SnapDetails []channelSnapInfoDetails `json:"map,omitempty"` -} - -// channelSnapInfoDetails is the subset of snapDetails we need to get -// information about the snaps in the various channels -type channelSnapInfoDetails struct { - Revision int `json:"revision"` // store revisions are ints starting at 1 - Confinement string `json:"confinement"` - Version string `json:"version"` - Channel string `json:"channel"` - Epoch snap.Epoch `json:"epoch"` - DownloadSize int64 `json:"binary_filesize"` - Info string `json:"info"` -} - func infoFromRemote(d *snapDetails) *snap.Info { info := &snap.Info{} info.Architectures = d.Architectures diff --git a/store/store.go b/store/store.go index 51c152cf10..193b9ebe58 100644 --- a/store/store.go +++ b/store/store.go @@ -1453,6 +1453,7 @@ var download = func(ctx context.Context, name, sha3_384, downloadURL string, use } var finalErr error + var dlSize float64 startTime := time.Now() for attempt := retry.Start(defaultRetryStrategy, nil); attempt.Next(); { reqOptions := downloadOptions(storeURL, cdnHeader) @@ -1511,7 +1512,8 @@ var download = func(ctx context.Context, name, sha3_384, downloadURL string, use if pbar == nil { pbar = progress.Null } - pbar.Start(name, float64(resp.ContentLength)) + dlSize = float64(resp.ContentLength) + pbar.Start(name, dlSize) mw := io.MultiWriter(w, h, pbar) _, finalErr = io.Copy(mw, resp.Body) pbar.Finished() @@ -1538,6 +1540,20 @@ var download = func(ctx context.Context, name, sha3_384, downloadURL string, use } break } + if finalErr == nil { + // not using quantity.FormatFoo as this is just for debug + dt := time.Since(startTime) + r := dlSize / dt.Seconds() + var p rune + for _, p = range " kMGTPEZY" { + if r < 1000 { + break + } + r /= 1000 + } + + logger.Debugf("Download succeeded in %.03fs (%.0f%cB/s).", dt.Seconds(), r, p) + } return finalErr } @@ -2120,6 +2136,7 @@ func (s *Store) snapAction(ctx context.Context, currentSnaps []*CurrentSnap, act } } + // TODO parallel-install: use of proper instance/store name aJSON := &snapActionJSON{ Action: a.Action, InstanceKey: instanceKey, diff --git a/store/store_test.go b/store/store_test.go index f3ebb70725..e15490210b 100644 --- a/store/store_test.go +++ b/store/store_test.go @@ -1908,103 +1908,6 @@ const ( helloWorldDeveloperID = "canonical" ) -/* acquired via - -http --pretty=format --print b https://api.snapcraft.io/api/v1/snaps/details/hello-world X-Ubuntu-Series:16 fields==anon_download_url,architecture,channel,download_sha3_384,summary,description,binary_filesize,download_url,icon_url,last_updated,license,package_name,prices,publisher,ratings_average,revision,screenshot_urls,snap_id,support_url,title,content,version,origin,developer_id,private,confinement,snap_yaml_raw channel==edge | xsel -b - -on 2016-07-03. Then, by hand: - * set prices to {"EUR": 0.99, "USD": 1.23}. - * Screenshot URLS set manually. - * Set "private" to true. - -on 2017-11-20. Then, by hand: - * add "snap_yaml_raw" from "test-snapd-content-plug" - -On Ubuntu, apt install httpie xsel (although you could get http from -the http snap instead). - -*/ -const MockDetailsJSON = `{ - "_links": { - "self": { - "href": "https://api.snapcraft.io/api/v1/snaps/details/hello-world?fields=anon_download_url%2Carchitecture%2Cchannel%2Cdownload_sha3_384%2Csummary%2Cdescription%2Cbinary_filesize%2Cdownload_url%2Cicon_url%2Clast_updated%2Clicense%2Cpackage_name%2Cprices%2Cpublisher%2Cratings_average%2Crevision%2Cscreenshot_urls%2Csnap_id%2Csupport_url%2Ctitle%2Ccontent%2Cversion%2Corigin%2Cdeveloper_id%2Cprivate%2Cconfinement&channel=edge" - } - }, - "anon_download_url": "https://public.apps.ubuntu.com/anon/download-snap/buPKUD3TKqCOgLEjjHx5kSiCpIs5cMuQ_27.snap", - "architecture": [ - "all" - ], - "base": "bare-base", - "binary_filesize": 20480, - "channel": "edge", - "confinement": "strict", - "content": "application", - "description": "This is a simple hello world example.", - "developer_id": "canonical", - "download_sha3_384": "eed62063c04a8c3819eb71ce7d929cc8d743b43be9e7d86b397b6d61b66b0c3a684f3148a9dbe5821360ae32105c1bd9", - "download_url": "https://public.apps.ubuntu.com/download-snap/buPKUD3TKqCOgLEjjHx5kSiCpIs5cMuQ_27.snap", - "icon_url": "https://myapps.developer.ubuntu.com/site_media/appmedia/2015/03/hello.svg_NZLfWbh.png", - "last_updated": "2016-07-12T16:37:23.960632Z", - "license": "GPL-3.0", - "origin": "canonical", - "package_name": "hello-world", - "prices": {"EUR": 0.99, "USD": 1.23}, - "publisher": "Canonical", - "ratings_average": 0.0, - "revision": 27, - "screenshot_urls": ["https://myapps.developer.ubuntu.com/site_media/appmedia/2015/03/screenshot.png"], - "snap_id": "buPKUD3TKqCOgLEjjHx5kSiCpIs5cMuQ", - "summary": "The 'hello-world' of snaps", - "support_url": "mailto:snappy-devel@lists.ubuntu.com", - "title": "Hello World", - "version": "6.3", - "snap_yaml_raw": "name: test-snapd-content-plug\nversion: 1.0\napps:\n content-plug:\n command: bin/content-plug\n plugs: [shared-content-plug]\nplugs:\n shared-content-plug:\n interface: content\n target: import\n content: mylib\n default-provider: test-snapd-content-slot\nslots:\n shared-content-slot:\n interface: content\n content: mylib\n read:\n - /\n", - "channel_maps_list": [ - { - "track": "latest", - "map": [ - { - "info": "released", - "version": "v1", - "binary_filesize": 12345, - "epoch": "0", - "confinement": "strict", - "channel": "stable", - "revision": 1 - }, - { - "info": "released", - "version": "v2", - "binary_filesize": 12345, - "epoch": "0", - "confinement": "strict", - "channel": "candidate", - "revision": 2 - }, - { - "info": "released", - "version": "v8", - "binary_filesize": 12345, - "epoch": "0", - "confinement": "devmode", - "channel": "beta", - "revision": 8 - }, - { - "info": "released", - "version": "v9", - "binary_filesize": 12345, - "epoch": "0", - "confinement": "devmode", - "channel": "edge", - "revision": 9 - } - ] - } - ] -} -` - const mockOrdersJSON = `{ "orders": [ { @@ -2285,7 +2188,8 @@ func (s *storeTestSuite) TestInfo(c *C) { } result, err := sto.SnapInfo(spec, nil) c.Assert(err, IsNil) - c.Check(result.Name(), Equals, "hello-world") + // TODO parallel-install: use of proper instance/store name + c.Check(result.InstanceName(), Equals, "hello-world") c.Check(result.Architectures, DeepEquals, []string{"all"}) c.Check(result.Revision, Equals, snap.R(27)) c.Check(result.SnapID, Equals, helloWorldSnapID) @@ -2367,7 +2271,7 @@ func (s *storeTestSuite) TestInfoBadResponses(c *C) { info, err := sto.SnapInfo(SnapSpec{Name: "hello"}, nil) c.Assert(err, IsNil) - c.Check(info.Name(), Equals, "hello") + c.Check(info.InstanceName(), Equals, "hello") info, err = sto.SnapInfo(SnapSpec{Name: "hello"}, nil) c.Check(err, Equals, ErrSnapNotFound) @@ -2411,7 +2315,8 @@ func (s *storeTestSuite) TestInfoDefaultChannelIsStable(c *C) { } result, err := sto.SnapInfo(spec, nil) c.Assert(err, IsNil) - c.Check(result.Name(), Equals, "hello-world") + // TODO parallel-install: use of proper instance/store name + c.Check(result.InstanceName(), Equals, "hello-world") c.Check(result.SnapID, Equals, helloWorldSnapID) c.Check(result.Channel, Equals, "stable") } @@ -2475,7 +2380,8 @@ func (s *storeTestSuite) TestInfo500once(c *C) { } result, err := sto.SnapInfo(spec, nil) c.Assert(err, IsNil) - c.Check(result.Name(), Equals, "hello-world") + // TODO parallel-install: use of proper instance/store name + c.Check(result.InstanceName(), Equals, "hello-world") c.Assert(n, Equals, 2) } @@ -2514,7 +2420,8 @@ func (s *storeTestSuite) TestInfoAndChannels(c *C) { result, err := sto.SnapInfo(spec, nil) c.Assert(err, IsNil) c.Assert(n, Equals, 1) - c.Check(result.Name(), Equals, "hello-world") + // TODO parallel-install: use of proper instance/store name + c.Check(result.InstanceName(), Equals, "hello-world") expected := map[string]*snap.ChannelSnapInfo{ "latest/stable": { Revision: snap.R(27), @@ -2636,7 +2543,8 @@ func (s *storeTestSuite) TestInfoNonDefaults(c *C) { } result, err := sto.SnapInfo(spec, nil) c.Assert(err, IsNil) - c.Check(result.Name(), Equals, "hello-world") + // TODO parallel-install: use of proper instance/store name + c.Check(result.InstanceName(), Equals, "hello-world") } func (s *storeTestSuite) TestStoreIDFromAuthContext(c *C) { @@ -2666,7 +2574,8 @@ func (s *storeTestSuite) TestStoreIDFromAuthContext(c *C) { } result, err := sto.SnapInfo(spec, nil) c.Assert(err, IsNil) - c.Check(result.Name(), Equals, "hello-world") + // TODO parallel-install: use of proper instance/store name + c.Check(result.InstanceName(), Equals, "hello-world") } func (s *storeTestSuite) TestProxyStoreFromAuthContext(c *C) { @@ -2698,7 +2607,8 @@ func (s *storeTestSuite) TestProxyStoreFromAuthContext(c *C) { } result, err := sto.SnapInfo(spec, nil) c.Assert(err, IsNil) - c.Check(result.Name(), Equals, "hello-world") + // TODO parallel-install: use of proper instance/store name + c.Check(result.InstanceName(), Equals, "hello-world") } func (s *storeTestSuite) TestProxyStoreFromAuthContextURLFallback(c *C) { @@ -2729,7 +2639,8 @@ func (s *storeTestSuite) TestProxyStoreFromAuthContextURLFallback(c *C) { } result, err := sto.SnapInfo(spec, nil) c.Assert(err, IsNil) - c.Check(result.Name(), Equals, "hello-world") + // TODO parallel-install: use of proper instance/store name + c.Check(result.InstanceName(), Equals, "hello-world") } func (s *storeTestSuite) TestInfoOopses(c *C) { @@ -2805,51 +2716,53 @@ func (s *storeTestSuite) TestNoInfo(c *C) { } /* acquired via: -curl -s -H "accept: application/hal+json" -H "X-Ubuntu-Release: 16" -H "X-Ubuntu-Device-Channel: edge" -H "X-Ubuntu-Wire-Protocol: 1" -H "X-Ubuntu-Architecture: amd64" 'https://api.snapcraft.io/api/v1/snaps/search?fields=anon_download_url%2Carchitecture%2Cchannel%2Cdownload_sha512%2Csummary%2Cdescription%2Cbinary_filesize%2Cdownload_url%2Cicon_url%2Clast_updated%2Clicense%2Cpackage_name%2Cprices%2Cpublisher%2Cratings_average%2Crevision%2Cscreenshot_urls%2Csnap_id%2Csupport_url%2Ctitle%2Ccontent%2Cversion%2Corigin%2Ccommon_ids&q=hello' | python -m json.tool | xsel -b -Screenshot URLS set manually. +curl -s -H "accept: application/hal+json" -H "X-Ubuntu-Release: 16" -H "X-Ubuntu-Device-Channel: edge" -H "X-Ubuntu-Wire-Protocol: 1" -H "X-Ubuntu-Architecture: amd64" 'https://api.snapcraft.io/api/v1/snaps/search?fields=anon_download_url%2Carchitecture%2Cchannel%2Cdownload_sha3_384%2Csummary%2Cdescription%2Cbinary_filesize%2Cdownload_url%2Cepoch%2Cicon_url%2Clast_updated%2Cpackage_name%2Cprices%2Cpublisher%2Cratings_average%2Crevision%2Cscreenshot_urls%2Csnap_id%2Clicense%2Cbase%2Csupport_url%2Ccontact%2Ctitle%2Ccontent%2Cversion%2Corigin%2Cdeveloper_id%2Cprivate%2Cconfinement%2Ccommon_ids&q=hello' | python -m json.tool | xsel -b +Add base and prices. */ const MockSearchJSON = `{ "_embedded": { "clickindex:package": [ { - "anon_download_url": "https://public.apps.ubuntu.com/anon/download-snap/buPKUD3TKqCOgLEjjHx5kSiCpIs5cMuQ_25.snap", + "anon_download_url": "https://api.snapcraft.io/api/v1/snaps/download/buPKUD3TKqCOgLEjjHx5kSiCpIs5cMuQ_27.snap", "architecture": [ "all" ], + "base": "bare-base", "binary_filesize": 20480, - "channel": "edge", + "channel": "stable", "common_ids": [], + "confinement": "strict", + "contact": "mailto:snappy-devel@lists.ubuntu.com", "content": "application", "description": "This is a simple hello world example.", - "download_sha512": "4bf23ce93efa1f32f0aeae7ec92564b7b0f9f8253a0bd39b2741219c1be119bb676c21208c6845ccf995e6aabe791d3f28a733ebcbbc3171bb23f67981f4068e", - "download_url": "https://public.apps.ubuntu.com/download-snap/buPKUD3TKqCOgLEjjHx5kSiCpIs5cMuQ_25.snap", - "icon_url": "https://myapps.developer.ubuntu.com/site_media/appmedia/2015/03/hello.svg_NZLfWbh.png", - "last_updated": "2016-04-19T19:50:50.435291Z", - "license": "GPL-3.0", + "developer_id": "canonical", + "download_sha3_384": "eed62063c04a8c3819eb71ce7d929cc8d743b43be9e7d86b397b6d61b66b0c3a684f3148a9dbe5821360ae32105c1bd9", + "download_url": "https://api.snapcraft.io/api/v1/snaps/download/buPKUD3TKqCOgLEjjHx5kSiCpIs5cMuQ_27.snap", + "epoch": "0", + "icon_url": "https://dashboard.snapcraft.io/site_media/appmedia/2015/03/hello.svg_NZLfWbh.png", + "last_updated": "2016-07-12T16:37:23.960632+00:00", + "license": "MIT", "origin": "canonical", "package_name": "hello-world", "prices": {"EUR": 2.99, "USD": 3.49}, + "private": false, "publisher": "Canonical", "ratings_average": 0.0, - "revision": 25, - "screenshot_urls": ["https://myapps.developer.ubuntu.com/site_media/appmedia/2015/03/screenshot.png"], + "revision": 27, + "screenshot_urls": [ + "https://dashboard.snapcraft.io/site_media/appmedia/2018/06/Screenshot_from_2018-06-14_09-33-31.png" + ], "snap_id": "buPKUD3TKqCOgLEjjHx5kSiCpIs5cMuQ", - "summary": "Hello world example", - "support_url": "mailto:snappy-devel@lists.ubuntu.com", + "summary": "The 'hello-world' of snaps", + "support_url": "", "title": "Hello World", - "version": "6.0" + "version": "6.3" } ] }, "_links": { - "first": { - "href": "https://api.snapcraft.io/api/v1/snaps/search?q=hello&fields=anon_download_url%2Carchitecture%2Cchannel%2Cdownload_sha512%2Csummary%2Cdescription%2Cbinary_filesize%2Cdownload_url%2Cicon_url%2Clast_updated%2Clicense%2Cpackage_name%2Cprices%2Cpublisher%2Cratings_average%2Crevision%2Cscreenshot_urls%2Csnap_id%2Csupport_url%2Ctitle%2Ccontent%2Cversion%2Corigin&page=1" - }, - "last": { - "href": "https://api.snapcraft.io/api/v1/snaps/search?q=hello&fields=anon_download_url%2Carchitecture%2Cchannel%2Cdownload_sha512%2Csummary%2Cdescription%2Cbinary_filesize%2Cdownload_url%2Cicon_url%2Clast_updated%2Clicense%2Cpackage_name%2Cprices%2Cpublisher%2Cratings_average%2Crevision%2Cscreenshot_urls%2Csnap_id%2Csupport_url%2Ctitle%2Ccontent%2Cversion%2Corigin&page=1" - }, "self": { - "href": "https://api.snapcraft.io/api/v1/snaps/search?q=hello&fields=anon_download_url%2Carchitecture%2Cchannel%2Cdownload_sha512%2Csummary%2Cdescription%2Cbinary_filesize%2Cdownload_url%2Cicon_url%2Clast_updated%2Clicense%2Cpackage_name%2Cprices%2Cpublisher%2Cratings_average%2Crevision%2Cscreenshot_urls%2Csnap_id%2Csupport_url%2Ctitle%2Ccontent%2Cversion%2Corigin&page=1" + "href": "http://api.snapcraft.io/api/v1/snaps/search?fields=anon_download_url%2Carchitecture%2Cchannel%2Cdownload_sha3_384%2Csummary%2Cdescription%2Cbinary_filesize%2Cdownload_url%2Cepoch%2Cicon_url%2Clast_updated%2Cpackage_name%2Cprices%2Cpublisher%2Cratings_average%2Crevision%2Cscreenshot_urls%2Csnap_id%2Clicense%2Cbase%2Csupport_url%2Ccontact%2Ctitle%2Ccontent%2Cversion%2Corigin%2Cdeveloper_id%2Cprivate%2Cconfinement%2Ccommon_ids&q=hello" } } } @@ -3100,6 +3013,88 @@ func (s *storeTestSuite) testSnapCommands(c *C, onClassic bool) { }) } +func (s *storeTestSuite) TestFind(c *C) { + restore := release.MockOnClassic(false) + defer restore() + + mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assertRequest(c, r, "GET", searchPath) + query := r.URL.Query() + + q := query.Get("q") + c.Check(q, Equals, "hello") + + c.Check(r.UserAgent(), Equals, userAgent) + + // check device authorization is set, implicitly checking doRequest was used + c.Check(r.Header.Get("X-Device-Authorization"), Equals, `Macaroon root="device-macaroon"`) + + // no store ID by default + storeID := r.Header.Get("X-Ubuntu-Store") + c.Check(storeID, Equals, "") + + c.Check(r.URL.Query().Get("fields"), Equals, "abc,def") + + c.Check(r.Header.Get("X-Ubuntu-Series"), Equals, release.Series) + c.Check(r.Header.Get("X-Ubuntu-Architecture"), Equals, arch.UbuntuArchitecture()) + c.Check(r.Header.Get("X-Ubuntu-Classic"), Equals, "false") + + c.Check(r.Header.Get("X-Ubuntu-Confinement"), Equals, "") + + w.Header().Set("X-Suggested-Currency", "GBP") + + w.Header().Set("Content-Type", "application/hal+json") + w.WriteHeader(200) + + io.WriteString(w, MockSearchJSON) + })) + + c.Assert(mockServer, NotNil) + defer mockServer.Close() + + mockServerURL, _ := url.Parse(mockServer.URL) + cfg := Config{ + StoreBaseURL: mockServerURL, + DetailFields: []string{"abc", "def"}, + } + authContext := &testAuthContext{c: c, device: s.device} + sto := New(&cfg, authContext) + + snaps, err := sto.Find(&Search{Query: "hello"}, nil) + c.Assert(err, IsNil) + c.Assert(snaps, HasLen, 1) + snp := snaps[0] + c.Check(snp.InstanceName(), Equals, "hello-world") + c.Check(snp.Architectures, DeepEquals, []string{"all"}) + c.Check(snp.Revision, Equals, snap.R(27)) + c.Check(snp.SnapID, Equals, helloWorldSnapID) + c.Check(snp.Publisher, Equals, "canonical") + c.Check(snp.PublisherID, Equals, "canonical") + c.Check(snp.Version, Equals, "6.3") + c.Check(snp.Sha3_384, Matches, `[[:xdigit:]]{96}`) + c.Check(snp.Size, Equals, int64(20480)) + c.Check(snp.Channel, Equals, "stable") + c.Check(snp.Description(), Equals, "This is a simple hello world example.") + c.Check(snp.Summary(), Equals, "The 'hello-world' of snaps") + c.Check(snp.Title(), Equals, "Hello World") + c.Check(snp.License, Equals, "MIT") + c.Assert(snp.Prices, DeepEquals, map[string]float64{"EUR": 2.99, "USD": 3.49}) + c.Assert(snp.Paid, Equals, true) + c.Assert(snp.Screenshots, DeepEquals, []snap.ScreenshotInfo{ + { + URL: "https://dashboard.snapcraft.io/site_media/appmedia/2018/06/Screenshot_from_2018-06-14_09-33-31.png", + }, + }) + c.Check(snp.MustBuy, Equals, true) + c.Check(snp.Contact, Equals, "mailto:snappy-devel@lists.ubuntu.com") + c.Check(snp.Base, Equals, "bare-base") + + // Make sure the epoch (currently not sent by the store) defaults to "0" + c.Check(snp.Epoch.String(), Equals, "0") + + c.Check(sto.SuggestedCurrency(), Equals, "GBP") +} + func (s *storeTestSuite) TestFindPrivate(c *C) { n := 0 mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -4615,7 +4610,8 @@ func (s *storeTestSuite) TestSnapAction(c *C) { }, nil, nil) c.Assert(err, IsNil) c.Assert(results, HasLen, 1) - c.Assert(results[0].Name(), Equals, "hello-world") + // TODO parallel-install: use of proper instance/store name + c.Assert(results[0].InstanceName(), Equals, "hello-world") c.Assert(results[0].Revision, Equals, snap.R(26)) c.Assert(results[0].Version, Equals, "6.1") c.Assert(results[0].SnapID, Equals, helloWorldSnapID) @@ -4983,7 +4979,8 @@ func (s *storeTestSuite) TestSnapActionRetryOnEOF(c *C) { c.Assert(err, IsNil) c.Assert(n, Equals, 4) c.Assert(results, HasLen, 1) - c.Assert(results[0].Name(), Equals, "hello-world") + // TODO parallel-install: use of proper instance/store name + c.Assert(results[0].InstanceName(), Equals, "hello-world") } func (s *storeTestSuite) TestSnapActionIgnoreValidation(c *C) { @@ -5070,7 +5067,8 @@ func (s *storeTestSuite) TestSnapActionIgnoreValidation(c *C) { }, nil, nil) c.Assert(err, IsNil) c.Assert(results, HasLen, 1) - c.Assert(results[0].Name(), Equals, "hello-world") + // TODO parallel-install: use of proper instance/store name + c.Assert(results[0].InstanceName(), Equals, "hello-world") c.Assert(results[0].Revision, Equals, snap.R(26)) } @@ -5151,7 +5149,8 @@ func (s *storeTestSuite) TestInstallFallbackChannelIsStable(c *C) { }, nil, nil) c.Assert(err, IsNil) c.Assert(results, HasLen, 1) - c.Assert(results[0].Name(), Equals, "hello-world") + // TODO parallel-install: use of proper instance/store name + c.Assert(results[0].InstanceName(), Equals, "hello-world") c.Assert(results[0].Revision, Equals, snap.R(26)) c.Assert(results[0].SnapID, Equals, helloWorldSnapID) } @@ -5246,7 +5245,8 @@ func (s *storeTestSuite) TestSnapActionNonDefaultsHeaders(c *C) { }, nil, nil) c.Assert(err, IsNil) c.Assert(results, HasLen, 1) - c.Assert(results[0].Name(), Equals, "hello-world") + // TODO parallel-install: use of proper instance/store name + c.Assert(results[0].InstanceName(), Equals, "hello-world") c.Assert(results[0].Revision, Equals, snap.R(26)) c.Assert(results[0].Version, Equals, "6.1") c.Assert(results[0].SnapID, Equals, helloWorldSnapID) @@ -5337,7 +5337,8 @@ func (s *storeTestSuite) TestSnapActionWithDeltas(c *C) { }, nil, nil) c.Assert(err, IsNil) c.Assert(results, HasLen, 1) - c.Assert(results[0].Name(), Equals, "hello-world") + // TODO parallel-install: use of proper instance/store name + c.Assert(results[0].InstanceName(), Equals, "hello-world") c.Assert(results[0].Revision, Equals, snap.R(26)) } @@ -5423,7 +5424,8 @@ func (s *storeTestSuite) TestSnapActionOptions(c *C) { }, nil, &RefreshOptions{RefreshManaged: true}) c.Assert(err, IsNil) c.Assert(results, HasLen, 1) - c.Assert(results[0].Name(), Equals, "hello-world") + // TODO parallel-install: use of proper instance/store name + c.Assert(results[0].InstanceName(), Equals, "hello-world") c.Assert(results[0].Revision, Equals, snap.R(26)) } @@ -5514,7 +5516,8 @@ func (s *storeTestSuite) testSnapActionGet(action string, c *C) { }, nil, nil) c.Assert(err, IsNil) c.Assert(results, HasLen, 1) - c.Assert(results[0].Name(), Equals, "hello-world") + // TODO parallel-install: use of proper instance/store name + c.Assert(results[0].InstanceName(), Equals, "hello-world") c.Assert(results[0].Revision, Equals, snap.R(26)) c.Assert(results[0].Version, Equals, "6.1") c.Assert(results[0].SnapID, Equals, helloWorldSnapID) @@ -5612,7 +5615,8 @@ func (s *storeTestSuite) testSnapActionGetWithRevision(action string, c *C) { }, nil, nil) c.Assert(err, IsNil) c.Assert(results, HasLen, 1) - c.Assert(results[0].Name(), Equals, "hello-world") + // TODO parallel-install: use of proper instance/store name + c.Assert(results[0].InstanceName(), Equals, "hello-world") c.Assert(results[0].Revision, Equals, snap.R(28)) c.Assert(results[0].Version, Equals, "6.1") c.Assert(results[0].SnapID, Equals, helloWorldSnapID) @@ -6201,7 +6205,8 @@ func (s *storeTestSuite) TestSnapActionRefreshesBothAuths(c *C) { }, s.user, nil) c.Assert(err, IsNil) c.Assert(results, HasLen, 1) - c.Assert(results[0].Name(), Equals, "hello-world") + // TODO parallel-install: use of proper instance/store name + c.Assert(results[0].InstanceName(), Equals, "hello-world") c.Check(refreshDischargeEndpointHit, Equals, true) c.Check(refreshSessionRequested, Equals, true) c.Check(n, Equals, 2) diff --git a/tests/lib/fakestore/store/store.go b/tests/lib/fakestore/store/store.go index baf67acaf8..24190723b4 100644 --- a/tests/lib/fakestore/store/store.go +++ b/tests/lib/fakestore/store/store.go @@ -218,7 +218,7 @@ func snapEssentialInfo(w http.ResponseWriter, fn, snapID string, bs asserts.Back } return &essentialInfo{ - Name: info.Name(), + Name: info.StoreName(), SnapID: snapID, DeveloperID: develID, DevelName: devel, @@ -329,7 +329,7 @@ func (s *Store) collectSnaps() (map[string]string, error) { if err != nil { return nil, err } - snaps[info.Name()] = fn + snaps[info.StoreName()] = fn } return snaps, err diff --git a/tests/lib/prepare-restore.sh b/tests/lib/prepare-restore.sh index 434b7ab32f..ca2f7eeccb 100755 --- a/tests/lib/prepare-restore.sh +++ b/tests/lib/prepare-restore.sh @@ -411,6 +411,9 @@ prepare_suite_each() { if is_classic_system; then prepare_each_classic fi + #shellcheck source=tests/lib/state.sh + . "$TESTSLIB"/state.sh + echo -n "$SPREAD_JOB " >> "$RUNTIME_STATE_PATH/runs" } restore_suite_each() { diff --git a/tests/lib/state.sh b/tests/lib/state.sh index 2e31e0d98b..65d273bbb0 100755 --- a/tests/lib/state.sh +++ b/tests/lib/state.sh @@ -1,7 +1,8 @@ #!/bin/bash SNAPD_STATE_PATH="$SPREAD_PATH/tests/snapd-state" -SNAPD_STATE_FILE="$SPREAD_PATH/tests/snapd-state.tar" +SNAPD_STATE_FILE="$SPREAD_PATH/tests/snapd-state/snapd-state.tar" +RUNTIME_STATE_PATH="$SPREAD_PATH/tests/runtime-state" # shellcheck source=tests/lib/dirs.sh . "$TESTSLIB/dirs.sh" @@ -13,19 +14,16 @@ SNAPD_STATE_FILE="$SPREAD_PATH/tests/snapd-state.tar" . "$TESTSLIB/systems.sh" delete_snapd_state() { - if is_core_system; then - rm -rf "$SNAPD_STATE_PATH" - else - rm -f "$SNAPD_STATE_FILE" - fi + rm -rf "$SNAPD_STATE_PATH" } save_snapd_state() { + mkdir -p "$SNAPD_STATE_PATH" "$RUNTIME_STATE_PATH" if is_core_system; then boot_path="$(get_boot_path)" test -n "$boot_path" || return 1 - mkdir -p "$SNAPD_STATE_PATH" "$SNAPD_STATE_PATH"/system-units + mkdir -p "$SNAPD_STATE_PATH"/system-units # Copy the state preserving the timestamps cp -a /var/lib/snapd "$SNAPD_STATE_PATH"/snapd-lib diff --git a/tests/main/econnreset/task.yaml b/tests/main/econnreset/task.yaml index 66085801d4..4ed2b4682c 100644 --- a/tests/main/econnreset/task.yaml +++ b/tests/main/econnreset/task.yaml @@ -1,5 +1,8 @@ summary: Ensure that ECONNRESET is handled restore: | + echo "Stop the snap download command" + kill -9 "$(pgrep -f 'snap download')" || true + echo "Remove the firewall rule again" iptables -D OUTPUT -m owner --uid-owner "$(id -u test)" -j REJECT -p tcp --reject-with tcp-reset || true @@ -14,6 +17,8 @@ debug: | ls -lh test-snapd-huge_* || true echo "other dir content" ls -lh + echo "download log:" + cat snap-download.log execute: | echo "Downloading a large snap in the background" @@ -22,17 +27,17 @@ execute: | echo "Wait until the download started and downloaded more than 1 MB" echo "starting: $(date)" - for _ in $(seq 400); do + for _ in $(seq 120); do partial=$(find . -name 'test-snapd-huge_*.snap.partial' | head -1) if [ -n "$partial" ] && [ "$(stat -c%s "$partial")" -gt "$(( 1024 * 1024 ))" ]; then break fi - sleep 0.1 + sleep 0.5 done if [ ! -f "$partial" ] || [ "$(stat -c%s "$partial")" -eq 0 ]; then echo "Partial file $partial did not start downloading, test broken" - kill -9 "$(pidof snap)" + kill -9 "$(pgrep -f 'snap download')" || true exit 1 fi @@ -40,6 +45,7 @@ execute: | echo "File fully downloaded before the test could act" echo "Test broken" echo "end: $(date)" + kill -9 "$(pgrep -f 'snap download')" || true exit 1 fi @@ -53,10 +59,16 @@ execute: | fi sleep .5 done + + if [ -n "$(find . -name 'test-snapd-huge_*.snap')" ]; then + echo "File fully downloaded even after iptables was applied" + echo "Test broken" + echo "end: $(date)" + exit 1 + fi + MATCH 'Retrying.*\.snap, attempt 2' < snap-download.log # Note that the download will not be successful because of the nature of # the netfilter testbed. When snap download retries the next attempt will # end up with a "connection refused" error, something we do not retry -debug: | - cat snap-download.log diff --git a/tests/main/security-setuid-root/task.yaml b/tests/main/security-setuid-root/task.yaml index a8e619879f..c44160af13 100644 --- a/tests/main/security-setuid-root/task.yaml +++ b/tests/main/security-setuid-root/task.yaml @@ -16,12 +16,12 @@ prepare: | . $TESTSLIB/snaps.sh install_local test-snapd-tools echo "Ensure the snap-confine profiles on core are not loaded" - for p in /etc/apparmor.d/snap.core.*.usr.lib.snapd.snap-confine; do + for p in /var/lib/snapd/apparmor/profiles/snap-confine.*; do apparmor_parser -R "$p" done restore: | echo "Ensure the snap-confine profiles are restored" - for p in /etc/apparmor.d/snap.core.*.usr.lib.snapd.snap-confine; do + for p in /var/lib/snapd/apparmor/profiles/snap-confine.*; do apparmor_parser -r $p done execute: | diff --git a/tests/main/snap-confine-from-core/task.yaml b/tests/main/snap-confine-from-core/task.yaml index 47ed34fbe2..a98e7f2f52 100644 --- a/tests/main/snap-confine-from-core/task.yaml +++ b/tests/main/snap-confine-from-core/task.yaml @@ -50,23 +50,23 @@ execute: | fi echo "Ensure snapd generates the right apparmor profile on restart" - PROFILES="$(find /etc/apparmor.d/ -maxdepth 1 -name "snap.core.*.snap-confine")" + PROFILES="$(find /var/lib/snapd/apparmor/profiles/ -maxdepth 1 -name "snap-confine.*")" if [ -z "$PROFILES" ]; then echo "cannot find apparmor profiles for snap-confine from core" echo "test broken" - ls -al /etc/apparmor.d + ls -al /var/lib/snapd/apparmor/profiles exit 1 fi echo "Force system-key change" systemd_stop_units snapd.service snapd.socket printf '{"version":1}' > /var/lib/snapd/system-key - rm -f /etc/apparmor.d/snap.core.*.snap-confine + rm -f /var/lib/snapd/apparmor/profiles/snap-confine.* systemctl start snapd.service snapd.socket wait_for_service snapd.service echo "Ensure this also re-generates the snap-confine from core profile" - PROFILES="$(find /etc/apparmor.d/ -maxdepth 1 -name "snap.core.*.snap-confine")" + PROFILES="$(find /var/lib/snapd/apparmor/profiles/ -maxdepth 1 -name "snap-confine.*")" if [ -z "$PROFILES" ]; then echo "apparmor profiles for snap-confine from core were not re-generated" echo "test broken" diff --git a/wrappers/desktop.go b/wrappers/desktop.go index 93426e30aa..0c8328a6d7 100644 --- a/wrappers/desktop.go +++ b/wrappers/desktop.go @@ -108,6 +108,8 @@ func rewriteExecLine(s *snap.Info, desktopFile, line string) (string, error) { cmd := strings.SplitN(line, "=", 2)[1] for _, app := range s.Apps { + // TODO parallel-install: adjust valid command checks to account + // for instance name wrapper := app.WrapperPath() validCmd := filepath.Base(wrapper) // check the prefix to allow %flag style args @@ -120,7 +122,7 @@ func rewriteExecLine(s *snap.Info, desktopFile, line string) (string, error) { } } - logger.Noticef("cannot use line %q for desktop file %q (snap %s)", line, desktopFile, s.Name()) + logger.Noticef("cannot use line %q for desktop file %q (snap %s)", line, desktopFile, s.InstanceName()) // The Exec= line in the desktop file is invalid. Instead of failing // hard we rewrite the Exec= line. The convention is that the desktop // file has the same name as the application we can use this fact here. @@ -214,7 +216,7 @@ func AddSnapDesktopFiles(s *snap.Info) (err error) { return err } - installedDesktopFileName := filepath.Join(dirs.SnapDesktopFilesDir, fmt.Sprintf("%s_%s", s.Name(), filepath.Base(df))) + installedDesktopFileName := filepath.Join(dirs.SnapDesktopFilesDir, fmt.Sprintf("%s_%s", s.InstanceName(), filepath.Base(df))) content = sanitizeDesktopFile(s, installedDesktopFileName, content) if err := osutil.AtomicWriteFile(installedDesktopFileName, content, 0755, 0); err != nil { return err @@ -232,7 +234,8 @@ func AddSnapDesktopFiles(s *snap.Info) (err error) { // RemoveSnapDesktopFiles removes the added desktop files for the applications in the snap. func RemoveSnapDesktopFiles(s *snap.Info) error { - glob := filepath.Join(dirs.SnapDesktopFilesDir, s.Name()+"_*.desktop") + // TODO parallel-install: verify use of instance names here + glob := filepath.Join(dirs.SnapDesktopFilesDir, s.InstanceName()+"_*.desktop") activeDesktopFiles, err := filepath.Glob(glob) if err != nil { return fmt.Errorf("cannot get desktop files for %v: %s", glob, err) diff --git a/wrappers/services.go b/wrappers/services.go index fbb61068ec..8407849689 100644 --- a/wrappers/services.go +++ b/wrappers/services.go @@ -372,7 +372,7 @@ func genServiceNames(snap *snap.Info, appNames []string) []string { func genServiceFile(appInfo *snap.AppInfo) []byte { serviceTemplate := `[Unit] # Auto-generated, DO NOT EDIT -Description=Service for snap application {{.App.Snap.Name}}.{{.App.Name}} +Description=Service for snap application {{.App.Snap.InstanceName}}.{{.App.Name}} Requires={{.MountUnit}} Wants={{.PrerequisiteTarget}} After={{.MountUnit}} {{.PrerequisiteTarget}}{{range .After}} {{.}}{{end}} @@ -383,7 +383,7 @@ X-Snappy=yes [Service] ExecStart={{.App.LauncherCommand}} -SyslogIdentifier={{.App.Snap.Name}}.{{.App.Name}} +SyslogIdentifier={{.App.Snap.InstanceName}}.{{.App.Name}} Restart={{.Restart}} WorkingDirectory={{.App.Snap.DataDir}} {{- if .App.StopCommand}} @@ -489,7 +489,7 @@ WantedBy={{.ServicesTarget}} func genServiceSocketFile(appInfo *snap.AppInfo, socketName string) []byte { socketTemplate := `[Unit] # Auto-generated, DO NO EDIT -Description=Socket {{.SocketName}} for snap application {{.App.Snap.Name}}.{{.App.Name}} +Description=Socket {{.SocketName}} for snap application {{.App.Snap.InstanceName}}.{{.App.Name}} Requires={{.MountUnit}} Wants={{.PrerequisiteTarget}} After={{.MountUnit}} {{.PrerequisiteTarget}} @@ -558,7 +558,7 @@ func renderListenStream(socket *snap.SocketInfo) string { func generateSnapTimerFile(app *snap.AppInfo) ([]byte, error) { timerTemplate := `[Unit] # Auto-generated, DO NOT EDIT -Description=Timer {{.TimerName}} for snap application {{.App.Snap.Name}}.{{.App.Name}} +Description=Timer {{.TimerName}} for snap application {{.App.Snap.InstanceName}}.{{.App.Name}} Requires={{.MountUnit}} After={{.MountUnit}} X-Snappy=yes |
