func (daemon *Daemon) mountVolumes(container *Container) error { mounts, err := daemon.setupMounts(container) if err != nil { return err } for _, m := range mounts { dest, err := container.GetResourcePath(m.Destination) if err != nil { return err } var stat os.FileInfo stat, err = os.Stat(m.Source) if err != nil { return err } if err = fileutils.CreateIfNotExists(dest, stat.IsDir()); err != nil { return err } opts := "rbind,ro" if m.Writable { opts = "rbind,rw" } if err := mount.Mount(m.Source, dest, "bind", opts); err != nil { return err } } return nil }
func bindMount(bindDir string, rootDir string, readonly bool) error { var srcDir, destDir string d := strings.SplitN(bindDir, ":", 2) if len(d) < 2 { srcDir = d[0] } else { srcDir, destDir = d[0], d[1] } if destDir == "" { destDir = srcDir } ok, err := osutil.IsDirEmpty(srcDir) if err != nil { return err } if ok { if _, err := os.Create(fp.Join(srcDir, ".droot.keep")); err != nil { return errwrap.Wrapf(err, "Failed to create .droot.keep: {{err}}") } } containerDir := fp.Join(rootDir, destDir) if err := fileutils.CreateIfNotExists(containerDir, true); err != nil { // mkdir -p return errwrap.Wrapff(err, "Failed to create directory: %s: {{err}}", containerDir) } ok, err = osutil.IsDirEmpty(containerDir) if err != nil { return err } if ok { log.Debug("bind mount", bindDir, "to", containerDir) if err := mount.Mount(srcDir, containerDir, "none", "bind,rw"); err != nil { return errwrap.Wrapff(err, "Failed to bind mount %s: {{err}}", containerDir) } if readonly { log.Debug("robind mount", bindDir, "to", containerDir) if err := mount.Mount(srcDir, containerDir, "none", "remount,ro,bind"); err != nil { return errwrap.Wrapff(err, "Failed to robind mount %s: {{err}}", containerDir) } } } return nil }
// 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 }
func (daemon *Daemon) mountVolumes(container *container.Container) error { mounts, err := daemon.setupMounts(container) if err != nil { return err } for _, m := range mounts { dest, err := container.GetResourcePath(m.Destination) if err != nil { return err } var stat os.FileInfo stat, err = os.Stat(m.Source) if err != nil { return err } if err = fileutils.CreateIfNotExists(dest, stat.IsDir()); err != nil { return err } opts := "rbind,ro" if m.Writable { opts = "rbind,rw" } if err := mount.Mount(m.Source, dest, bindMountType, opts); err != nil { return err } // mountVolumes() seems to be called for temporary mounts // outside the container. Soon these will be unmounted with // lazy unmount option and given we have mounted the rbind, // all the submounts will propagate if these are shared. If // daemon is running in host namespace and has / as shared // then these unmounts will propagate and unmount original // mount as well. So make all these mounts rprivate. // Do not use propagation property of volume as that should // apply only when mounting happen inside the container. if err := mount.MakeRPrivate(dest); err != nil { return err } } return nil }
func (m *Mounter) BindMount(hostDir, containerDir string) error { containerDir = fp.Join(m.rootDir, containerDir) if ok := osutil.IsDirEmpty(hostDir); ok { if _, err := os.Create(fp.Join(hostDir, ".droot.keep")); err != nil { return err } } if err := fileutils.CreateIfNotExists(containerDir, true); err != nil { // mkdir -p return err } if err := osutil.MountIfNotMounted(hostDir, containerDir, "none", "bind,rw"); err != nil { return err } return nil }
func (container *Container) Copy(resource string) (io.ReadCloser, error) { container.Lock() defer container.Unlock() var err error if err := container.Mount(); err != nil { return nil, err } defer func() { if err != nil { // unmount any volumes container.UnmountVolumes(true) // unmount the container's rootfs container.Unmount() } }() mounts, err := container.setupMounts() if err != nil { return nil, err } for _, m := range mounts { var dest string dest, err = container.GetResourcePath(m.Destination) if err != nil { return nil, err } var stat os.FileInfo stat, err = os.Stat(m.Source) if err != nil { return nil, err } if err = fileutils.CreateIfNotExists(dest, stat.IsDir()); err != nil { return nil, err } if err = mount.Mount(m.Source, dest, "bind", "rbind,ro"); err != nil { return nil, err } } basePath, err := container.GetResourcePath(resource) if err != nil { return nil, err } stat, err := os.Stat(basePath) if err != nil { return nil, err } var filter []string if !stat.IsDir() { d, f := filepath.Split(basePath) basePath = d filter = []string{f} } else { filter = []string{filepath.Base(basePath)} basePath = filepath.Dir(basePath) } archive, err := archive.TarWithOptions(basePath, &archive.TarOptions{ Compression: archive.Uncompressed, IncludeFiles: filter, }) if err != nil { return nil, err } reader := ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() container.UnmountVolumes(true) container.Unmount() return err }) container.LogEvent("copy") return reader, nil }