func (s *SnapTestSuite) setupSnappyDependentServices(c *C) (string, *MockProgressMeter) { inter := &MockProgressMeter{} fmkYaml := `name: fmk version: 1.0 type: framework version: ` fmkFile := makeTestSnapPackage(c, fmkYaml+"1") _, err := installClick(fmkFile, AllowUnauthenticated, inter, "") c.Assert(err, IsNil) packageYaml := `name: foo icon: foo.svg frameworks: - fmk services: - name: svc1 start: bin/hello - name: svc2 start: bin/bye version: ` snapFile := makeTestSnapPackage(c, packageYaml+"1.0") _, err = installClick(snapFile, AllowUnauthenticated, inter, testOrigin) c.Assert(err, IsNil) c.Assert(helpers.FileExists(filepath.Join(dirs.SnapServicesDir, "foo_svc1_1.0.service")), Equals, true) c.Assert(helpers.FileExists(filepath.Join(dirs.SnapServicesDir, "foo_svc2_1.0.service")), Equals, true) return fmkYaml, inter }
func (ts *FileLockTestSuite) TestFileLock(c *C) { lockfile := filepath.Join(c.MkDir(), "lock") c.Assert(helpers.FileExists(lockfile), Equals, false) lock := NewFileLock(lockfile) c.Assert(lock, Not(IsNil)) c.Assert(lock.Filename, Equals, lockfile) c.Assert(lock.realFile, IsNil) err := lock.Unlock() c.Assert(err, Equals, ErrNotLocked) // can only test non-blocking in a single process. err = lock.Lock(false) c.Assert(err, IsNil) c.Assert(helpers.FileExists(lockfile), Equals, true) c.Assert(lock.Filename, Equals, lockfile) c.Assert(lock.realFile, Not(IsNil)) err = lock.Lock(false) c.Assert(err, Equals, ErrAlreadyLocked) err = lock.Unlock() c.Assert(err, IsNil) c.Assert(helpers.FileExists(lockfile), Equals, false) c.Assert(lock.Filename, Equals, "") c.Assert(lock.realFile, IsNil) }
func (s *SnapTestSuite) TestSnappyHandleServicesOnInstall(c *C) { packageYaml := `name: foo icon: foo.svg services: - name: service start: bin/hello ` snapFile := makeTestSnapPackage(c, packageYaml+"version: 1.0") _, err := installClick(snapFile, AllowUnauthenticated, nil, "mvo") c.Assert(err, IsNil) servicesFile := filepath.Join(dirs.SnapServicesDir, "foo_service_1.0.service") c.Assert(helpers.FileExists(servicesFile), Equals, true) st, err := os.Stat(servicesFile) c.Assert(err, IsNil) // should _not_ be executable c.Assert(st.Mode().String(), Equals, "-rw-r--r--") // and that it gets removed on remove snapDir := filepath.Join(dirs.SnapSnapsDir, "foo.mvo", "1.0") yamlPath := filepath.Join(snapDir, "meta", "package.yaml") part, err := NewInstalledSnapPart(yamlPath, testOrigin) c.Assert(err, IsNil) err = part.remove(&progress.NullProgress{}) c.Assert(err, IsNil) c.Assert(helpers.FileExists(servicesFile), Equals, false) c.Assert(helpers.FileExists(snapDir), Equals, false) }
func (s *SnapTestSuite) TestRemoveHWAccess(c *C) { makeInstalledMockSnap(s.tempdir, "") err := AddHWAccess("hello-app", "/dev/ttyUSB0") // check that the udev rules file got created udevRulesFilename := "70-snappy_hwassign_hello-app.rules" c.Assert(helpers.FileExists(filepath.Join(dirs.SnapUdevRulesDir, udevRulesFilename)), Equals, true) writePaths, err := ListHWAccess("hello-app") c.Assert(err, IsNil) c.Assert(writePaths, DeepEquals, []string{"/dev/ttyUSB0"}) regenerateAppArmorRulesWasCalled := mockRegenerateAppArmorRules() err = RemoveHWAccess("hello-app", "/dev/ttyUSB0") c.Assert(err, IsNil) c.Assert(*regenerateAppArmorRulesWasCalled, Equals, true) writePaths, err = ListHWAccess("hello-app") c.Assert(err, IsNil) c.Assert(writePaths, HasLen, 0) // check that the udev rules file got removed on unassign c.Assert(helpers.FileExists(filepath.Join(dirs.SnapUdevRulesDir, udevRulesFilename)), Equals, false) // check the json.additional got cleaned out content, err := ioutil.ReadFile(filepath.Join(dirs.SnapAppArmorAdditionalDir, "hello-app.hwaccess.yaml")) c.Assert(err, IsNil) c.Assert(string(content), Equals, "{}\n") }
func (s *PartitionTestSuite) TestHandleAssets(c *C) { s.makeFakeUbootEnv(c) p := New() bootloader, err := bootloader(p) c.Assert(err, IsNil) // mock the hardwareYaml and the cacheDir hardwareSpecFile = makeHardwareYaml(c, "") cacheDir = c.MkDir() // create mock assets/ makeMockAssetsDir(c) // run the handle assets code err = bootloader.HandleAssets() c.Assert(err, IsNil) // ensure the files are where we expect them otherBootPath := bootloader.(*uboot).otherBootPath for _, f := range []string{"vmlinuz", "initrd.img", "dtbs/foo.dtb", "dtbs/bar.dtb"} { content, err := ioutil.ReadFile(filepath.Join(otherBootPath, f)) c.Assert(err, IsNil) // match content c.Assert(strings.HasSuffix(string(content), f), Equals, true) } // ensure nothing left behind c.Assert(helpers.FileExists(filepath.Join(cacheDir, "assets")), Equals, false) c.Assert(helpers.FileExists(hardwareSpecFile), Equals, false) }
func (s *purgeSuite) TestPurgeMultiContinuesOnFail(c *C) { inter := &MockProgressMeter{} ddirs0, _ := s.mkpkg(c, "v0") ddirs1, _ := s.mkpkg(c, "v1") ddirs2, _ := s.mkpkg(c, "v2") count := 0 anError := errors.New("fail") remove = func(n, v string) error { count++ // Fail to remove v1 if v == "v1" { return anError } return removeSnapData(n, v) } defer func() { remove = removeSnapData }() err := Purge("hello-app", 0, inter) c.Check(err, Equals, anError) c.Check(count, Equals, 6) for _, ddir := range ddirs0 { c.Check(helpers.FileExists(ddir), Equals, false) } for _, ddir := range ddirs1 { c.Check(helpers.FileExists(ddir), Equals, true) } for _, ddir := range ddirs2 { c.Check(helpers.FileExists(ddir), Equals, false) } c.Assert(inter.notified, HasLen, 2) c.Check(inter.notified[0], Matches, `unable to purge.*fail`) c.Check(inter.notified[1], Matches, `unable to purge.*fail`) }
func (s *purgeSuite) TestPurgeMultiContinuesOnFail(c *C) { inter := &MockProgressMeter{} ddir0, _ := s.mkpkg(c, "v0") ddir1, _ := s.mkpkg(c, "v1") ddir2, _ := s.mkpkg(c, "v2") count := 0 anError := errors.New("fail") remove = func(n, v string) error { count++ if count == 2 { return anError } return removeSnapData(n, v) } defer func() { remove = removeSnapData }() err := Purge("hello-app", 0, inter) c.Check(err, Equals, anError) c.Check(count, Equals, 3) c.Check(helpers.FileExists(ddir0), Equals, false) c.Check(helpers.FileExists(ddir1), Equals, true) c.Check(helpers.FileExists(ddir2), Equals, false) c.Assert(inter.notified, HasLen, 1) c.Check(inter.notified[0], Matches, `unable to purge.*fail`) }
func (s *SnapTestSuite) TestSnappyHandleServicesOnInstall(c *C) { snapYamlContent := `name: foo apps: service: command: bin/hello daemon: forking ` snapFile := makeTestSnapPackage(c, snapYamlContent+"version: 1.0") _, err := installClick(snapFile, AllowUnauthenticated, nil, "mvo") c.Assert(err, IsNil) servicesFile := filepath.Join(dirs.SnapServicesDir, "foo_service_1.0.service") c.Assert(helpers.FileExists(servicesFile), Equals, true) st, err := os.Stat(servicesFile) c.Assert(err, IsNil) // should _not_ be executable c.Assert(st.Mode().String(), Equals, "-rw-r--r--") // and that it gets removed on remove snapDir := filepath.Join(dirs.SnapSnapsDir, "foo.mvo", "1.0") yamlPath := filepath.Join(snapDir, "meta", "snap.yaml") part, err := NewInstalledSnapPart(yamlPath, testOrigin) c.Assert(err, IsNil) err = (&Overlord{}).Uninstall(part, &MockProgressMeter{}) c.Assert(err, IsNil) c.Assert(helpers.FileExists(servicesFile), Equals, false) c.Assert(helpers.FileExists(snapDir), Equals, false) }
func (s *SnapTestSuite) TestSnappyHandleBinariesOnInstall(c *C) { packageYaml := `name: foo icon: foo.svg binaries: - name: bin/bar ` snapFile := makeTestSnapPackage(c, packageYaml+"version: 1.0") _, err := installClick(snapFile, AllowUnauthenticated, nil, "mvo") c.Assert(err, IsNil) // ensure that the binary wrapper file go generated with the right // name binaryWrapper := filepath.Join(dirs.SnapBinariesDir, "foo.bar") c.Assert(helpers.FileExists(binaryWrapper), Equals, true) // and that it gets removed on remove snapDir := filepath.Join(dirs.SnapSnapsDir, "foo.mvo", "1.0") yamlPath := filepath.Join(snapDir, "meta", "package.yaml") part, err := NewInstalledSnapPart(yamlPath, testOrigin) c.Assert(err, IsNil) err = part.remove(&MockProgressMeter{}) c.Assert(err, IsNil) c.Assert(helpers.FileExists(binaryWrapper), Equals, false) c.Assert(helpers.FileExists(snapDir), Equals, false) }
// BootloaderDir returns the full path to the (mounted and writable) // bootloader-specific boot directory. func BootloaderDir() string { if helpers.FileExists(bootloaderUbootDir()) { return bootloaderUbootDir() } else if helpers.FileExists(bootloaderGrubDir()) { return bootloaderGrubDir() } return "" }
func (s *purgeSuite) TestPurgeMultiOK(c *C) { inter := &MockProgressMeter{} ddir0, _ := s.mkpkg(c, "v0") ddir1, _ := s.mkpkg(c, "v1") err := Purge("hello-app", 0, inter) c.Check(err, IsNil) c.Check(helpers.FileExists(ddir0), Equals, false) c.Check(helpers.FileExists(ddir1), Equals, false) c.Check(inter.notified, HasLen, 0) }
func (s *SquashfsTestSuite) TestUnpackMeta(c *C) { snap := makeSnap(c, "", "random-data") outputDir := c.MkDir() err := snap.UnpackMeta(outputDir) c.Assert(err, IsNil) // we got the meta/ stuff c.Assert(helpers.FileExists(filepath.Join(outputDir, "meta/package.yaml")), Equals, true) // ... but not the data c.Assert(helpers.FileExists(filepath.Join(outputDir, "data.bin")), Equals, false) }
func (s *purgeSuite) TestPurgeRemovedWorks(c *C) { inter := &MockProgressMeter{} ddir, part := s.mkpkg(c) err := part.remove(inter) c.Assert(err, IsNil) c.Check(helpers.FileExists(ddir), Equals, true) err = Purge("hello-app", 0, inter) c.Check(err, IsNil) c.Check(helpers.FileExists(ddir), Equals, false) }
func (ts *FileLockTestSuite) TestFileLock(c *C) { path := filepath.Join(c.MkDir(), "lock") c.Assert(helpers.FileExists(path), Equals, false) lock, err := lockfile.Lock(path, false) c.Assert(err, IsNil) c.Check(lock > 0, Equals, true) c.Assert(helpers.FileExists(path), Equals, true) err = lock.Unlock() c.Assert(err, IsNil) }
func (s *SnapTestSuite) TestRemoveAllHWAccess(c *C) { makeInstalledMockSnap(s.tempdir, "") err := AddHWAccess("hello-app", "/dev/ttyUSB0") c.Assert(err, IsNil) regenerateAppArmorRulesWasCalled := mockRegenerateAppArmorRules() c.Check(*regenerateAppArmorRulesWasCalled, Equals, false) c.Check(RemoveAllHWAccess("hello-app"), IsNil) c.Check(helpers.FileExists(filepath.Join(dirs.SnapUdevRulesDir, "70-snappy_hwassign_foo-app.rules")), Equals, false) c.Check(helpers.FileExists(filepath.Join(dirs.SnapAppArmorAdditionalDir, "hello-app.hwaccess.yaml")), Equals, false) c.Check(*regenerateAppArmorRulesWasCalled, Equals, true) }
func (s *OemSuite) TestCleanupOemHardwareRules(c *C) { m, err := parsePackageYamlData(hardwareYaml, false) c.Assert(err, IsNil) err = writeApparmorAdditionalFile(m) c.Assert(err, IsNil) additionalFile := filepath.Join(dirs.SnapAppArmorDir, "device-hive-iot-hal.json.additional") c.Assert(helpers.FileExists(additionalFile), Equals, true) err = cleanupOemHardwareUdevRules(m) c.Assert(err, IsNil) c.Assert(helpers.FileExists(additionalFile), Equals, false) }
func (s *SnapTestSuite) TestWriteCompatManifestJSONNoFollow(c *C) { manifest := []byte(`{ "name": "hello-world" } `) manifestJSON := filepath.Join(s.tempdir, "hello-world.some-origin.manifest") symlinkTarget := filepath.Join(s.tempdir, "symlink-target") os.Symlink(symlinkTarget, manifestJSON) c.Assert(helpers.FileExists(symlinkTarget), Equals, false) err := writeCompatManifestJSON(s.tempdir, manifest, "some-origin") c.Assert(err, IsNil) c.Check(helpers.FileExists(manifestJSON), Equals, true) c.Check(helpers.FileExists(symlinkTarget), Equals, false) }
// Icon returns the path to the icon func (s *SnapPart) Icon() string { if helpers.FileExists(iconPath(s)) { return iconPath(s) } return filepath.Join(s.basedir, s.m.Icon) }
func (s *RemoteSnapPart) downloadIcon(pbar progress.Meter) error { if err := os.MkdirAll(dirs.SnapIconsDir, 0755); err != nil { return err } iconPath := iconPath(s) if helpers.FileExists(iconPath) { return nil } req, err := http.NewRequest("GET", s.Icon(), nil) if err != nil { return err } w, err := os.OpenFile(iconPath, os.O_WRONLY|os.O_CREATE, 0644) if err != nil { return err } defer w.Close() if err := download("icon for package", w, req, pbar); err != nil { return err } return w.Sync() }
func (s *SnapPart) remove(inter interacter) (err error) { // TODO[JRL]: check the logic here. I'm not sure “remove // everything if active, and the click hooks if not” makes // sense. E.g. are we removing fmk bins on fmk upgrade? Etc. if err := removeClickHooks(s.m, s.origin, false); err != nil { return err } if err := s.deactivate(false, inter); err != nil && err != ErrSnapNotActive { return err } err = os.RemoveAll(s.basedir) if err != nil { return err } // best effort(?) os.Remove(filepath.Dir(s.basedir)) // don't fail if icon can't be removed if helpers.FileExists(iconPath(s)) { if err := os.Remove(iconPath(s)); err != nil { logger.Noticef("Failed to remove store icon %s: %s", iconPath(s), err) } } return nil }
func (s *purgeSuite) TestPurgeRemovedWorks(c *C) { inter := &MockProgressMeter{} ddirs, part := s.mkpkg(c) err := (&Overlord{}).Uninstall(part, &MockProgressMeter{}) c.Assert(err, IsNil) for _, ddir := range ddirs { c.Check(helpers.FileExists(ddir), Equals, true) } err = Purge("hello-app", 0, inter) c.Check(err, IsNil) for _, ddir := range ddirs { c.Check(helpers.FileExists(ddir), Equals, false) } }
func (s *PartitionTestSuite) TestSyncBootFilesWithAssets(c *C) { err := os.MkdirAll(bootloaderGrubDir, 0755) c.Assert(err, IsNil) runCommand = mockRunCommand b := grub{ bootloaderType{ currentBootPath: c.MkDir(), otherBootPath: c.MkDir(), bootloaderDir: c.MkDir(), }, } bootfile := filepath.Join(c.MkDir(), "bootfile") err = ioutil.WriteFile(bootfile, []byte(bootfile), 0644) c.Assert(err, IsNil) bootassets := map[string]string{ bootfile: filepath.Base(bootfile), } err = b.SyncBootFiles(bootassets) c.Assert(err, IsNil) dst := filepath.Join(b.bootloaderDir, bootassets[bootfile]) c.Check(helpers.FileExists(dst), Equals, true) c.Check(helpers.FilesAreEqual(bootfile, dst), Equals, true) }
func (s *purgeSuite) TestPurgeActiveRestartServices(c *C) { inter := &MockProgressMeter{} ddirs, part := s.mkpkg(c, "v1", `apps: svc: command: foo daemon: forking `) c.Assert(part.activate(true, inter), IsNil) for _, ddir := range ddirs { canary := filepath.Join(ddir, "canary") c.Assert(os.Mkdir(canary, 0755), IsNil) } called := [][]string{} systemd.SystemctlCmd = func(cmd ...string) ([]byte, error) { called = append(called, cmd) return []byte("ActiveState=inactive\n"), nil } err := Purge("hello-app", DoPurgeActive, inter) c.Check(err, IsNil) for _, ddir := range ddirs { c.Check(helpers.FileExists(filepath.Join(ddir, "canary")), Equals, false) } c.Assert(inter.notified, HasLen, 1) c.Check(inter.notified[0], Matches, `Waiting for .* to stop.`) rv := make(map[string]int) for i, c := range called { rv[c[0]] = i + 1 } c.Check(rv["stop"] > 0 && rv["start"] > rv["stop"], Equals, true) }
func (s *SquashfsTestSuite) TestInstallFailUnmountsSnap(c *C) { snapPkg := makeTestSnapPackage(c, `name: hello version: 1.10 apps: some-binary: command: some-binary uses: [some-binary] uses: some-binary: type: migration-skill security-template: not-there `) // install but our missing security-template will break the install _, err := (&Overlord{}).Install(snapPkg, "origin", 0, &MockProgressMeter{}) c.Assert(err, ErrorMatches, "could not find specified template: not-there.*") // ensure the mount unit is not there mup := systemd.MountUnitPath("/snaps/hello.origin/1.10", "mount") c.Assert(helpers.FileExists(mup), Equals, false) // ensure that the mount gets unmounted and stopped c.Assert(s.systemdCmds, DeepEquals, [][]string{ {"start", "snaps-hello.origin-1.10.mount"}, {"--root", dirs.GlobalRootDir, "disable", "snaps-hello.origin-1.10.mount"}, {"stop", "snaps-hello.origin-1.10.mount"}, {"show", "--property=ActiveState", "snaps-hello.origin-1.10.mount"}, }) }
func (s *SquashfsTestSuite) TestRemoveSquashfsMountUnit(c *C) { m := &snapYaml{} inter := &MockProgressMeter{} err := addSquashfsMount(m, filepath.Join(dirs.SnapSnapsDir, "foo.origin/1.0"), true, inter) c.Assert(err, IsNil) // ensure we have the files p := filepath.Join(dirs.SnapServicesDir, "snaps-foo.origin-1.0.mount") c.Assert(helpers.FileExists(p), Equals, true) // now call remove and ensure they are gone err = removeSquashfsMount(m, filepath.Join(dirs.SnapSnapsDir, "foo.origin/1.0"), inter) c.Assert(err, IsNil) p = filepath.Join(dirs.SnapServicesDir, "snaps-foo.origin-1.0.mount") c.Assert(helpers.FileExists(p), Equals, false) }
// MigrateToDynamicGrub rearranges things to work with the old, // dynamic grub setup. Needed for when you rollback over the switch to // static grub. func MigrateToDynamicGrub() error { grubConfigRaw, err := ioutil.ReadFile(bootloaderGrubConfigFile()) if err != nil && !os.IsNotExist(err) { return err } grubConfig := string(grubConfigRaw) if !isOldGrubConfig(grubConfig) { // nothing to do return nil } part := New() // first copy current kernel/initrd to /boot/grub/$current (a or b) if err := copyKernelAssets("/", part.rootPartition().shortName); err != nil { return err } // then copy other kernel/initrd to /boot/grub/$other (a or b) if helpers.FileExists("/writable/cache/system/boot") { if err := copyKernelAssets("/writable/cache/system/", part.otherRootPartition().shortName); err != nil { return err } } return helpers.AtomicWriteFile(bootloaderGrubConfigFile(), []byte(newGrubConfig), 0644, 0) }
func (dbs *databaseSuite) TestGenerateKey(c *C) { fingerp, err := dbs.db.GenerateKey("account0") c.Assert(err, IsNil) c.Check(fingerp, NotNil) keyPath := filepath.Join(dbs.topDir, "private-keys-v0/account0", fingerp) c.Check(helpers.FileExists(keyPath), Equals, true) }
// IsSideLoaded determines if the system was installed using a // custom enablement part. func IsSideLoaded(bootloaderDir string) bool { file := filepath.Join(bootloaderDir, InstallYamlFile) if !helpers.FileExists(file) { // the system may have been sideloaded, but we have no // way of knowing :-( return false } InstallYaml, err := parseInstallYaml(file) if err != nil { logger.Noticef("Kernel sideload cannot be read, assuming sideload: %s", err) // file isn't parseable, so let's assume system is sideloaded return true } if InstallYaml.InstallOptions.DevicePart != "" { // system was created with something like: // // "ubuntu-device-flash [...] --device-part=unofficial-assets.tar.xz ..." // return true } return false }
// regeneratePolicyForSnap is used to regenerate all security policy for a // given snap func regeneratePolicyForSnap(snapname string) error { globExpr := filepath.Join(dirs.SnapAppArmorDir, fmt.Sprintf("%s_*", snapname)) matches, err := filepath.Glob(globExpr) if err != nil { return err } if len(matches) == 0 { // Nothing to regenerate is not an error return nil } appliedVersion := "" for _, profile := range matches { appID, err := newAppID(filepath.Base(profile)) if err != nil { return err } if appID.Version != appliedVersion { // FIXME: dirs.SnapAppsDir is too simple, gadget fn := filepath.Join(dirs.SnapAppsDir, appID.Pkgname, appID.Version, "meta", "package.yaml") if !helpers.FileExists(fn) { continue } err := GeneratePolicyFromFile(fn, true) if err != nil { return err } appliedVersion = appID.Version } } return nil }
// InDeveloperMode returns true if the image was build with --developer-mode func InDeveloperMode() bool { // FIXME: this is a bit terrible, we really need a single // bootloader dir like /boot or /boot/loader // instead of having to query the partition code bootloader, err := findBootloader() if err != nil { // can only happy on systems like ubuntu classic // that are not full snappy systems return false } file := filepath.Join(bootloader.Dir(), InstallYamlFile) if !helpers.FileExists(file) { // no idea return false } InstallYaml, err := parseInstallYaml(file) if err != nil { // no idea return false } return InstallYaml.InstallOptions.DeveloperMode }