Skip to content

Commit

Permalink
feature: populate empty volumes when creating container
Browse files Browse the repository at this point in the history
Signed-off-by: Eric Li <[email protected]>
  • Loading branch information
shaloulcy committed Jul 17, 2018
1 parent f29327d commit 7bf8568
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 11 deletions.
1 change: 0 additions & 1 deletion apis/opts/mountpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ func ParseVolumesFrom(volume string) (string, string, error) {
// ParseBindMode is used to parse the bind's mode.
func ParseBindMode(mp *types.MountPoint, mode string) error {
mp.RW = true
mp.CopyData = true

defaultMode := 0
rwMode := 0
Expand Down
122 changes: 112 additions & 10 deletions daemon/mgr/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -1950,6 +1950,12 @@ func (mgr *ContainerManager) generateMountPoints(ctx context.Context, c *Contain
return errors.Wrap(err, "failed to get mount point from volumes")
}

// 5. populate the volumes
err = mgr.populateVolumes(ctx, c)
if err != nil {
return errors.Wrap(err, "failed to populate volumes")
}

return nil
}

Expand All @@ -1973,6 +1979,7 @@ func (mgr *ContainerManager) getMountPointFromBinds(ctx context.Context, c *Cont
case 1:
mp.Source = ""
mp.Destination = parts[0]
mp.CopyData = true
case 2:
mp.Source = parts[0]
mp.Destination = parts[1]
Expand All @@ -1993,11 +2000,6 @@ func (mgr *ContainerManager) getMountPointFromBinds(ctx context.Context, c *Cont

if mp.Source == "" {
mp.Source = randomid.Generate()

// Source is empty, anonymouse volume
if _, exist := c.Config.Volumes[mp.Destination]; !exist {
c.Config.Volumes[mp.Destination] = struct{}{}
}
}

err = opts.ParseBindMode(mp, mode)
Expand Down Expand Up @@ -2037,6 +2039,7 @@ func (mgr *ContainerManager) getMountPointFromBinds(ctx context.Context, c *Cont
mp.Named = false
mp.Driver = ""
}
mp.CopyData = true
}

if _, err = os.Stat(mp.Source); err != nil {
Expand Down Expand Up @@ -2075,6 +2078,7 @@ func (mgr *ContainerManager) getMountPointFromVolumes(ctx context.Context, c *Co
mp := new(types.MountPoint)
mp.Name = name
mp.Destination = dest
mp.CopyData = true

mp.Source, mp.Driver, err = mgr.attachVolume(ctx, mp.Name, c)
if err != nil {
Expand Down Expand Up @@ -2104,10 +2108,6 @@ func (mgr *ContainerManager) getMountPointFromImage(ctx context.Context, c *Cont
return errors.Wrapf(err, "failed to get image: %s", c.Image)
}
for dest := range image.Config.Volumes {
if _, exist := c.Config.Volumes[dest]; !exist {
c.Config.Volumes[dest] = struct{}{}
}

// check if volume has been created
name := randomid.Generate()
if _, exist := volumeSet[name]; exist {
Expand All @@ -2122,6 +2122,7 @@ func (mgr *ContainerManager) getMountPointFromImage(ctx context.Context, c *Cont
mp := new(types.MountPoint)
mp.Name = name
mp.Destination = dest
mp.CopyData = true

mp.Source, mp.Driver, err = mgr.attachVolume(ctx, mp.Name, c)
if err != nil {
Expand Down Expand Up @@ -2172,6 +2173,7 @@ func (mgr *ContainerManager) getMountPointFromContainers(ctx context.Context, co
Named: oldMountPoint.Named,
RW: oldMountPoint.RW,
Propagation: oldMountPoint.Propagation,
CopyData: false,
}

if _, exist := volumeSet[oldMountPoint.Name]; len(oldMountPoint.Name) > 0 && !exist {
Expand All @@ -2182,7 +2184,6 @@ func (mgr *ContainerManager) getMountPointFromContainers(ctx context.Context, co
return errors.Wrap(err, "failed to bind volume")
}

container.Config.Volumes[mp.Destination] = struct{}{}
volumeSet[mp.Name] = struct{}{}
}

Expand All @@ -2199,6 +2200,37 @@ func (mgr *ContainerManager) getMountPointFromContainers(ctx context.Context, co
return nil
}

func (mgr *ContainerManager) populateVolumes(ctx context.Context, c *Container) error {
err := mgr.Mount(ctx, c)
if err != nil {
return err
}
defer mgr.Unmount(ctx, c)

for _, mnt := range c.Mounts {
if mnt.Driver == "tmpfs" {
continue
}

if !mnt.CopyData {
continue
}

logrus.Debugf("copying image data from %s:%s, to %s, path: %s",
c.ID, mnt.Destination, mnt.Name, mnt.Source)

imagePath := path.Join(mgr.Store.Path(c.ID), "rootfs", mnt.Destination)

err := copyImageContent(imagePath, mnt.Source)
if err != nil {
logrus.Errorf("failed to populate volume[name: %s, source: %s] err: %v", mnt.Name, mnt.Source, err)
return err
}
}

return nil
}

func (mgr *ContainerManager) setMountPointDiskQuota(ctx context.Context, c *Container) error {
if c.Config.DiskQuota == nil {
if c.Config.QuotaID != "" && c.Config.QuotaID != "0" {
Expand Down Expand Up @@ -2386,3 +2418,73 @@ func (mgr *ContainerManager) execProcessGC() {
func (mgr *ContainerManager) NewSnapshotsSyncer(snapshotStore *SnapshotStore, duration time.Duration) *SnapshotsSyncer {
return newSnapshotsSyncer(snapshotStore, mgr.Client, duration)
}

// Mount sets the container rootfs
func (mgr *ContainerManager) Mount(ctx context.Context, c *Container) error {
mounts, err := mgr.Client.GetMounts(ctx, c.ID)
if err != nil {
return err
} else if len(mounts) != 1 {
return fmt.Errorf("failed to get snapshot %s mounts: not equals 1", c.ID)
}

mountPath := path.Join(mgr.Store.Path(c.ID), "rootfs")

err = os.MkdirAll(mountPath, 0755)
if err != nil && !os.IsExist(err) {
return err
}

return mounts[0].Mount(mountPath)
}

// Unmount unsets the container rootfs
func (mgr *ContainerManager) Unmount(ctx context.Context, c *Container) error {
mountPath := path.Join(mgr.Store.Path(c.ID), "rootfs")

err := mount.Unmount(mountPath, 0)
if err != nil {
return err
}

return os.RemoveAll(mountPath)
}

func copyImageContent(source, destination string) error {
volList, err := ioutil.ReadDir(source)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}

if len(volList) > 0 {
dstList, err := ioutil.ReadDir(destination)
if err != nil {
return err
}
if len(dstList) == 0 {
// TODO: refactor

// If the source volume is empty, copies files from the root into the volume
commandLine := fmt.Sprintf("cp -r %s/* %s", source, destination)

cmd := exec.Command("sh", "-c", commandLine)
out, err := cmd.CombinedOutput()
if err != nil {
logrus.Errorf("copyImageContent: %s, %v", string(out), err)
return err
}
}
}
return copyOwnership(source, destination)
}

func copyOwnership(source, destination string) error {
fi, err := os.Stat(source)
if err != nil {
return err
}
return os.Chmod(destination, os.FileMode(fi.Mode()))
}

0 comments on commit 7bf8568

Please sign in to comment.