Beispiel #1
0
// 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
}
Beispiel #2
0
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"`)
}
Beispiel #3
0
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
}
Beispiel #4
0
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`)
}
Beispiel #5
0
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},
	})
}
Beispiel #6
0
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")
}
Beispiel #7
0
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},
	})
}
Beispiel #8
0
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)
}
Beispiel #9
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,
	})
}
Beispiel #10
0
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()),
		})
	}
}
Beispiel #11
0
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")
}
Beispiel #12
0
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
}
Beispiel #13
0
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)
}
Beispiel #14
0
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"},
		},
	})
}
Beispiel #15
0
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)
}
Beispiel #16
0
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))
		}
	}
}
Beispiel #17
0
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)
}
Beispiel #18
0
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`)
}
Beispiel #19
0
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",
		},
	})
}
Beispiel #20
0
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")
}
Beispiel #21
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"})
}
Beispiel #22
0
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)
}
Beispiel #23
0
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)
}
Beispiel #24
0
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"})
}
Beispiel #25
0
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\)`)
}
Beispiel #26
0
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"})
}
Beispiel #27
0
// 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)
}
Beispiel #28
0
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\)`)
}
Beispiel #29
0
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\)`)
}
Beispiel #30
0
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
}