Beispiel #1
0
// CopyToDir will copy all elements specified in the froms slice into the
// directory inside the current ACI specified by the to string.
func (a *ACBuild) CopyToDir(froms []string, to string) (err error) {
	if err = a.lock(); err != nil {
		return err
	}
	defer func() {
		if err1 := a.unlock(); err == nil {
			err = err1
		}
	}()

	target := path.Join(a.CurrentACIPath, aci.RootfsDir, to)

	targetInfo, err := os.Stat(target)
	switch {
	case os.IsNotExist(err):
		err := os.MkdirAll(target, 0755)
		if err != nil {
			return err
		}
	case err != nil:
		return err
	case !targetInfo.IsDir():
		return fmt.Errorf("target %q is not a directory", to)
	}

	for _, from := range froms {
		_, file := path.Split(from)
		tmptarget := path.Join(target, file)
		err := fileutil.CopyTree(from, tmptarget, user.NewBlankUidRange())
		if err != nil {
			return err
		}
	}
	return nil
}
Beispiel #2
0
Datei: run.go Projekt: krieg/rkt
// 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
}
Beispiel #3
0
func (e Engine) Run(command string, args []string, environment types.Environment, chroot, workingDir string) error {
	resolvConfFile := filepath.Join(chroot, "/etc/resolv.conf")
	_, err := os.Stat(resolvConfFile)
	switch {
	case os.IsNotExist(err):
		err := os.MkdirAll(filepath.Dir(resolvConfFile), 0755)
		if err != nil {
			return err
		}
		err = fileutil.CopyTree("/etc/resolv.conf", resolvConfFile, user.NewBlankUidRange())
		if err != nil {
			return err
		}
		defer os.RemoveAll(resolvConfFile)
	case err != nil:
		return err
	}
	var serializedArgs string
	for _, arg := range args {
		if serializedArgs != "" {
			serializedArgs += ","
		}
		serializedArgs += arg
	}
	var serializedEnv string
	for _, envvar := range environment {
		if serializedEnv != "" {
			serializedEnv += ","
		}
		serializedEnv += envvar.Name + "=" + envvar.Value
	}
	path := "PATH="
	for _, p := range engine.Pathlist {
		if path != "PATH=" {
			path += ":"
		}
		path += p
	}
	chrootArgs := []string{
		"--cmd", command,
		"--chroot", chroot,
		"--working-dir", workingDir,
	}
	if len(serializedArgs) > 0 {
		chrootArgs = append(chrootArgs, "--args", serializedArgs)
	}
	if len(serializedEnv) > 0 {
		chrootArgs = append(chrootArgs, "--env", serializedEnv)
	}
	cmd := exec.Command("acbuild-chroot", chrootArgs...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Env = []string{path}
	return cmd.Run()
}
Beispiel #4
0
func (a *ACBuild) beginFromLocalDirectory(start string) error {
	err := os.MkdirAll(a.CurrentACIPath, 0755)
	if err != nil {
		return err
	}

	err = fileutil.CopyTree(start, path.Join(a.CurrentACIPath, aci.RootfsDir), user.NewBlankUidRange())
	if err != nil {
		return err
	}

	return a.writeEmptyManifest()
}
Beispiel #5
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, 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
}
Beispiel #6
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, 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
}
Beispiel #7
0
// PrepareMountpoints creates and sets permissions for empty volumes.
// If the mountpoint comes from a Docker image and it is an implicit empty
// volume, we copy files from the image to the volume, see
// https://docs.docker.com/engine/userguide/containers/dockervolumes/#data-volumes
func PrepareMountpoints(volPath string, targetPath string, vol *types.Volume, dockerImplicit bool) error {
	if vol.Kind != "empty" {
		return nil
	}

	diag.Printf("creating an empty volume folder for sharing: %q", volPath)
	m, err := strconv.ParseUint(*vol.Mode, 8, 32)
	if err != nil {
		return errwrap.Wrap(fmt.Errorf("invalid mode %q for volume %q", *vol.Mode, vol.Name), err)
	}
	mode := os.FileMode(m)
	Uid := *vol.UID
	Gid := *vol.GID

	if dockerImplicit {
		fi, err := os.Stat(targetPath)
		if err == nil {
			// the directory exists in the image, let's set the same
			// permissions and copy files from there to the empty volume
			mode = fi.Mode()
			Uid = int(fi.Sys().(*syscall.Stat_t).Uid)
			Gid = int(fi.Sys().(*syscall.Stat_t).Gid)

			if err := fileutil.CopyTree(targetPath, volPath, user.NewBlankUidRange()); err != nil {
				return errwrap.Wrap(fmt.Errorf("error copying image files to empty volume %q", volPath), err)
			}
		}
	}

	if err := os.MkdirAll(volPath, 0770); err != nil {
		return errwrap.Wrap(fmt.Errorf("error creating %q", volPath), err)
	}
	if err := os.Chown(volPath, Uid, Gid); err != nil {
		return errwrap.Wrap(fmt.Errorf("could not change owner of %q", volPath), err)
	}
	if err := os.Chmod(volPath, mode); err != nil {
		return errwrap.Wrap(fmt.Errorf("could not change permissions of %q", volPath), err)
	}

	return nil
}
Beispiel #8
0
// CreateBackup backs a directory up in a given directory. It basically
// copies this directory into a given backups directory. The backups
// directory has a simple structure - a directory inside named "0" is
// the most recent backup. A directory name for oldest backup is
// deduced from a given limit. For instance, for limit being 5 the
// name for the oldest backup would be "4". If a backups number
// exceeds the given limit then only newest ones are kept and the rest
// is removed.
func CreateBackup(dir, backupsDir string, limit int) error {
	tmpBackupDir := filepath.Join(backupsDir, "tmp")
	if err := os.MkdirAll(backupsDir, 0750); err != nil {
		return err
	}
	if err := fileutil.CopyTree(dir, tmpBackupDir, user.NewBlankUidRange()); err != nil {
		return err
	}
	defer os.RemoveAll(tmpBackupDir)
	// prune backups
	if err := pruneOldBackups(backupsDir, limit-1); err != nil {
		return err
	}
	if err := shiftBackups(backupsDir, limit-2); err != nil {
		return err
	}
	if err := os.Rename(tmpBackupDir, filepath.Join(backupsDir, "0")); err != nil {
		return err
	}
	return nil
}
Beispiel #9
0
// createBackup backs a database up in a given directory. It basically
// copies this directory into a given backups directory. The backups
// directory has a simple structure - a directory inside named "0" is
// the most recent backup. A directory name for oldest backup is
// deduced from a given limit. For instance, for limit being 5 the
// name for the oldest backup would be "4". If a backups number
// exceeds the given limit then only newest ones are kept and the rest
// is removed.
func createBackup(dbDir, backupsDir string, limit int) error {
	tmpBackupDir := filepath.Join(backupsDir, "tmp")
	if err := os.MkdirAll(backupsDir, defaultPathPerm); err != nil {
		return err
	}
	if err := fileutil.CopyTree(dbDir, tmpBackupDir); err != nil {
		return err
	}
	defer os.RemoveAll(tmpBackupDir)
	// prune backups
	if err := pruneOldBackups(backupsDir, limit-1); err != nil {
		return err
	}
	if err := shiftBackups(backupsDir, limit-2); err != nil {
		return err
	}
	if err := os.Rename(tmpBackupDir, filepath.Join(backupsDir, "0")); err != nil {
		return err
	}
	return nil
}
Beispiel #10
0
// CopyToTarget will copy a single file/directory from the from string to the
// path specified by the to string inside the current ACI.
func (a *ACBuild) CopyToTarget(from string, to string) (err error) {
	if err = a.lock(); err != nil {
		return err
	}
	defer func() {
		if err1 := a.unlock(); err == nil {
			err = err1
		}
	}()

	target := path.Join(a.CurrentACIPath, aci.RootfsDir, to)

	dir, _ := path.Split(target)
	if dir != "" {
		err := os.MkdirAll(dir, 0755)
		if err != nil {
			return err
		}
	}

	return fileutil.CopyTree(from, target, user.NewBlankUidRange())
}
Beispiel #11
0
func runImageExtract(cmd *cobra.Command, args []string) (exit int) {
	if len(args) != 2 {
		cmd.Usage()
		return 254
	}
	outputDir := args[1]

	s, err := imagestore.NewStore(storeDir())
	if err != nil {
		stderr.PrintE("cannot open store", err)
		return 254
	}

	key, err := getStoreKeyFromAppOrHash(s, args[0])
	if err != nil {
		stderr.Error(err)
		return 254
	}

	aci, err := s.ReadStream(key)
	if err != nil {
		stderr.PrintE("error reading ACI from the store", err)
		return 254
	}

	// ExtractTar needs an absolute path
	absOutputDir, err := filepath.Abs(outputDir)
	if err != nil {
		stderr.PrintE("error converting output to an absolute path", err)
		return 254
	}

	if _, err := os.Stat(absOutputDir); err == nil {
		if !flagExtractOverwrite {
			stderr.Print("output directory exists (try --overwrite)")
			return 254
		}

		// don't allow the user to delete the root filesystem by mistake
		if absOutputDir == "/" {
			stderr.Print("this would delete your root filesystem. Refusing.")
			return 254
		}

		if err := os.RemoveAll(absOutputDir); err != nil {
			stderr.PrintE("error removing existing output dir", err)
			return 254
		}
	}

	// if the user only asks for the rootfs we extract the image to a temporary
	// directory and then move/copy the rootfs to the output directory, if not
	// we just extract the image to the output directory
	extractDir := absOutputDir
	if flagExtractRootfsOnly {
		rktTmpDir, err := s.TmpDir()
		if err != nil {
			stderr.PrintE("error creating rkt temporary directory", err)
			return 254
		}

		tmpDir, err := ioutil.TempDir(rktTmpDir, "rkt-image-extract-")
		if err != nil {
			stderr.PrintE("error creating temporary directory", err)
			return 254
		}
		defer os.RemoveAll(tmpDir)

		extractDir = tmpDir
	} else {
		if err := os.MkdirAll(absOutputDir, 0755); err != nil {
			stderr.PrintE("error creating output directory", err)
			return 254
		}
	}

	if err := tar.ExtractTar(aci, extractDir, false, user.NewBlankUidRange(), nil); err != nil {
		stderr.PrintE("error extracting ACI", err)
		return 254
	}

	if flagExtractRootfsOnly {
		rootfsDir := filepath.Join(extractDir, "rootfs")
		if err := os.Rename(rootfsDir, absOutputDir); err != nil {
			if e, ok := err.(*os.LinkError); ok && e.Err == syscall.EXDEV {
				// it's on a different device, fall back to copying
				if err := fileutil.CopyTree(rootfsDir, absOutputDir, user.NewBlankUidRange()); err != nil {
					stderr.PrintE("error copying ACI rootfs", err)
					return 254
				}
			} else {
				stderr.PrintE("error moving ACI rootfs", err)
				return 254
			}
		}
	}

	return 0
}
Beispiel #12
0
func runImageRender(cmd *cobra.Command, args []string) (exit int) {
	if len(args) != 2 {
		cmd.Usage()
		return 254
	}
	outputDir := args[1]

	s, err := imagestore.NewStore(storeDir())
	if err != nil {
		stderr.PrintE("cannot open store", err)
		return 254
	}

	ts, err := treestore.NewStore(treeStoreDir(), s)
	if err != nil {
		stderr.PrintE("cannot open store", err)
		return
	}

	key, err := getStoreKeyFromAppOrHash(s, args[0])
	if err != nil {
		stderr.Error(err)
		return 254
	}

	id, _, err := ts.Render(key, false)
	if err != nil {
		stderr.PrintE("error rendering ACI", err)
		return 254
	}
	if _, err := ts.Check(id); err != nil {
		stderr.Print("warning: tree cache is in a bad state. Rebuilding...")
		var err error
		if id, _, err = ts.Render(key, true); err != nil {
			stderr.PrintE("error rendering ACI", err)
			return 254
		}
	}

	if _, err := os.Stat(outputDir); err == nil {
		if !flagRenderOverwrite {
			stderr.Print("output directory exists (try --overwrite)")
			return 254
		}

		// don't allow the user to delete the root filesystem by mistake
		if outputDir == "/" {
			stderr.Print("this would delete your root filesystem. Refusing.")
			return 254
		}

		if err := os.RemoveAll(outputDir); err != nil {
			stderr.PrintE("error removing existing output dir", err)
			return 254
		}
	}
	rootfsOutDir := outputDir
	if !flagRenderRootfsOnly {
		if err := os.MkdirAll(outputDir, 0755); err != nil {
			stderr.PrintE("error creating output directory", err)
			return 254
		}
		rootfsOutDir = filepath.Join(rootfsOutDir, "rootfs")

		manifest, err := s.GetImageManifest(key)
		if err != nil {
			stderr.PrintE("error getting manifest", err)
			return 254
		}

		mb, err := json.Marshal(manifest)
		if err != nil {
			stderr.PrintE("error marshalling image manifest", err)
			return 254
		}

		if err := ioutil.WriteFile(filepath.Join(outputDir, "manifest"), mb, 0700); err != nil {
			stderr.PrintE("error writing image manifest", err)
			return 254
		}
	}

	cachedTreePath := ts.GetRootFS(id)
	if err := fileutil.CopyTree(cachedTreePath, rootfsOutDir, user.NewBlankUidRange()); err != nil {
		stderr.PrintE("error copying ACI rootfs", err)
		return 254
	}

	return 0
}
Beispiel #13
0
func runImageRender(cmd *cobra.Command, args []string) (exit int) {
	if len(args) != 2 {
		cmd.Usage()
		return 1
	}
	outputDir := args[1]

	s, err := store.NewStore(globalFlags.Dir)
	if err != nil {
		stderr("image render: cannot open store: %v", err)
		return 1
	}

	key, err := getKeyFromAppOrHash(s, args[0])
	if err != nil {
		stderr("image render: %v", err)
		return 1
	}

	if err := s.RenderTreeStore(key, false); err != nil {
		stderr("image render: error rendering ACI: %v", err)
		return 1
	}
	if err := s.CheckTreeStore(key); err != nil {
		stderr("image render: warning: tree cache is in a bad state. Rebuilding...")
		if err := s.RenderTreeStore(key, true); err != nil {
			stderr("image render: error rendering ACI: %v", err)
			return 1
		}
	}

	if _, err := os.Stat(outputDir); err == nil {
		if !flagRenderOverwrite {
			stderr("image render: output directory exists (try --overwrite)")
			return 1
		}

		// don't allow the user to delete the root filesystem by mistake
		if outputDir == "/" {
			stderr("image extract: this would delete your root filesystem. Refusing.")
			return 1
		}

		if err := os.RemoveAll(outputDir); err != nil {
			stderr("image render: error removing existing output dir: %v", err)
			return 1
		}
	}
	rootfsOutDir := outputDir
	if !flagRenderRootfsOnly {
		if err := os.MkdirAll(outputDir, 0755); err != nil {
			stderr("image render: error creating output directory: %v", err)
			return 1
		}
		rootfsOutDir = filepath.Join(rootfsOutDir, "rootfs")

		manifest, err := s.GetImageManifest(key)
		if err != nil {
			stderr("image render: error getting manifest: %v", err)
			return 1
		}

		mb, err := json.Marshal(manifest)
		if err != nil {
			stderr("image render: error marshalling image manifest: %v", err)
			return 1
		}

		if err := ioutil.WriteFile(filepath.Join(outputDir, "manifest"), mb, 0700); err != nil {
			stderr("image render: error writing image manifest: %v", err)
			return 1
		}
	}

	cachedTreePath := s.GetTreeStoreRootFS(key)
	if err := fileutil.CopyTree(cachedTreePath, rootfsOutDir); err != nil {
		stderr("image render: error copying ACI rootfs: %v", err)
		return 1
	}

	return 0
}