Example #1
0
// Atomic deploy by symlink
// 1. rsync maindir => backupdir
// 2. mv -T backuplink destdir
// 3. rsync srcdir => maindir
// 4. mv -T mainlink destdir
func DeployWithSymlink(srcDir, destDir string) error {
	mainLink := destDir + ".drootmain"
	backupLink := destDir + ".drootbackup"
	mainDir := destDir + ".d/main"
	backupDir := destDir + ".d/backup"

	for _, dir := range []string{mainDir, backupDir} {
		if err := fileutils.CreateIfNotExists(dir, true); err != nil { // mkdir -p
			return fmt.Errorf("Failed to create directory %s: %s", dir, err)
		}
	}

	// Return error if the working directory that droot internally uses exists
	for _, link := range []string{mainLink, backupLink, destDir} {
		if !osutil.IsSymlink(link) && (osutil.ExistsFile(link) || osutil.ExistsDir(link)) {
			return fmt.Errorf("%s already exists. Please use another directory as --dest option or delete %s", link, link)
		}
	}

	if err := osutil.Symlink(mainDir, mainLink); err != nil {
		return fmt.Errorf("Failed to create symlink %s: %s", mainLink, err)
	}
	if err := osutil.Symlink(backupDir, backupLink); err != nil {
		return fmt.Errorf("Failed to create symlink %s: %s", backupLink, err)
	}

	log.Info("-->", "Syncing", "from", mainDir, "to", backupDir)
	if err := Rsync(mainDir, backupDir); err != nil {
		return fmt.Errorf("Failed to rsync: %s", err)
	}

	log.Info("-->", "Renaming", "from", backupLink, "to", destDir)
	if err := os.Rename(backupLink, destDir); err != nil {
		return fmt.Errorf("Failed to rename %s: %s", destDir, err)
	}

	log.Info("-->", "Syncing", "from", srcDir, "to", mainDir)
	if err := Rsync(srcDir, mainDir); err != nil {
		return fmt.Errorf("Failed to rsync: %s", err)
	}

	log.Info("-->", "Renaming", "from", mainLink, "to", destDir)
	if err := os.Rename(mainLink, destDir); err != nil {
		return fmt.Errorf("Failed to rename %s: %s", destDir, err)
	}

	return nil
}
Example #2
0
File: run.go Project: yuuki/droot
func doRun(c *cli.Context) error {
	command := c.Args()
	if len(command) < 1 {
		cli.ShowCommandHelp(c, "run")
		return errors.New("command required")
	}

	optRootDir := c.String("root")
	if optRootDir == "" {
		cli.ShowCommandHelp(c, "run")
		return errors.New("--root option required")
	}

	rootDir, err := mounter.ResolveRootDir(optRootDir)
	if err != nil {
		return err
	}

	// Check env format KEY=VALUE
	env := c.StringSlice("env")
	if len(env) > 0 {
		for _, e := range env {
			if len(strings.SplitN(e, "=", 2)) != 2 {
				return fmt.Errorf("Invalid env format: %s", e)
			}
		}
	}

	uid, gid := os.Getuid(), os.Getgid()

	if group := c.String("group"); group != "" {
		if gid, err = osutil.LookupGroup(group); err != nil {
			return fmt.Errorf("Failed to lookup group: %s", err)
		}
	}
	if user := c.String("user"); user != "" {
		if uid, err = osutil.LookupUser(user); err != nil {
			return fmt.Errorf("Failed to lookup user: %s", err)
		}
	}

	// copy files
	if c.Bool("copy-files") {
		for _, f := range copyFiles {
			srcFile, destFile := fp.Join("/", f), fp.Join(rootDir, f)
			if err := osutil.Cp(srcFile, destFile); err != nil {
				return fmt.Errorf("Failed to copy %s: %s", f, err)
			}
			if err := os.Lchown(destFile, uid, gid); err != nil {
				return fmt.Errorf("Failed to lchown %s: %s", f, err)
			}
		}
	}

	mnt := mounter.NewMounter(rootDir)

	if err := mnt.MountSysProc(); err != nil {
		return err
	}

	for _, val := range c.StringSlice("bind") {
		hostDir, containerDir, err := parseBindOption(val)
		if err != nil {
			return err
		}
		if err := mnt.BindMount(hostDir, containerDir); err != nil {
			return err
		}
	}
	for _, val := range c.StringSlice("robind") {
		hostDir, containerDir, err := parseBindOption(val)
		if err != nil {
			return err
		}
		if err := mnt.RoBindMount(hostDir, containerDir); err != nil {
			return fmt.Errorf("Failed to robind mount %s: %s", val, err)
		}
	}

	// create symlinks
	if err := osutil.Symlink("../run/lock", fp.Join(rootDir, "/var/lock")); err != nil {
		return fmt.Errorf("Failed to symlink lock file: %s", err)
	}

	if err := createDevices(rootDir, uid, gid); err != nil {
		return fmt.Errorf("Failed to create devices: %s", err)
	}

	if err := osutil.Chroot(rootDir); err != nil {
		return fmt.Errorf("Failed to chroot: %s", err)
	}

	if !c.Bool("no-dropcaps") {
		if err := osutil.DropCapabilities(keepCaps); err != nil {
			return fmt.Errorf("Failed to drop capabilities: %s", err)
		}
	}

	if err := osutil.Setgid(gid); err != nil {
		return fmt.Errorf("Failed to set group %d: %s", gid, err)
	}
	if err := osutil.Setuid(uid); err != nil {
		return fmt.Errorf("Failed to set user %d: %s", uid, err)
	}

	if osutil.ExistsFile(environ.DROOT_ENV_FILE_PATH) {
		envFromFile, err := environ.GetEnvironFromEnvFile(environ.DROOT_ENV_FILE_PATH)
		if err != nil {
			return fmt.Errorf("Failed to read environ from '%s'", environ.DROOT_ENV_FILE_PATH)
		}
		env, err = environ.MergeEnviron(envFromFile, env)
		if err != nil {
			return fmt.Errorf("Failed to merge environ: %s", err)
		}
	}
	return osutil.Execv(command[0], command[0:], env)
}