Exemplo n.º 1
0
Arquivo: run.go Projeto: krieg/rkt
// 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 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); err != nil {
			return fmt.Errorf("error rendering ACI: %v", err)
		}
	}
	return nil
}
Exemplo n.º 2
0
Arquivo: run.go Projeto: NeilW/rkt
// 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
}
Exemplo n.º 3
0
// Write renders the ACI with the provided key in the treestore
// Write, to avoid having a rendered ACI with old stale files, requires that
// the destination directory doesn't exist (usually Remove should be called
// before Write)
func (ts *TreeStore) Write(key string, s *Store) error {
	treepath := filepath.Join(ts.path, key)
	fi, _ := os.Stat(treepath)
	if fi != nil {
		return fmt.Errorf("treestore: path %s already exists", treepath)
	}
	imageID, err := types.NewHash(key)
	if err != nil {
		return fmt.Errorf("treestore: cannot convert key to imageID: %v", err)
	}
	if err := os.MkdirAll(treepath, 0755); err != nil {
		return fmt.Errorf("treestore: cannot create treestore directory %s: %v", treepath, err)
	}
	err = aci.RenderACIWithImageID(*imageID, treepath, s)
	if err != nil {
		return fmt.Errorf("treestore: cannot render aci: %v", err)
	}
	hash, err := ts.Hash(key)
	if err != nil {
		return fmt.Errorf("treestore: cannot calculate tree hash: %v", err)
	}
	err = ioutil.WriteFile(filepath.Join(treepath, hashfilename), []byte(hash), 0644)
	if err != nil {
		return fmt.Errorf("treestore: cannot write hash file: %v", err)
	}
	// before creating the "rendered" flag file we need to ensure that all data is fsynced
	dfd, err := syscall.Open(treepath, syscall.O_RDONLY, 0)
	if err != nil {
		return err
	}
	defer syscall.Close(dfd)
	if err := sys.Syncfs(dfd); err != nil {
		return fmt.Errorf("treestore: failed to sync data: %v", err)
	}
	// Create rendered file
	f, err := os.Create(filepath.Join(treepath, renderedfilename))
	if err != nil {
		return fmt.Errorf("treestore: failed to write rendered file: %v", err)
	}
	f.Close()

	if err := syscall.Fsync(dfd); err != nil {
		return fmt.Errorf("treestore: failed to sync tree store directory: %v", err)
	}
	return nil
}
Exemplo n.º 4
0
// 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
}
Exemplo n.º 5
0
Arquivo: run.go Projeto: matomesc/rkt
// 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
}
Exemplo n.º 6
0
// Write renders the ACI with the provided key in the treestore. id references
// that specific tree store rendered image.
// Write, to avoid having a rendered ACI with old stale files, requires that
// the destination directory doesn't exist (usually Remove should be called
// before Write)
func (ts *TreeStore) Write(id string, key string, s *Store) (string, error) {
	treepath := ts.GetPath(id)
	fi, _ := os.Stat(treepath)
	if fi != nil {
		return "", fmt.Errorf("path %s already exists", treepath)
	}
	imageID, err := types.NewHash(key)
	if err != nil {
		return "", errwrap.Wrap(errors.New("cannot convert key to imageID"), err)
	}
	if err := os.MkdirAll(treepath, 0755); err != nil {
		return "", errwrap.Wrap(fmt.Errorf("cannot create treestore directory %s", treepath), err)
	}
	err = aci.RenderACIWithImageID(*imageID, treepath, s, uid.NewBlankUidRange())
	if err != nil {
		return "", errwrap.Wrap(errors.New("cannot render aci"), err)
	}
	hash, err := ts.Hash(id)
	if err != nil {
		return "", errwrap.Wrap(errors.New("cannot calculate tree hash"), err)
	}
	err = ioutil.WriteFile(filepath.Join(treepath, hashfilename), []byte(hash), 0644)
	if err != nil {
		return "", errwrap.Wrap(errors.New("cannot write hash file"), err)
	}
	// before creating the "rendered" flag file we need to ensure that all data is fsynced
	dfd, err := syscall.Open(treepath, syscall.O_RDONLY, 0)
	if err != nil {
		return "", err
	}
	defer syscall.Close(dfd)
	if err := sys.Syncfs(dfd); err != nil {
		return "", errwrap.Wrap(errors.New("failed to sync data"), err)
	}
	// Create rendered file
	f, err := os.Create(filepath.Join(treepath, renderedfilename))
	if err != nil {
		return "", errwrap.Wrap(errors.New("failed to write rendered file"), err)
	}
	f.Close()

	// Write the hash of the image that will use this tree store
	err = ioutil.WriteFile(filepath.Join(treepath, imagefilename), []byte(key), 0644)
	if err != nil {
		return "", errwrap.Wrap(errors.New("cannot write image file"), err)
	}

	if err := syscall.Fsync(dfd); err != nil {
		return "", errwrap.Wrap(errors.New("failed to sync tree store directory"), err)
	}

	treeSize, err := ts.Size(id)
	if err != nil {
		return "", err
	}

	if err := s.UpdateTreeStoreSize(key, treeSize); err != nil {
		return "", err
	}

	return string(hash), nil
}
Exemplo n.º 7
0
Arquivo: app.go Projeto: nhlfr/rkt
// 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
}
Exemplo n.º 8
0
// render renders the ACI with the provided key in the treestore. id references
// that specific tree store rendered image.
// render, to avoid having a rendered ACI with old stale files, requires that
// the destination directory doesn't exist (usually remove should be called
// before render)
func (ts *Store) render(id string, key string) (string, error) {
	treepath := ts.GetPath(id)
	fi, _ := os.Stat(treepath)
	if fi != nil {
		return "", fmt.Errorf("path %s already exists", treepath)
	}
	imageID, err := types.NewHash(key)
	if err != nil {
		return "", errwrap.Wrap(errors.New("cannot convert key to imageID"), err)
	}
	if err := os.MkdirAll(treepath, 0755); err != nil {
		return "", errwrap.Wrap(fmt.Errorf("cannot create treestore directory %s", treepath), err)
	}
	err = aci.RenderACIWithImageID(*imageID, treepath, ts.store, user.NewBlankUidRange())
	if err != nil {
		return "", errwrap.Wrap(errors.New("cannot render aci"), err)
	}
	hash, err := ts.Hash(id)
	if err != nil {
		return "", errwrap.Wrap(errors.New("cannot calculate tree hash"), err)
	}
	err = ioutil.WriteFile(filepath.Join(treepath, hashfilename), []byte(hash), 0644)
	if err != nil {
		return "", errwrap.Wrap(errors.New("cannot write hash file"), err)
	}
	// before creating the "rendered" flag file we need to ensure that all data is fsynced
	dfd, err := syscall.Open(treepath, syscall.O_RDONLY, 0)
	if err != nil {
		return "", err
	}
	defer syscall.Close(dfd)
	if err := sys.Syncfs(dfd); err != nil {
		return "", errwrap.Wrap(errors.New("failed to sync data"), err)
	}
	// Create rendered file
	f, err := os.Create(filepath.Join(treepath, renderedfilename))
	if err != nil {
		return "", errwrap.Wrap(errors.New("failed to write rendered file"), err)
	}
	f.Close()

	// Write the hash of the image that will use this tree store
	err = ioutil.WriteFile(filepath.Join(treepath, imagefilename), []byte(key), 0644)
	if err != nil {
		return "", errwrap.Wrap(errors.New("cannot write image file"), err)
	}

	if err := syscall.Fsync(dfd); err != nil {
		return "", errwrap.Wrap(errors.New("failed to sync tree store directory"), err)
	}

	// TODO(sgotti) this is wrong for various reasons:
	// * Doesn't consider that can there can be multiple treestore per ACI
	// (and fixing this adding/subtracting sizes is bad since cannot be
	// atomic and could bring to duplicated/missing subtractions causing
	// wrong sizes)
	// * ImageStore and TreeStore are decoupled (TreeStore should just use acirenderer.ACIRegistry interface)
	treeSize, err := ts.Size(id)
	if err != nil {
		return "", err
	}

	if err := ts.store.UpdateTreeStoreSize(key, treeSize); err != nil {
		return "", err
	}

	return string(hash), nil
}