// MockSnap puts a snap.yaml file on disk so to mock an installed snap, based on the provided arguments. // // The caller is responsible for mocking root directory with dirs.SetRootDir() // and for altering the overlord state if required. func MockSnap(c *check.C, yamlText string, snapContents string, sideInfo *snap.SideInfo) *snap.Info { c.Assert(sideInfo, check.Not(check.IsNil)) // Parse the yaml (we need the Name). snapInfo, err := snap.InfoFromSnapYaml([]byte(yamlText)) c.Assert(err, check.IsNil) // Set SideInfo so that we can use MountDir below snapInfo.SideInfo = *sideInfo // Put the YAML on disk, in the right spot. metaDir := filepath.Join(snapInfo.MountDir(), "meta") err = os.MkdirAll(metaDir, 0755) c.Assert(err, check.IsNil) err = ioutil.WriteFile(filepath.Join(metaDir, "snap.yaml"), []byte(yamlText), 0644) c.Assert(err, check.IsNil) // Write the .snap to disk err = os.MkdirAll(filepath.Dir(snapInfo.MountFile()), 0755) c.Assert(err, check.IsNil) err = ioutil.WriteFile(snapInfo.MountFile(), []byte(snapContents), 0644) c.Assert(err, check.IsNil) snapInfo.Size = int64(len(snapContents)) return snapInfo }
func (s *snapExecSuite) TestFindCommandNoCommand(c *C) { info, err := snap.InfoFromSnapYaml(mockYaml) c.Assert(err, IsNil) _, err = findCommand(info.Apps["nostop"], "stop") c.Check(err, ErrorMatches, `no "stop" command found for "nostop"`) }
func (f *fakeSnappyBackend) ReadInfo(name string, si *snap.SideInfo) (*snap.Info, error) { if name == "borken" { return nil, errors.New(`cannot read info for "borken" snap`) } // naive emulation for now, always works info := &snap.Info{SuggestedName: name, SideInfo: *si} info.Type = snap.TypeApp if name == "gadget" { info.Type = snap.TypeGadget } if name == "core" { info.Type = snap.TypeOS } if name == "alias-snap" { var err error info, err = snap.InfoFromSnapYaml([]byte(`name: alias-snap apps: cmd1: aliases: [alias1, alias1.cmd1] cmd2: aliases: [alias2] cmd3: aliases: [alias3] cmd4: aliases: [alias4] cmd5: aliases: [alias5] `)) if err != nil { panic(err) } info.SideInfo = *si } return info, nil }
func (s *snapExecSuite) TestFindCommandInvalidCommand(c *C) { info, err := snap.InfoFromSnapYaml(mockYaml) c.Assert(err, IsNil) _, err = findCommand(info.Apps["app"], "xxx") c.Check(err, ErrorMatches, `cannot use "xxx" command`) }
func (s *YamlSuite) TestUnmarshalSlotsImplicitlyDefinedExplicitlyBoundToApps(c *C) { // NOTE: yaml content cannot use tabs, indent the section with spaces. info, err := snap.InfoFromSnapYaml([]byte(` name: snap apps: app: slots: ["network-client"] `)) c.Assert(err, IsNil) c.Check(info.Name(), Equals, "snap") c.Check(info.Plugs, HasLen, 0) c.Check(info.Slots, HasLen, 1) c.Check(info.Apps, HasLen, 1) slot := info.Slots["network-client"] app := info.Apps["app"] c.Assert(slot, DeepEquals, &snap.SlotInfo{ Snap: info, Name: "network-client", Interface: "network-client", Apps: map[string]*snap.AppInfo{app.Name: app}, }) c.Assert(app, DeepEquals, &snap.AppInfo{ Snap: info, Name: "app", Slots: map[string]*snap.SlotInfo{slot.Name: slot}, }) }
func (s *checkSnapSuite) TestCheckSnapGadgetCannotBeInstalledOnClassic(c *C) { reset := release.MockOnClassic(true) defer reset() st := state.New(nil) st.Lock() defer st.Unlock() const yaml = `name: gadget type: gadget version: 1 ` info, err := snap.InfoFromSnapYaml([]byte(yaml)) c.Assert(err, IsNil) var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { return info, nil, nil } restore := snapstate.MockOpenSnapFile(openSnapFile) defer restore() st.Unlock() err = snapstate.CheckSnap(st, "snap-path", nil, nil, snapstate.Flags{}) st.Lock() c.Check(err, ErrorMatches, "cannot install a gadget snap on classic") }
func (s *YamlSuite) TestUnmarshalExplicitGlobalPlugBoundToHook(c *C) { // NOTE: yaml content cannot use tabs, indent the section with spaces. info, err := snap.InfoFromSnapYaml([]byte(` name: snap plugs: test-plug: test-interface hooks: test-hook: plugs: ["test-plug"] `)) c.Assert(err, IsNil) c.Check(info.Name(), Equals, "snap") c.Check(info.Plugs, HasLen, 1) c.Check(info.Slots, HasLen, 0) c.Check(info.Apps, HasLen, 0) c.Check(info.Hooks, HasLen, 1) plug, ok := info.Plugs["test-plug"] c.Assert(ok, Equals, true, Commentf("Expected plugs to include 'test-plug'")) hook, ok := info.Hooks["test-hook"] c.Assert(ok, Equals, true, Commentf("Expected hooks to include 'test-hook'")) c.Check(plug, DeepEquals, &snap.PlugInfo{ Snap: info, Name: "test-plug", Interface: "test-interface", Hooks: map[string]*snap.HookInfo{hook.Name: hook}, }) c.Check(hook, DeepEquals, &snap.HookInfo{ Snap: info, Name: "test-hook", Plugs: map[string]*snap.PlugInfo{plug.Name: plug}, }) }
func (s *YamlSuite) TestUnmarshalEmpty(c *C) { info, err := snap.InfoFromSnapYaml([]byte(``)) c.Assert(err, IsNil) c.Assert(info.Plugs, HasLen, 0) c.Assert(info.Slots, HasLen, 0) c.Assert(info.Apps, HasLen, 0) }
func (s *YamlSuite) TestUnmarshalHookFiltersOutUnsupportedHooks(c *C) { s.restore() hookType := snap.NewHookType(regexp.MustCompile("test-.*")) s.restore = snap.MockSupportedHookTypes([]*snap.HookType{hookType}) // NOTE: yaml content cannot use tabs, indent the section with spaces. info, err := snap.InfoFromSnapYaml([]byte(` name: snap hooks: test-hook: foo-hook: `)) c.Assert(err, IsNil) c.Check(info.Name(), Equals, "snap") c.Check(info.Plugs, HasLen, 0) c.Check(info.Slots, HasLen, 0) c.Check(info.Apps, HasLen, 0) c.Check(info.Hooks, HasLen, 1) hook, ok := info.Hooks["test-hook"] c.Assert(ok, Equals, true, Commentf("Expected hooks to include 'test-hook'")) c.Check(hook, DeepEquals, &snap.HookInfo{ Snap: info, Name: "test-hook", Plugs: nil, }) }
func (s *HTestSuite) TestSnapRunSnapExecEnv(c *C) { info, err := snap.InfoFromSnapYaml(mockYaml) c.Assert(err, IsNil) info.SideInfo.Revision = snap.R(42) usr, err := user.Current() c.Assert(err, IsNil) homeEnv := os.Getenv("HOME") defer os.Setenv("HOME", homeEnv) for _, withHomeEnv := range []bool{true, false} { if !withHomeEnv { os.Setenv("HOME", "") } env := snapEnv(info) c.Check(env, DeepEquals, map[string]string{ "HOME": fmt.Sprintf("%s/snap/snapname/42", usr.HomeDir), "SNAP": fmt.Sprintf("%s/snapname/42", dirs.SnapMountDir), "SNAP_ARCH": arch.UbuntuArchitecture(), "SNAP_COMMON": "/var/snap/snapname/common", "SNAP_DATA": "/var/snap/snapname/42", "SNAP_LIBRARY_PATH": "/var/lib/snapd/lib/gl:", "SNAP_NAME": "snapname", "SNAP_REEXEC": "", "SNAP_REVISION": "42", "SNAP_USER_COMMON": fmt.Sprintf("%s/snap/snapname/common", usr.HomeDir), "SNAP_USER_DATA": fmt.Sprintf("%s/snap/snapname/42", usr.HomeDir), "SNAP_VERSION": "1.0", "XDG_RUNTIME_DIR": fmt.Sprintf("/run/user/%d/snap.snapname", os.Geteuid()), }) } }
func (s *checkSnapSuite) TestCheckSnapGadgetMissingPrior(c *C) { err := os.MkdirAll(filepath.Dir(dirs.SnapFirstBootStamp), 0755) c.Assert(err, IsNil) err = ioutil.WriteFile(dirs.SnapFirstBootStamp, nil, 0644) c.Assert(err, IsNil) reset := release.MockOnClassic(false) defer reset() st := state.New(nil) st.Lock() defer st.Unlock() const yaml = `name: gadget type: gadget version: 1 ` info, err := snap.InfoFromSnapYaml([]byte(yaml)) c.Assert(err, IsNil) var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { return info, nil, nil } restore := snapstate.MockOpenSnapFile(openSnapFile) defer restore() st.Unlock() err = snapstate.CheckSnap(st, "snap-path", nil, 0) st.Lock() c.Check(err, ErrorMatches, "cannot find original gadget snap") }
func prepare(sourceDir, targetDir, buildDir string) (snapName string, err error) { // ensure we have valid content yaml, err := ioutil.ReadFile(filepath.Join(sourceDir, "meta", "snap.yaml")) if err != nil { return "", err } info, err := snap.InfoFromSnapYaml(yaml) if err != nil { return "", err } err = snap.Validate(info) if err != nil { return "", err } if err := copyToBuildDir(sourceDir, buildDir); err != nil { return "", err } // build the package snapName = fmt.Sprintf("%s_%s_%v.snap", info.Name(), info.Version, debArchitecture(info)) if targetDir != "" { snapName = filepath.Join(targetDir, snapName) if _, err := os.Stat(targetDir); os.IsNotExist(err) { if err := os.MkdirAll(targetDir, 0755); err != nil { return "", err } } } return snapName, nil }
func (s *InfoSnapYamlTestSuite) TestSimple(c *C) { info, err := snap.InfoFromSnapYaml(mockYaml) c.Assert(err, IsNil) c.Assert(info.Name(), Equals, "foo") c.Assert(info.Version, Equals, "1.0") c.Assert(info.Type, Equals, snap.TypeApp) }
func (s *YamlSuite) TestUnmarshalStandaloneSlotWithIntAndListAndMap(c *C) { // NOTE: yaml content cannot use tabs, indent the section with spaces. info, err := snap.InfoFromSnapYaml([]byte(` name: snap slots: iface: interface: complex i: 3 l: [1,2] m: a: "A" `)) c.Assert(err, IsNil) c.Check(info.Name(), Equals, "snap") c.Check(info.Plugs, HasLen, 0) c.Check(info.Slots, HasLen, 1) c.Assert(info.Slots["iface"], DeepEquals, &snap.SlotInfo{ Snap: info, Name: "iface", Interface: "complex", Attrs: map[string]interface{}{ "i": int64(3), "l": []interface{}{int64(1), int64(2)}, "m": map[string]interface{}{"a": "A"}, }, }) }
func (s *servicesWrapperGenSuite) TestGenServiceFileWithBusName(c *C) { yamlText := ` name: snap version: 1.0 apps: app: command: bin/start stop-command: bin/stop post-stop-command: bin/stop --post stop-timeout: 10s bus-name: foo.bar.baz daemon: dbus ` info, err := snap.InfoFromSnapYaml([]byte(yamlText)) c.Assert(err, IsNil) info.Revision = snap.R(44) app := info.Apps["app"] wrapperText, err := wrappers.GenerateSnapServiceFile(app) c.Assert(err, IsNil) c.Assert(wrapperText, Equals, expectedDbusService) }
func (s *servicesWrapperGenSuite) TestGenerateSnapServiceFileRestart(c *C) { yamlTextTemplate := ` name: snap apps: app: restart-condition: %s ` for name, cond := range systemd.RestartMap { yamlText := fmt.Sprintf(yamlTextTemplate, cond) info, err := snap.InfoFromSnapYaml([]byte(yamlText)) c.Assert(err, IsNil) info.Revision = snap.R(44) app := info.Apps["app"] wrapperText, err := wrappers.GenerateSnapServiceFile(app) c.Assert(err, IsNil) if cond == systemd.RestartNever { c.Check(wrapperText, Matches, `(?ms).*^Restart=no$.*`, Commentf(name)) } else { c.Check(wrapperText, Matches, `(?ms).*^Restart=`+name+`$.*`, Commentf(name)) } } }
func (s *checkSnapSuite) TestCheckSnapGadgetNoPrior(c *C) { reset := release.MockOnClassic(false) defer reset() st := state.New(nil) st.Lock() defer st.Unlock() st.Set("seeded", true) const yaml = `name: gadget type: gadget version: 1 ` info, err := snap.InfoFromSnapYaml([]byte(yaml)) c.Assert(err, IsNil) var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { return info, nil, nil } restore := snapstate.MockOpenSnapFile(openSnapFile) defer restore() st.Unlock() err = snapstate.CheckSnap(st, "snap-path", nil, nil, snapstate.Flags{}) st.Lock() c.Check(err, IsNil) }
func (s *DockerSupportInterfaceSuite) TestSanitizePlugWithPrivilegedTrue(c *C) { var mockSnapYaml = []byte(`name: docker version: 1.0 plugs: privileged: interface: docker-support privileged-containers: true `) info, err := snap.InfoFromSnapYaml(mockSnapYaml) c.Assert(err, IsNil) info.SideInfo = snap.SideInfo{Developer: "docker"} plug := &interfaces.Plug{PlugInfo: info.Plugs["privileged"]} err = s.iface.SanitizePlug(plug) c.Assert(err, IsNil) snippet, err := s.iface.ConnectedPlugSnippet(plug, s.slot, interfaces.SecurityAppArmor) c.Assert(err, IsNil) c.Assert(string(snippet), testutil.Contains, `change_profile -> *,`) snippet, err = s.iface.ConnectedPlugSnippet(plug, s.slot, interfaces.SecuritySecComp) c.Assert(err, IsNil) c.Assert(string(snippet), testutil.Contains, `@unrestricted`) }
func (s *YamlSuite) TestDaemonEverythingExample(c *C) { y := []byte(`name: wat version: 42 apps: svc: command: svc1 description: svc one stop-timeout: 25s daemon: forking stop-command: stop-cmd post-stop-command: post-stop-cmd restart-condition: on-abnormal bus-name: busName `) info, err := snap.InfoFromSnapYaml(y) c.Assert(err, IsNil) c.Check(info.Apps, DeepEquals, map[string]*snap.AppInfo{ "svc": { Snap: info, Name: "svc", Command: "svc1", Daemon: "forking", RestartCond: systemd.RestartOnAbnormal, StopTimeout: timeout.Timeout(25 * time.Second), StopCommand: "stop-cmd", PostStopCommand: "post-stop-cmd", BusName: "busName", }, }) }
func (s *YamlSuite) TestSnapYamlEpochDefault(c *C) { y := []byte(`name: binary version: 1.0 `) info, err := snap.InfoFromSnapYaml(y) c.Assert(err, IsNil) c.Assert(info.Epoch, Equals, "0") }
func (s *YamlSuite) TestSnapYamlNoArchitecturesParsing(c *C) { y := []byte(`name: binary version: 1.0 `) info, err := snap.InfoFromSnapYaml(y) c.Assert(err, IsNil) c.Assert(info.Architectures, DeepEquals, []string{"all"}) }
func (s *YamlSuite) TestSnapYamlConfinementDefault(c *C) { y := []byte(`name: binary version: 1.0 `) info, err := snap.InfoFromSnapYaml(y) c.Assert(err, IsNil) c.Assert(info.Confinement, Equals, snap.StrictConfinement) }
func (s *YamlSuite) TestSnapYamlTypeDefault(c *C) { y := []byte(`name: binary version: 1.0 `) info, err := snap.InfoFromSnapYaml(y) c.Assert(err, IsNil) c.Assert(info.Type, Equals, snap.TypeApp) }
func (s *YamlSuite) TestSnapYamlMultipleArchitecturesParsing(c *C) { y := []byte(`name: binary version: 1.0 architectures: [i386, armhf] `) info, err := snap.InfoFromSnapYaml(y) c.Assert(err, IsNil) c.Assert(info.Architectures, DeepEquals, []string{"i386", "armhf"}) }
func (s *YamlSuite) TestUnmarshalCorruptedSlotWithUnexpectedType(c *C) { // NOTE: yaml content cannot use tabs, indent the section with spaces. _, err := snap.InfoFromSnapYaml([]byte(` name: snap slots: net: 5 `)) c.Assert(err, ErrorMatches, `slot "net" has malformed definition \(found int\)`) }
func (s *YamlSuite) TestSnapYamlAssumesParsing(c *C) { y := []byte(`name: binary version: 1.0 assumes: [feature2, feature1] `) info, err := snap.InfoFromSnapYaml(y) c.Assert(err, IsNil) c.Assert(info.Assumes, DeepEquals, []string{"feature1", "feature2"}) }
// classic confinement func (s *YamlSuite) TestClassicConfinement(c *C) { y := []byte(` name: foo confinement: classic `) info, err := snap.InfoFromSnapYaml(y) c.Assert(err, IsNil) c.Assert(info.Confinement, Equals, snap.ClassicConfinement) }
func (s *YamlSuite) TestUnmarshalCorruptedSlotWithNonStringLabel(c *C) { // NOTE: yaml content cannot use tabs, indent the section with spaces. _, err := snap.InfoFromSnapYaml([]byte(` name: snap slots: bool-file: label: 1.0 `)) c.Assert(err, ErrorMatches, `label of slot "bool-file" is not a string \(found float64\)`) }
func (s *YamlSuite) TestUnmarshalCorruptedSlotWithNonStringAttributes(c *C) { // NOTE: yaml content cannot use tabs, indent the section with spaces. _, err := snap.InfoFromSnapYaml([]byte(` name: snap slots: net: 1: ok `)) c.Assert(err, ErrorMatches, `slot "net" has attribute that is not a string \(found int\)`) }
func infoFromSnapYaml(c *C, snapYaml string, rev snap.Revision) *snap.Info { info, err := snap.InfoFromSnapYaml([]byte(snapYaml)) c.Assert(err, IsNil) if !rev.Unset() { info.SnapID = info.Name() + "-Id" info.Revision = rev } return info }