// SetJournalPermissions sets ACLs and permissions so the rkt group can access // the pod's logs func SetJournalPermissions(p *stage1commontypes.Pod) error { s1 := common.Stage1ImagePath(p.Root) rktgid, err := common.LookupGid(common.RktGroup) if err != nil { return fmt.Errorf("group %q not found", common.RktGroup) } journalPath := filepath.Join(s1, "rootfs", "var", "log", "journal") if err := os.MkdirAll(journalPath, os.FileMode(0755)); err != nil { return fmt.Errorf("error creating journal dir: %v", err) } a, err := acl.Parse(fmt.Sprintf("g:%d:r-x,m:r-x", rktgid)) if err != nil { panic(fmt.Sprintf("error parsing ACL string: %v", err)) } defer a.Free() if err := a.SetFileDefault(journalPath); err != nil { return err } return nil }
// prepareStage1Image renders and verifies tree cache of the given hash // when using overlay. // When useOverlay is false, it attempts to render and expand the stage1. func prepareStage1Image(cfg PrepareConfig, img types.Hash, cdir string, useOverlay bool) error { s1 := common.Stage1ImagePath(cdir) if err := os.MkdirAll(s1, 0755); err != nil { return fmt.Errorf("error creating stage1 directory: %v", err) } if err := cfg.Store.RenderTreeStore(img.String(), false); err != nil { return fmt.Errorf("error rendering tree image: %v", err) } if err := cfg.Store.CheckTreeStore(img.String()); err != nil { log.Printf("Warning: tree cache is in a bad state. Rebuilding...") if err := cfg.Store.RenderTreeStore(img.String(), true); err != nil { return fmt.Errorf("error rendering tree image: %v", err) } } if !useOverlay { if err := writeManifest(cfg.CommonConfig, img, s1); err != nil { return fmt.Errorf("error writing manifest: %v", err) } destRootfs := filepath.Join(s1, "rootfs") cachedTreePath := cfg.Store.GetTreeStoreRootFS(img.String()) if err := fileutil.CopyTree(cachedTreePath, destRootfs); err != nil { return fmt.Errorf("error rendering ACI: %v", err) } } return nil }
// deletePod cleans up files and resource associated with the pod // pod must be under exclusive lock and be in either ExitedGarbage // or Garbage state func deletePod(p *pod) { if !p.isExitedGarbage && !p.isGarbage { panic(fmt.Sprintf("logic error: deletePod called with non-garbage pod %q (status %q)", p.uuid, p.getState())) } if p.isExitedGarbage { s, err := store.NewStore(getDataDir()) if err != nil { stderr("Cannot open store: %v", err) return } defer s.Close() stage1TreeStoreID, err := p.getStage1TreeStoreID() if err != nil { stderr("Error getting stage1 treeStoreID: %v", err) return } stage1RootFS := s.GetTreeStoreRootFS(stage1TreeStoreID) // execute stage1's GC if err := stage0.GC(p.path(), p.uuid, stage1RootFS, globalFlags.Debug); err != nil { stderr("Stage1 GC of pod %q failed: %v", p.uuid, err) return } if p.usesOverlay() { apps, err := p.getApps() if err != nil { stderr("Error retrieving app hashes from pod manifest: %v", err) return } for _, a := range apps { dest := filepath.Join(common.AppPath(p.path(), a.Name), "rootfs") if err := syscall.Unmount(dest, 0); err != nil { // machine could have been rebooted and mounts lost. // ignore "does not exist" and "not a mount point" errors if err != syscall.ENOENT && err != syscall.EINVAL { stderr("Error unmounting app at %v: %v", dest, err) } } } s1 := filepath.Join(common.Stage1ImagePath(p.path()), "rootfs") if err := syscall.Unmount(s1, 0); err != nil { // machine could have been rebooted and mounts lost. // ignore "does not exist" and "not a mount point" errors if err != syscall.ENOENT && err != syscall.EINVAL { stderr("Error unmounting stage1 at %v: %v", s1, err) return } } } } if err := os.RemoveAll(p.path()); err != nil { stderr("Unable to remove pod %q: %v", p.uuid, err) } }
// setupStage1Image mounts the overlay filesystem for stage1. // When useOverlay is false it is a noop func setupStage1Image(cfg RunConfig, img types.Hash, cdir string, useOverlay bool) error { if useOverlay { s1 := common.Stage1ImagePath(cdir) if err := overlayRender(cfg, img, cdir, s1); err != nil { return fmt.Errorf("error rendering overlay filesystem: %v", err) } } return nil }
// setupStage1Image mounts the overlay filesystem for stage1. // When useOverlay is false it is a noop func setupStage1Image(cfg RunConfig, img types.Hash, cdir string, useOverlay bool) error { if useOverlay { s1 := common.Stage1ImagePath(cdir) if err := overlayRender(cfg, img, cdir, s1); err != nil { return fmt.Errorf("error rendering overlay filesystem: %v", err) } // we will later read the status from the upper layer of the overlay fs // force the status directory to be there by touching it statusPath := filepath.Join(s1, "rootfs", "rkt", "status") if err := os.Chtimes(statusPath, time.Now(), time.Now()); err != nil { return fmt.Errorf("error touching status dir: %v", err) } } return nil }
// setupStage1Image mounts the overlay filesystem for stage1. // When useOverlay is false it is a noop func setupStage1Image(cfg RunConfig, cdir string, useOverlay bool) error { s1 := common.Stage1ImagePath(cdir) if useOverlay { treeStoreID, err := ioutil.ReadFile(filepath.Join(cdir, common.Stage1TreeStoreIDFilename)) if err != nil { return err } // pass an empty appName: make sure it remains consistent with // overlayStatusDirTemplate if err := overlayRender(cfg, string(treeStoreID), cdir, s1, ""); err != nil { return fmt.Errorf("error rendering overlay filesystem: %v", err) } // we will later read the status from the upper layer of the overlay fs // force the status directory to be there by touching it statusPath := filepath.Join(s1, "rootfs", "rkt", "status") if err := os.Chtimes(statusPath, time.Now(), time.Now()); err != nil { return fmt.Errorf("error touching status dir: %v", err) } } // Chown the 'rootfs' directory, so that rkt list/rkt status can access it. if err := os.Chown(filepath.Join(s1, "rootfs"), -1, cfg.RktGid); err != nil { return err } // Chown the 'rootfs/rkt' and its sub-directory, so that rkt list/rkt status can // access it. // Also set 'S_ISGID' bit on the mode so that when the app writes exit status to // 'rootfs/rkt/status/$app', the file has the group ID set to 'rkt'. chownWalker := func(path string, info os.FileInfo, err error) error { if err != nil { return err } if err := os.Chown(path, -1, cfg.RktGid); err != nil { return err } if err := os.Chmod(path, info.Mode()|os.ModeSetgid); err != nil { return err } return nil } return filepath.Walk(filepath.Join(s1, "rootfs", "rkt"), chownWalker) }
// prepareStage1Image renders and verifies tree cache of the given hash // when using overlay. // When useOverlay is false, it attempts to render and expand the stage1. func prepareStage1Image(cfg PrepareConfig, img types.Hash, cdir string, useOverlay bool) error { s1 := common.Stage1ImagePath(cdir) if err := os.MkdirAll(s1, defaultRegularDirPerm); err != nil { return fmt.Errorf("error creating stage1 directory: %v", err) } treeStoreID, _, err := cfg.Store.RenderTreeStore(img.String(), false) if err != nil { return fmt.Errorf("error rendering tree image: %v", err) } if !cfg.SkipTreeStoreCheck { hash, err := cfg.Store.CheckTreeStore(treeStoreID) if err != nil { log.Printf("Warning: tree cache is in a bad state: %v. Rebuilding...", err) var err error treeStoreID, hash, err = cfg.Store.RenderTreeStore(img.String(), true) if err != nil { return fmt.Errorf("error rendering tree image: %v", err) } } cfg.CommonConfig.RootHash = hash } if err := writeManifest(*cfg.CommonConfig, img, s1); err != nil { return fmt.Errorf("error writing manifest: %v", err) } if !useOverlay { destRootfs := filepath.Join(s1, "rootfs") cachedTreePath := cfg.Store.GetTreeStoreRootFS(treeStoreID) if err := fileutil.CopyTree(cachedTreePath, destRootfs, cfg.PrivateUsers); err != nil { return fmt.Errorf("error rendering ACI: %v", err) } } fn := path.Join(cdir, common.Stage1TreeStoreIDFilename) if err := ioutil.WriteFile(fn, []byte(treeStoreID), defaultRegularFilePerm); err != nil { return fmt.Errorf("error writing stage1 treeStoreID: %v", err) } return nil }
// prepareStage1Image renders and verifies tree cache of the given hash // when using overlay. // When useOverlay is false, it attempts to render and expand the stage1. func prepareStage1Image(cfg PrepareConfig, cdir string) error { s1 := common.Stage1ImagePath(cdir) if err := os.MkdirAll(s1, common.DefaultRegularDirPerm); err != nil { return errwrap.Wrap(errors.New("error creating stage1 directory"), err) } treeStoreID, _, err := cfg.TreeStore.Render(cfg.Stage1Image.String(), false) if err != nil { return errwrap.Wrap(errors.New("error rendering tree image"), err) } if !cfg.SkipTreeStoreCheck { hash, err := cfg.TreeStore.Check(treeStoreID) if err != nil { log.Printf("warning: tree cache is in a bad state: %v. Rebuilding...", err) var err error treeStoreID, hash, err = cfg.TreeStore.Render(cfg.Stage1Image.String(), true) if err != nil { return errwrap.Wrap(errors.New("error rendering tree image"), err) } } cfg.CommonConfig.RootHash = hash } if err := writeManifest(*cfg.CommonConfig, cfg.Stage1Image, s1); err != nil { return errwrap.Wrap(errors.New("error writing manifest"), err) } if !cfg.UseOverlay { destRootfs := filepath.Join(s1, "rootfs") cachedTreePath := cfg.TreeStore.GetRootFS(treeStoreID) if err := fileutil.CopyTree(cachedTreePath, destRootfs, cfg.PrivateUsers); err != nil { return errwrap.Wrap(errors.New("error rendering ACI"), err) } } fn := path.Join(cdir, common.Stage1TreeStoreIDFilename) if err := ioutil.WriteFile(fn, []byte(treeStoreID), common.DefaultRegularFilePerm); err != nil { return errwrap.Wrap(errors.New("error writing stage1 treeStoreID"), err) } return nil }
// setupStage1Image mounts the overlay filesystem for stage1. // When useOverlay is false it is a noop func setupStage1Image(cfg RunConfig, cdir string, useOverlay bool) error { if useOverlay { treeStoreID, err := ioutil.ReadFile(filepath.Join(cdir, common.Stage1TreeStoreIDFilename)) if err != nil { return err } s1 := common.Stage1ImagePath(cdir) // pass an empty appName: make sure it remains consistent with // overlayStatusDirTemplate if err := overlayRender(cfg, string(treeStoreID), cdir, s1, ""); err != nil { return fmt.Errorf("error rendering overlay filesystem: %v", err) } // we will later read the status from the upper layer of the overlay fs // force the status directory to be there by touching it statusPath := filepath.Join(s1, "rootfs", "rkt", "status") if err := os.Chtimes(statusPath, time.Now(), time.Now()); err != nil { return fmt.Errorf("error touching status dir: %v", err) } } return nil }
// prepareStage1Image renders and verifies tree cache of the given hash // when using overlay. // When useOverlay is false, it attempts to render and expand the stage1. func prepareStage1Image(cfg PrepareConfig, img types.Hash, cdir string, useOverlay bool) error { s1 := common.Stage1ImagePath(cdir) if err := os.MkdirAll(s1, 0755); err != nil { return fmt.Errorf("error creating stage1 directory: %v", err) } if err := cfg.Store.RenderTreeStore(img.String(), false); err != nil { return fmt.Errorf("error rendering tree image: %v", err) } if err := cfg.Store.CheckTreeStore(img.String()); err != nil { log.Printf("Warning: tree cache is in a bad state. Rebuilding...") if err := cfg.Store.RenderTreeStore(img.String(), true); err != nil { return fmt.Errorf("error rendering tree image: %v", err) } } if !useOverlay { if err := aci.RenderACIWithImageID(img, s1, cfg.Store); err != nil { return fmt.Errorf("error rendering ACI: %v", err) } } return nil }
// SetJournalPermissions sets ACLs and permissions so the rkt group can access // the pod's logs func SetJournalPermissions(p *stage1commontypes.Pod) error { s1 := common.Stage1ImagePath(p.Root) rktgid, err := common.LookupGid(common.RktGroup) if err != nil { return fmt.Errorf("group %q not found", common.RktGroup) } journalPath := filepath.Join(s1, "rootfs", "var", "log", "journal") if err := os.MkdirAll(journalPath, os.FileMode(0755)); err != nil { return errwrap.Wrap(errors.New("error creating journal dir"), err) } a, err := acl.InitACL() if err != nil { return err } defer a.Free() if err := a.ParseACL(fmt.Sprintf("g:%d:r-x,m:r-x", rktgid)); err != nil { return errwrap.Wrap(errors.New("error parsing ACL string"), err) } if err := a.AddBaseEntries(journalPath); err != nil { return errwrap.Wrap(errors.New("error adding base ACL entries"), err) } if err := a.Valid(); err != nil { return err } if err := a.SetFileACLDefault(journalPath); err != nil { return errwrap.Wrap(fmt.Errorf("error setting default ACLs on %q", journalPath), err) } return nil }
// emptyExitedGarbage discards sufficiently aged pods from exitedGarbageDir() func emptyExitedGarbage(gracePeriod time.Duration) error { if err := walkPods(includeExitedGarbageDir, func(p *pod) { gp := p.path() st := &syscall.Stat_t{} if err := syscall.Lstat(gp, st); err != nil { if err != syscall.ENOENT { stderr("Unable to stat %q, ignoring: %v", gp, err) } return } if expiration := time.Unix(st.Ctim.Unix()).Add(gracePeriod); time.Now().After(expiration) { if err := p.ExclusiveLock(); err != nil { return } stdout("Garbage collecting pod %q", p.uuid) s, err := store.NewStore(globalFlags.Dir) if err != nil { stderr("Cannot open store: %v", err) return } stage1ID, err := p.getStage1Hash() if err != nil { stderr("Error getting stage1 hash") return } stage1RootFS := s.GetTreeStoreRootFS(stage1ID.String()) if p.usesOverlay() { apps, err := p.getAppsHashes() if err != nil { stderr("Error retrieving app hashes from pod manifest: %v", err) return } for _, a := range apps { dest := filepath.Join(common.AppImagePath(p.path(), a), "rootfs") if err := syscall.Unmount(dest, 0); err != nil { // machine could have been rebooted and mounts lost. // ignore "does not exist" and "not a mount point" errors if err != syscall.ENOENT && err != syscall.EINVAL { stderr("Error unmounting app at %v: %v", dest, err) } } } s1 := filepath.Join(common.Stage1ImagePath(p.path()), "rootfs") if err := syscall.Unmount(s1, 0); err != nil { // machine could have been rebooted and mounts lost. // ignore "does not exist" and "not a mount point" errors if err != syscall.ENOENT && err != syscall.EINVAL { stderr("Error unmounting stage1 at %v: %v", s1, err) return } } } // execute stage1's GC if err := stage0.GC(p.path(), p.uuid, stage1RootFS, globalFlags.Debug); err != nil { stderr("Stage1 GC of pod %q failed: %v", p.uuid, err) return } if err := os.RemoveAll(gp); err != nil { stderr("Unable to remove pod %q: %v", p.uuid, err) } } }); err != nil { return err } return nil }