// CreateDepListFromImageID returns the flat dependency tree of the image with // the provided imageID func CreateDepListFromImageID(imageID types.Hash, ap ACIRegistry) (Images, error) { key, err := ap.ResolveKey(imageID.String()) if err != nil { return nil, err } return createDepList(key, ap) }
// 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 }
// overlayRender renders the image that corresponds to the given hash using the // overlay filesystem. // It writes the manifest in the specified directory and mounts an overlay // filesystem from the cached tree of the image as rootfs. func overlayRender(cfg RunConfig, img types.Hash, cdir string, dest string) error { if err := writeManifest(cfg.CommonConfig, img, dest); err != nil { return err } destRootfs := path.Join(dest, "rootfs") if err := os.MkdirAll(destRootfs, 0755); err != nil { return err } cachedTreePath := cfg.Store.GetTreeStoreRootFS(img.String()) overlayDir := path.Join(cdir, "overlay", img.String()) if err := os.MkdirAll(overlayDir, 0755); err != nil { return err } upperDir := path.Join(overlayDir, "upper") if err := os.MkdirAll(upperDir, 0755); err != nil { return err } workDir := path.Join(overlayDir, "work") if err := os.MkdirAll(workDir, 0755); err != nil { return err } opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", cachedTreePath, upperDir, workDir) opts = label.FormatMountLabel(opts, cfg.MountLabel) if err := syscall.Mount("overlay", destRootfs, "overlay", 0, opts); err != nil { return fmt.Errorf("error mounting: %v", err) } return nil }
// writeManifest takes an img ID and writes the corresponding manifest in dest func writeManifest(cfg CommonConfig, img types.Hash, dest string) error { mb, err := cfg.Store.GetImageManifestJSON(img.String()) if err != nil { return err } debug("Writing image manifest") if err := ioutil.WriteFile(filepath.Join(dest, "manifest"), mb, defaultRegularFilePerm); err != nil { return fmt.Errorf("error writing image manifest: %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 := 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 }
// prepareAppImage renders and verifies the tree cache of the app image that // corresponds to the given app name. // When useOverlay is false, it attempts to render and expand the app image func prepareAppImage(cfg PrepareConfig, appName types.ACName, img types.Hash, cdir string, useOverlay bool) error { log.Println("Loading image", img.String()) if useOverlay { if cfg.PrivateUsers.Shift > 0 { return fmt.Errorf("cannot use both overlay and user namespace: not implemented yet. (Try --no-overlay)") } 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) } } } else { ad := common.AppPath(cdir, appName) err := os.MkdirAll(ad, 0755) if err != nil { return fmt.Errorf("error creating image directory: %v", err) } if err := aci.RenderACIWithImageID(img, ad, cfg.Store, cfg.PrivateUsers); err != nil { return fmt.Errorf("error rendering ACI: %v", err) } } return nil }
// prepareAppImage renders and verifies the tree cache of the app image that // corresponds to the given app name. // When useOverlay is false, it attempts to render and expand the app image func prepareAppImage(cfg PrepareConfig, appName types.ACName, img types.Hash, cdir string, useOverlay bool) error { log.Println("Loading image", img.String()) am, err := cfg.Store.GetImageManifest(img.String()) if err != nil { return fmt.Errorf("error getting the manifest: %v", err) } if _, hasOS := am.Labels.Get("os"); !hasOS { return fmt.Errorf("missing os label in the image manifest") } if _, hasArch := am.Labels.Get("arch"); !hasArch { return fmt.Errorf("missing arch label in the image manifest") } if err := types.IsValidOSArch(am.Labels.ToMap(), ValidOSArch); err != nil { return err } appInfoDir := common.AppInfoPath(cdir, appName) if err := os.MkdirAll(appInfoDir, 0755); err != nil { return fmt.Errorf("error creating apps info directory: %v", err) } if useOverlay { if cfg.PrivateUsers.Shift > 0 { return fmt.Errorf("cannot use both overlay and user namespace: not implemented yet. (Try --no-overlay)") } treeStoreID, err := cfg.Store.RenderTreeStore(img.String(), false) if err != nil { return fmt.Errorf("error rendering tree image: %v", err) } if err := cfg.Store.CheckTreeStore(treeStoreID); err != nil { log.Printf("Warning: tree cache is in a bad state: %v. Rebuilding...", err) var err error if treeStoreID, err = cfg.Store.RenderTreeStore(img.String(), true); err != nil { return fmt.Errorf("error rendering tree image: %v", err) } } if err := ioutil.WriteFile(common.AppTreeStoreIDPath(cdir, appName), []byte(treeStoreID), 0700); err != nil { return fmt.Errorf("error writing app treeStoreID: %v", err) } } else { ad := common.AppPath(cdir, appName) err := os.MkdirAll(ad, 0755) if err != nil { return fmt.Errorf("error creating image directory: %v", err) } if err := aci.RenderACIWithImageID(img, ad, cfg.Store, cfg.PrivateUsers); err != nil { return fmt.Errorf("error rendering ACI: %v", err) } } if err := writeManifest(cfg.CommonConfig, img, appInfoDir); err != nil { return err } return nil }
// writeManifest takes an img ID and writes the corresponding manifest in dest func writeManifest(cfg CommonConfig, img types.Hash, dest string) error { manifest, err := cfg.Store.GetImageManifest(img.String()) if err != nil { return err } mb, err := json.Marshal(manifest) if err != nil { return fmt.Errorf("error marshalling image manifest: %v", err) } log.Printf("Writing image manifest") if err := ioutil.WriteFile(filepath.Join(dest, "manifest"), mb, 0700); err != nil { return fmt.Errorf("error writing image manifest: %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, 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 }
// Enter enters the pod/app by exec()ing the stage1's /enter similar to /init // /enter can expect to have its CWD set to the app root. // imageID and command are supplied to /enter on argv followed by any arguments. // stage1Path is the path of the stage1 rootfs func Enter(cdir string, podPID int, imageID *types.Hash, stage1Path string, cmdline []string) error { if err := os.Chdir(cdir); err != nil { return fmt.Errorf("error changing to dir: %v", err) } id := types.ShortHash(imageID.String()) ep, err := getStage1Entrypoint(cdir, enterEntrypoint) if err != nil { return fmt.Errorf("error determining entrypoint: %v", err) } argv := []string{filepath.Join(stage1Path, ep)} argv = append(argv, strconv.Itoa(podPID)) argv = append(argv, id) argv = append(argv, cmdline...) if err := syscall.Exec(argv[0], argv, os.Environ()); err != nil { return fmt.Errorf("error execing enter: %v", err) } // never reached return nil }
// overlayRender renders the image that corresponds to the given hash using the // overlay filesystem. // It writes the manifest in the specified directory and mounts an overlay // filesystem from the cached tree of the image as rootfs. func overlayRender(cfg RunConfig, img types.Hash, cdir string, dest string) error { manifest, err := cfg.Store.GetImageManifest(img.String()) if err != nil { return err } mb, err := json.Marshal(manifest) if err != nil { return fmt.Errorf("error marshalling image manifest: %v", err) } log.Printf("Writing image manifest") if err := ioutil.WriteFile(filepath.Join(dest, "manifest"), mb, 0700); err != nil { return fmt.Errorf("error writing pod manifest: %v", err) } destRootfs := path.Join(dest, "rootfs") if err := os.MkdirAll(destRootfs, 0755); err != nil { return err } cachedTreePath := cfg.Store.GetTreeStoreRootFS(img.String()) overlayDir := path.Join(cdir, "overlay", img.String()) if err := os.MkdirAll(overlayDir, 0755); err != nil { return err } upperDir := path.Join(overlayDir, "upper") if err := os.MkdirAll(upperDir, 0755); err != nil { return err } workDir := path.Join(overlayDir, "work") if err := os.MkdirAll(workDir, 0755); err != nil { return err } opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", cachedTreePath, upperDir, workDir) if err := syscall.Mount("overlay", destRootfs, "overlay", 0, opts); err != nil { return fmt.Errorf("error mounting: %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 }
// AppImagePath returns the path where an app image (i.e. unpacked ACI) is rooted (i.e. // where its contents are extracted during stage0), based on the app image ID. func AppImagePath(root string, imageID types.Hash) string { return filepath.Join(AppImagesPath(root), types.ShortHash(imageID.String())) }
// ServiceUnitName returns a systemd service unit name for the given imageID func ServiceUnitName(imageID types.Hash) string { return types.ShortHash(imageID.String()) + ".service" }
// RelEnvFilePath returns the path to the environment file for the given imageID // relative to the pod's root func RelEnvFilePath(imageID types.Hash) string { return filepath.Join(envDir, types.ShortHash(imageID.String())) }
// SocketUnitName returns a systemd socket unit name for the given imageID func SocketUnitName(imageID types.Hash) string { return imageID.String() + ".socket" }
// RelAppImagePath returns the path of an application image relative to the // stage1 chroot func RelAppImagePath(imageID types.Hash) string { return filepath.Join(stage2Dir, types.ShortHash(imageID.String())) }
// prepareAppImage renders and verifies the tree cache of the app image that // corresponds to the given app name. // When useOverlay is false, it attempts to render and expand the app image func prepareAppImage(cfg PrepareConfig, appName types.ACName, img types.Hash, cdir string, useOverlay bool) error { debug("Loading image %s", img.String()) am, err := cfg.Store.GetImageManifest(img.String()) if err != nil { return fmt.Errorf("error getting the manifest: %v", err) } if _, hasOS := am.Labels.Get("os"); !hasOS { return fmt.Errorf("missing os label in the image manifest") } if _, hasArch := am.Labels.Get("arch"); !hasArch { return fmt.Errorf("missing arch label in the image manifest") } if err := types.IsValidOSArch(am.Labels.ToMap(), ValidOSArch); err != nil { return err } appInfoDir := common.AppInfoPath(cdir, appName) if err := os.MkdirAll(appInfoDir, defaultRegularDirPerm); err != nil { return fmt.Errorf("error creating apps info directory: %v", err) } if useOverlay { if cfg.PrivateUsers.Shift > 0 { return fmt.Errorf("cannot use both overlay and user namespace: not implemented yet. (Try --no-overlay)") } 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 := ioutil.WriteFile(common.AppTreeStoreIDPath(cdir, appName), []byte(treeStoreID), defaultRegularFilePerm); err != nil { return fmt.Errorf("error writing app treeStoreID: %v", err) } } else { ad := common.AppPath(cdir, appName) err := os.MkdirAll(ad, defaultRegularDirPerm) if err != nil { return fmt.Errorf("error creating image directory: %v", err) } shiftedUid, shiftedGid, err := cfg.PrivateUsers.ShiftRange(uint32(os.Getuid()), uint32(os.Getgid())) if err != nil { return fmt.Errorf("error getting uid, gid: %v", err) } if err := os.Chown(ad, int(shiftedUid), int(shiftedGid)); err != nil { return fmt.Errorf("error shifting app %q's stage2 dir: %v", appName, err) } if err := aci.RenderACIWithImageID(img, ad, cfg.Store, cfg.PrivateUsers); err != nil { return fmt.Errorf("error rendering ACI: %v", err) } } if err := writeManifest(*cfg.CommonConfig, img, appInfoDir); err != nil { return err } return nil }