// prepareAppImage renders and verifies the tree cache of the app image that // corresponds to the given hash. // When useOverlay is false, it attempts to render and expand the app image // TODO(jonboulle): tighten up the Hash type here; currently it is partially-populated (i.e. half-length sha512) func prepareAppImage(cfg PrepareConfig, img types.Hash, cdir string, useOverlay bool) (*schema.ImageManifest, error) { log.Println("Loading image", img.String()) if useOverlay { if err := cfg.Store.RenderTreeStore(img.String(), false); err != nil { return nil, 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 nil, fmt.Errorf("error rendering tree image: %v", err) } } } else { ad := common.AppImagePath(cdir, img) err := os.MkdirAll(ad, 0755) if err != nil { return nil, fmt.Errorf("error creating image directory: %v", err) } if err := aci.RenderACIWithImageID(img, ad, cfg.Store); err != nil { return nil, fmt.Errorf("error rendering ACI: %v", err) } } am, err := cfg.Store.GetImageManifest(img.String()) if err != nil { return nil, fmt.Errorf("error getting the manifest: %v", err) } return am, nil }
// setupAppImage mounts the overlay filesystem for the app image that // corresponds to the given hash. Then, it creates the tmp directory. // When useOverlay is false it just creates the tmp directory for this app. func setupAppImage(cfg RunConfig, img types.Hash, cdir string, useOverlay bool) error { ad := common.AppImagePath(cdir, img) if useOverlay { err := os.MkdirAll(ad, 0776) if err != nil { return fmt.Errorf("error creating image directory: %v", err) } if err := overlayRender(cfg, img, cdir, ad); err != nil { return fmt.Errorf("error rendering overlay filesystem: %v", err) } } err := os.MkdirAll(filepath.Join(ad, "rootfs/tmp"), 0777) if err != nil { return fmt.Errorf("error creating tmp directory: %v", 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 }