Esempio n. 1
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()),
		})
	}
}
Esempio n. 2
0
// basicEnv returns the app-level environment variables for a snap.
// Despite this being a bit snap-specific, this is in helpers.go because it's
// 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 {
	return map[string]string{
		"SNAP":              info.MountDir(),
		"SNAP_COMMON":       info.CommonDataDir(),
		"SNAP_DATA":         info.DataDir(),
		"SNAP_NAME":         info.Name(),
		"SNAP_VERSION":      info.Version,
		"SNAP_REVISION":     info.Revision.String(),
		"SNAP_ARCH":         arch.UbuntuArchitecture(),
		"SNAP_LIBRARY_PATH": "/var/lib/snapd/lib/gl:",
		"SNAP_REEXEC":       os.Getenv("SNAP_REEXEC"),
	}
}
Esempio n. 3
0
func (ts *HTestSuite) TestBasic(c *C) {
	env := basicEnv(mockSnapInfo)

	c.Assert(env, DeepEquals, map[string]string{
		"SNAP":              fmt.Sprintf("%s/foo/17", dirs.SnapMountDir),
		"SNAP_ARCH":         arch.UbuntuArchitecture(),
		"SNAP_COMMON":       "/var/snap/foo/common",
		"SNAP_DATA":         "/var/snap/foo/17",
		"SNAP_LIBRARY_PATH": "/var/lib/snapd/lib/gl:",
		"SNAP_NAME":         "foo",
		"SNAP_REEXEC":       "",
		"SNAP_REVISION":     "17",
		"SNAP_VERSION":      "1.0",
	})

}
Esempio n. 4
0
func (s *checkSnapSuite) TestCheckSnapErrorOnUnsupportedArchitecture(c *C) {
	const yaml = `name: hello
version: 1.10
architectures:
    - yadayada
    - blahblah
`
	info, err := snap.InfoFromSnapYaml([]byte(yaml))
	c.Assert(err, IsNil)

	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
		c.Check(path, Equals, "snap-path")
		c.Check(si, IsNil)
		return info, nil, nil
	}
	restore := snapstate.MockOpenSnapFile(openSnapFile)
	defer restore()

	err = snapstate.CheckSnap(s.st, "snap-path", nil, nil, snapstate.Flags{})

	errorMsg := fmt.Sprintf(`snap "hello" supported architectures (yadayada, blahblah) are incompatible with this system (%s)`, arch.UbuntuArchitecture())
	c.Assert(err.Error(), Equals, errorMsg)
}
Esempio n. 5
0
// checkSnap ensures that the snap can be installed.
func checkSnap(st *state.State, snapFilePath string, curInfo *snap.Info, flags Flags) error {
	// This assumes that the snap was already verified or --dangerous was used.

	s, _, err := openSnapFile(snapFilePath, nil)
	if err != nil {
		return err
	}

	if s.NeedsDevMode() && !flags.DevModeAllowed() {
		return fmt.Errorf("snap %q requires devmode or confinement override", s.Name())
	}

	// verify we have a valid architecture
	if !arch.IsSupportedArchitecture(s.Architectures) {
		return fmt.Errorf("snap %q supported architectures (%s) are incompatible with this system (%s)", s.Name(), strings.Join(s.Architectures, ", "), arch.UbuntuArchitecture())
	}

	// check assumes
	err = checkAssumes(s)
	if err != nil {
		return err
	}

	if s.Type != snap.TypeGadget {
		return nil
	}

	// gadget specific checks
	if release.OnClassic {
		// for the time being
		return fmt.Errorf("cannot install a gadget snap on classic")
	}

	st.Lock()
	defer st.Unlock()
	currentGadget, err := GadgetInfo(st)
	// in firstboot we have no gadget yet - that is ok
	if err == state.ErrNoState && !firstboot.HasRun() {
		return nil
	}
	if err != nil {
		return fmt.Errorf("cannot find original gadget snap")
	}

	// TODO: actually compare snap ids, from current gadget and candidate
	if currentGadget.Name() != s.Name() {
		return fmt.Errorf("cannot replace gadget snap with a different one")
	}

	return nil
}
Esempio n. 6
0
func SetUserAgentFromVersion(version string) {
	extras := make([]string, 1, 3)
	extras[0] = "series " + release.Series
	if release.OnClassic {
		extras = append(extras, "classic")
	}
	if release.ReleaseInfo.ForceDevMode() {
		extras = append(extras, "devmode")
	}
	// xxx this assumes ReleaseInfo's ID and VersionID don't have weird characters
	// (see rfc 7231 for values of weird)
	// assumption checks out in practice, q.v. https://github.com/zyga/os-release-zoo
	userAgent = fmt.Sprintf("snapd/%v (%s) %s/%s (%s)", version, strings.Join(extras, "; "), release.ReleaseInfo.ID, release.ReleaseInfo.VersionID, string(arch.UbuntuArchitecture()))
}
Esempio n. 7
0
// New creates a new Store with the given access configuration and for given the store id.
func New(cfg *Config, authContext auth.AuthContext) *Store {
	if cfg == nil {
		cfg = &defaultConfig
	}

	fields := cfg.DetailFields
	if fields == nil {
		fields = detailFields
	}

	rawQuery := ""
	if len(fields) > 0 {
		v := url.Values{}
		v.Set("fields", strings.Join(fields, ","))
		rawQuery = v.Encode()
	}

	var searchURI *url.URL
	if cfg.SearchURI != nil {
		uri := *cfg.SearchURI
		uri.RawQuery = rawQuery
		searchURI = &uri
	}

	var detailsURI *url.URL
	if cfg.DetailsURI != nil {
		uri := *cfg.DetailsURI
		uri.RawQuery = rawQuery
		detailsURI = &uri
	}

	var sectionsURI *url.URL
	if cfg.SectionsURI != nil {
		uri := *cfg.SectionsURI
		uri.RawQuery = rawQuery
		sectionsURI = &uri
	}

	architecture := arch.UbuntuArchitecture()
	if cfg.Architecture != "" {
		architecture = cfg.Architecture
	}

	series := release.Series
	if cfg.Series != "" {
		series = cfg.Series
	}

	deltaFormat := cfg.DeltaFormat
	if deltaFormat == "" {
		deltaFormat = defaultSupportedDeltaFormat
	}

	// see https://wiki.ubuntu.com/AppStore/Interfaces/ClickPackageIndex
	return &Store{
		searchURI:       searchURI,
		detailsURI:      detailsURI,
		bulkURI:         cfg.BulkURI,
		assertionsURI:   cfg.AssertionsURI,
		ordersURI:       cfg.OrdersURI,
		customersMeURI:  cfg.CustomersMeURI,
		sectionsURI:     sectionsURI,
		series:          series,
		architecture:    architecture,
		fallbackStoreID: cfg.StoreID,
		detailFields:    fields,
		authContext:     authContext,
		deltaFormat:     deltaFormat,

		client: newHTTPClient(&httpClientOpts{
			Timeout:    10 * time.Second,
			MayLogBody: true,
		}),
	}
}
Esempio n. 8
0
// New creates a new Store with the given access configuration and for given the store id.
func New(cfg *Config, authContext auth.AuthContext) *Store {
	deltaDirs, _ := filepath.Glob(filepath.Join(dirs.SnapPartialBlobDir, "deltas-*"))
	for _, dir := range deltaDirs {
		os.RemoveAll(dir)
	}

	if cfg == nil {
		cfg = &defaultConfig
	}

	fields := cfg.DetailFields
	if fields == nil {
		fields = detailFields
	}

	rawQuery := ""
	if len(fields) > 0 {
		v := url.Values{}
		v.Set("fields", strings.Join(fields, ","))
		rawQuery = v.Encode()
	}

	var searchURI *url.URL
	if cfg.SearchURI != nil {
		uri := *cfg.SearchURI
		uri.RawQuery = rawQuery
		searchURI = &uri
	}

	var detailsURI *url.URL
	if cfg.DetailsURI != nil {
		uri := *cfg.DetailsURI
		uri.RawQuery = rawQuery
		detailsURI = &uri
	}

	architecture := arch.UbuntuArchitecture()
	if cfg.Architecture != "" {
		architecture = cfg.Architecture
	}

	series := release.Series
	if cfg.Series != "" {
		series = cfg.Series
	}

	deltaFormat := cfg.DeltaFormat
	if deltaFormat == "" {
		deltaFormat = defaultSupportedDeltaFormat
	}

	// see https://wiki.ubuntu.com/AppStore/Interfaces/ClickPackageIndex
	return &Store{
		searchURI:       searchURI,
		detailsURI:      detailsURI,
		bulkURI:         cfg.BulkURI,
		assertionsURI:   cfg.AssertionsURI,
		ordersURI:       cfg.OrdersURI,
		customersMeURI:  cfg.CustomersMeURI,
		series:          series,
		architecture:    architecture,
		fallbackStoreID: cfg.StoreID,
		detailFields:    fields,
		client:          newHTTPClient(),
		authContext:     authContext,
		deltaFormat:     deltaFormat,
	}
}
Esempio n. 9
0
[Service]
ExecStart=/usr/bin/snap run snap.app
Restart=on-failure
WorkingDirectory=/var/snap/snap/44
ExecStop=/usr/bin/snap run --command=stop snap.app
ExecStopPost=/usr/bin/snap run --command=post-stop snap.app
TimeoutStopSec=10
%[2]s

