// 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) }
func (h *Host) getLocalImage(hash types.Hash, name types.ACIdentifier, labels types.Labels) (*Image, error) { if hash.Empty() && name.Empty() { return nil, errors.Trace(ErrUsage) } if !hash.Empty() { if idStr, err := os.Readlink(h.Path("images", hash.String())); os.IsNotExist(err) { return nil, ErrNotFound } else if err != nil { return nil, errors.Trace(err) } else if id := uuid.Parse(idStr); id == nil { return nil, errors.Errorf("Invalid UUID: %v", idStr) } else if img, err := LoadImage(h, id); err != nil { return nil, errors.Trace(err) } else { return img, nil } } else if imgs, err := h.Images(); err != nil { return nil, errors.Trace(err) } else { for _, img := range imgs { if img.Manifest.Name != name { continue } if !acutil.MatchLabels(labels, img.Manifest.Labels) { continue } // TODO: multiple matches? return img, nil } return nil, ErrNotFound } }
// 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 errwrap.Wrap(errors.New("error writing image manifest"), 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 errwrap.Wrap(errors.New("error creating stage1 directory"), err) } treeStoreID, _, err := cfg.Store.RenderTreeStore(img.String(), false) if err != nil { return errwrap.Wrap(errors.New("error rendering tree image"), 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 errwrap.Wrap(errors.New("error rendering tree image"), err) } } cfg.CommonConfig.RootHash = hash } if err := writeManifest(*cfg.CommonConfig, img, s1); err != nil { return errwrap.Wrap(errors.New("error writing manifest"), err) } if !useOverlay { destRootfs := filepath.Join(s1, "rootfs") cachedTreePath := cfg.Store.GetTreeStoreRootFS(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), defaultRegularFilePerm); err != nil { return errwrap.Wrap(errors.New("error writing stage1 treeStoreID"), 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 { debug("Loading image %s", img.String()) am, err := cfg.Store.GetImageManifest(img.String()) if err != nil { return errwrap.Wrap(errors.New("error getting the manifest"), 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 errwrap.Wrap(errors.New("error creating apps info directory"), 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 errwrap.Wrap(errors.New("error rendering tree image"), err) } if !cfg.SkipTreeStoreCheck { hash, err := cfg.Store.CheckTreeStore(treeStoreID) if err != nil { log.PrintE("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 errwrap.Wrap(errors.New("error rendering tree image"), err) } } cfg.CommonConfig.RootHash = hash } if err := ioutil.WriteFile(common.AppTreeStoreIDPath(cdir, appName), []byte(treeStoreID), defaultRegularFilePerm); err != nil { return errwrap.Wrap(errors.New("error writing app treeStoreID"), err) } } else { ad := common.AppPath(cdir, appName) err := os.MkdirAll(ad, defaultRegularDirPerm) if err != nil { return errwrap.Wrap(errors.New("error creating image directory"), err) } shiftedUid, shiftedGid, err := cfg.PrivateUsers.ShiftRange(uint32(os.Getuid()), uint32(os.Getgid())) if err != nil { return errwrap.Wrap(errors.New("error getting uid, gid"), err) } if err := os.Chown(ad, int(shiftedUid), int(shiftedGid)); err != nil { return errwrap.Wrap(fmt.Errorf("error shifting app %q's stage2 dir", appName), err) } if err := aci.RenderACIWithImageID(img, ad, cfg.Store, cfg.PrivateUsers); err != nil { return errwrap.Wrap(errors.New("error rendering ACI"), err) } } if err := writeManifest(*cfg.CommonConfig, img, appInfoDir); err != nil { return err } return nil }
// TODO(iaguis): add override options for Exec, Environment (à la patch-manifest) func AddApp(cfg RunConfig, dir string, img *types.Hash) error { im, err := cfg.Store.GetImageManifest(img.String()) if err != nil { return err } appName, err := imageNameToAppName(im.Name) if err != nil { return err } p, err := stage1types.LoadPod(dir, cfg.UUID) if err != nil { return errwrap.Wrap(errors.New("error loading pod manifest"), err) } pm := p.Manifest var mutable bool ms, ok := pm.Annotations.Get("coreos.com/rkt/stage1/mutable") if ok { mutable, err = strconv.ParseBool(ms) if err != nil { return errwrap.Wrap(errors.New("error parsing mutable annotation"), err) } } if !mutable { return errors.New("immutable pod: cannot add application") } if pm.Apps.Get(*appName) != nil { return fmt.Errorf("error: multiple apps with name %s", *appName) } if im.App == nil { return fmt.Errorf("error: image %s has no app section)", img) } appInfoDir := common.AppInfoPath(dir, *appName) if err := os.MkdirAll(appInfoDir, common.DefaultRegularDirPerm); err != nil { return errwrap.Wrap(errors.New("error creating apps info directory"), err) } uidRange := user.NewBlankUidRange() // TODO(iaguis): DRY: refactor this var treeStoreID string if cfg.UseOverlay { treeStoreID, _, err := cfg.TreeStore.Render(img.String(), false) if err != nil { return errwrap.Wrap(errors.New("error rendering tree image"), err) } hash, err := cfg.TreeStore.Check(treeStoreID) if err != nil { log.PrintE("warning: tree cache is in a bad state. Rebuilding...", err) var err error treeStoreID, hash, err = cfg.TreeStore.Render(img.String(), true) if err != nil { return errwrap.Wrap(errors.New("error rendering tree image"), err) } } cfg.RootHash = hash if err := ioutil.WriteFile(common.AppTreeStoreIDPath(dir, *appName), []byte(treeStoreID), common.DefaultRegularFilePerm); err != nil { return errwrap.Wrap(errors.New("error writing app treeStoreID"), err) } } else { ad := common.AppPath(dir, *appName) err := os.MkdirAll(ad, common.DefaultRegularDirPerm) if err != nil { return errwrap.Wrap(errors.New("error creating image directory"), err) } privateUsers, err := preparedWithPrivateUsers(dir) if err != nil { log.FatalE("error reading user namespace information", err) } if err := uidRange.Deserialize([]byte(privateUsers)); err != nil { return err } shiftedUid, shiftedGid, err := uidRange.ShiftRange(uint32(os.Getuid()), uint32(os.Getgid())) if err != nil { return errwrap.Wrap(errors.New("error getting uid, gid"), err) } if err := os.Chown(ad, int(shiftedUid), int(shiftedGid)); err != nil { return errwrap.Wrap(fmt.Errorf("error shifting app %q's stage2 dir", *appName), err) } if err := aci.RenderACIWithImageID(*img, ad, cfg.Store, uidRange); err != nil { return errwrap.Wrap(errors.New("error rendering ACI"), err) } } if err := writeManifest(*cfg.CommonConfig, *img, appInfoDir); err != nil { return errwrap.Wrap(errors.New("error writing manifest"), err) } if err := setupAppImage(cfg, *appName, *img, dir, cfg.UseOverlay); err != nil { return fmt.Errorf("error setting up app image: %v", err) } if cfg.UseOverlay { imgDir := filepath.Join(dir, "overlay", treeStoreID) if err := os.Chown(imgDir, -1, cfg.RktGid); err != nil { return err } } ra := schema.RuntimeApp{ Name: *appName, App: im.App, Image: schema.RuntimeImage{ Name: &im.Name, ID: *img, Labels: im.Labels, }, // TODO(iaguis): default isolators } env := ra.App.Environment env.Set("AC_APP_NAME", appName.String()) envFilePath := filepath.Join(common.Stage1RootfsPath(dir), "rkt", "env", appName.String()) if err := common.WriteEnvFile(env, uidRange, envFilePath); err != nil { return err } apps := append(p.Manifest.Apps, ra) p.Manifest.Apps = apps if err := updatePodManifest(dir, p.Manifest); err != nil { return err } if _, err := os.Create(common.AppCreatedPath(p.Root, appName.String())); err != nil { return err } return nil }