[Install]
WantedBy=multi-user.target
`

var (
	expectedAppService  = fmt.Sprintf(expectedServiceFmt, "After=snapd.frameworks.target\nRequires=snapd.frameworks.target", "Type=simple\n", arch.UbuntuArchitecture(), dirs.SnapMountDir)
	expectedDbusService = fmt.Sprintf(expectedServiceFmt, "After=snapd.frameworks.target\nRequires=snapd.frameworks.target", "Type=dbus\nBusName=foo.bar.baz", arch.UbuntuArchitecture(), dirs.SnapMountDir)
)

var (
	expectedServiceWrapperFmt = `[Unit]
# Auto-generated, DO NO EDIT
Description=Service for snap application xkcd-webserver.xkcd-webserver
%s
X-Snappy=yes

[Service]
ExecStart=/usr/bin/snap run xkcd-webserver
Restart=on-failure
WorkingDirectory=/var/snap/xkcd-webserver/44
ExecStop=/usr/bin/snap run --command=stop xkcd-webserver
Esempio n. 10
0
// checkSnap ensures that the snap can be installed.
func checkSnap(st *state.State, snapFilePath string, si *snap.SideInfo, curInfo *snap.Info, flags Flags) error {
	// This assumes that the snap was already verified or --dangerous was used.

	s, _, err := openSnapFile(snapFilePath, si)
	if err != nil {
		return err
	}

	if s.NeedsDevMode() && !flags.DevModeAllowed() {
		return fmt.Errorf("snap %q requires devmode or confinement override", s.Name())
	}
	if s.NeedsClassic() {
		if !release.OnClassic {
			return fmt.Errorf("snap %q requires classic confinement which is only available on classic systems", s.Name())
		}
		if !flags.Classic {
			return fmt.Errorf("snap %q requires consent to use classic confinement", s.Name())
		}
	}

	// verify we have a valid architecture
	if !arch.IsSupportedArchitecture(s.Architectures) {
		return fmt.Errorf("snap %q supported architectures (%s) are incompatible with this system (%s)", s.Name(), strings.Join(s.Architectures, ", "), arch.UbuntuArchitecture())
	}

	// check assumes
	err = checkAssumes(s)
	if err != nil {
		return err
	}

	st.Lock()
	defer st.Unlock()

	for _, check := range checkSnapCallbacks {
		err := check(st, s, curInfo, flags)
		if err != nil {
			return err
		}
	}

	return nil
}
Esempio n. 11
0
func archWithBrokenDevPtmx() error {
	if ubuArch := arch.UbuntuArchitecture(); ubuArch == "ppc64el" || ubuArch == "powerpc" {
		return fmt.Errorf("/dev/ptmx ioctl not working on %s", ubuArch)
	}
	return nil
}