func diff(id, parent string) (diff archive.Archive, err error) { // create pod // start or replace pod glog.Infof("Diff between %s and %s", id, parent) layerFs := "/tmp/test1" if parent == "" { archive, err := archive.Tar(layerFs, archive.Uncompressed) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() return err }), nil } parentFs := "/tmp/test2" changes, err := archive.ChangesDirs(layerFs, parentFs) if err != nil { return nil, err } archive, err := archive.ExportChanges(layerFs, changes) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() return err }), nil }
// Diff produces an archive of the changes between the specified // layer and its parent layer which may be "". func (gdw *NaiveDiffDriver) Diff(id, parent string) (arch archive.Archive, err error) { startTime := time.Now() driver := gdw.ProtoDriver layerFs, err := driver.Get(id, "") if err != nil { return nil, err } defer func() { if err != nil { driver.Put(id) } }() if parent == "" { archive, err := archive.Tar(layerFs, archive.Uncompressed) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() driver.Put(id) return err }), nil } parentFs, err := driver.Get(parent, "") if err != nil { return nil, err } defer driver.Put(parent) changes, err := archive.ChangesDirs(layerFs, parentFs) if err != nil { return nil, err } archive, err := archive.ExportChanges(layerFs, changes, gdw.uidMaps, gdw.gidMaps) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() driver.Put(id) // NaiveDiffDriver compares file metadata with parent layers. Parent layers // are extracted from tar's with full second precision on modified time. // We need this hack here to make sure calls within same second receive // correct result. time.Sleep(startTime.Truncate(time.Second).Add(time.Second).Sub(time.Now())) return err }), nil }
// Diff produces an archive of the changes between the specified // layer and its parent layer which may be "". func (gdw *naiveDiffDriver) Diff(id, parent string) (arch archive.Archive, err error) { driver := gdw.ProtoDriver layerFs, err := driver.Get(id, "") if err != nil { return nil, err } defer func() { if err != nil { driver.Put(id) } }() if parent == "" { archive, err := archive.Tar(layerFs, archive.Uncompressed) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() driver.Put(id) return err }), nil } parentFs, err := driver.Get(parent, "") if err != nil { return nil, err } defer driver.Put(parent) changes, err := archive.ChangesDirs(layerFs, parentFs) if err != nil { return nil, err } archive, err := archive.ExportChanges(layerFs, changes) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() driver.Put(id) return err }), nil }
func (container *Container) ExportRw(options *archive.ChangeOptions) (archive.Archive, error) { if err := container.Mount(); err != nil { return nil, err } if container.daemon == nil { return nil, fmt.Errorf("Can't load storage driver for unregistered container %s", container.ID) } var ( commitID = fmt.Sprintf("%s-commit", container.ID) driver = container.daemon.driver ) // create tmp rootfs for commit if err := container.daemon.createTmpRootfs(container); err != nil { return nil, err } defer driver.Remove(commitID) archive, err := driver.Diff(container.ID, commitID, options) if err != nil { container.Unmount() return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() container.Unmount() return err }), 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 { dest, err := container.GetResourcePath(m.Destination) if 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 } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() container.UnmountVolumes(true) container.Unmount() return err }), nil }
func (container *Container) Copy(resource string) (io.ReadCloser, error) { if err := container.Mount(); err != nil { return nil, err } basePath, err := container.getResourcePath(resource) if err != nil { container.Unmount() return nil, err } // Check if this is actually in a volume for _, mnt := range container.VolumeMounts() { if len(mnt.MountToPath) > 0 && strings.HasPrefix(resource, mnt.MountToPath[1:]) { return mnt.Export(resource) } } // Check if this is a special one (resolv.conf, hostname, ..) if resource == "etc/resolv.conf" { basePath = container.ResolvConfPath } if resource == "etc/hostname" { basePath = container.HostnamePath } if resource == "etc/hosts" { basePath = container.HostsPath } stat, err := os.Stat(basePath) if err != nil { container.Unmount() return nil, err } var filter []string if !stat.IsDir() { d, f := path.Split(basePath) basePath = d filter = []string{f} } else { filter = []string{path.Base(basePath)} basePath = path.Dir(basePath) } archive, err := archive.TarWithOptions(basePath, &archive.TarOptions{ Compression: archive.Uncompressed, IncludeFiles: filter, }) if err != nil { container.Unmount() return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() container.Unmount() return err }), 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 { container.Unmount() } }() if err = container.mountVolumes(); err != nil { container.unmountVolumes() return nil, err } defer func() { if err != nil { container.unmountVolumes() } }() 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 := path.Split(basePath) basePath = d filter = []string{f} } else { filter = []string{path.Base(basePath)} basePath = path.Dir(basePath) } archive, err := archive.TarWithOptions(basePath, &archive.TarOptions{ Compression: archive.Uncompressed, IncludeFiles: filter, }) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() container.unmountVolumes() container.Unmount() return err }), nil }
func (daemon *Daemon) exportContainerRw(container *Container) (archive.Archive, error) { archive, err := daemon.diff(container) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() return err }), nil }
func (container *Container) exportContainerRw() (archive.Archive, error) { if container.daemon == nil { return nil, fmt.Errorf("Can't load storage driver for unregistered container %s", container.ID) } archive, err := container.daemon.diff(container) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() return err }), nil }
func (container *Container) exportContainerRw() (archive.Archive, error) { if container.daemon == nil { return nil, derr.ErrorCodeUnregisteredContainer.WithArgs(container.ID) } archive, err := container.daemon.diff(container) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() return err }), nil }
func (daemon *Daemon) exportContainerRw(container *container.Container) (archive.Archive, error) { if err := daemon.Mount(container); err != nil { return nil, err } archive, err := container.RWLayer.TarStream() if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { archive.Close() return container.RWLayer.Unmount() }), nil }
// exportLayer generates an archive from a layer based on the given ID. func (d *Driver) exportLayer(id string, parentLayerPaths []string) (archive.Archive, error) { if hcsshim.IsTP4() { // Export in TP4 format to maintain compatibility with existing images and // because ExportLayer is somewhat broken on TP4 and can't work with the new // scheme. tempFolder, err := ioutil.TempDir("", "hcs") if err != nil { return nil, err } defer func() { if err != nil { os.RemoveAll(tempFolder) } }() if err = hcsshim.ExportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil { return nil, err } archive, err := archive.Tar(tempFolder, archive.Uncompressed) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() os.RemoveAll(tempFolder) return err }), nil } var r hcsshim.LayerReader r, err := hcsshim.NewLayerReader(d.info, id, parentLayerPaths) if err != nil { return nil, err } archive, w := io.Pipe() go func() { err := writeTarFromLayer(r, w) cerr := r.Close() if err == nil { err = cerr } w.CloseWithError(err) }() return archive, nil }
func (container *Container) ExportRw() (archive.Archive, error) { if container.daemon == nil { return nil, fmt.Errorf("Can't load storage driver for unregistered container %s", container.ID) } glog.V(2).Infof("container address %p, daemon address %p", container, container.daemon) archive, err := container.daemon.Diff(container) // archive, err := diff("/tmp/test1/", "") if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() return err }), nil return nil, nil }
func (container *Container) Export() (archive.Archive, error) { if err := container.Mount(); err != nil { return nil, err } archive, err := archive.Tar(container.basefs, archive.Uncompressed) if err != nil { container.Unmount() return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() container.Unmount() return err }), nil }
func (container *Container) export(ctx context.Context) (archive.Archive, error) { if err := container.Mount(ctx); err != nil { return nil, err } archive, err := archive.Tar(container.basefs, archive.Uncompressed) if err != nil { container.Unmount(ctx) return nil, err } arch := ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() container.Unmount(ctx) return err }) container.logEvent(ctx, "export") return arch, err }
func (d *WindowsGraphDriver) Export(id string, parentLayerPaths []string) (arch archive.Archive, err error) { layerFs, err := d.Get(id, "") if err != nil { return } defer func() { if err != nil { d.Put(id) } }() tempFolder := layerFs + "-temp" if err = os.MkdirAll(tempFolder, 0755); err != nil { logrus.Errorf("Could not create %s %s", tempFolder, err) return } defer func() { if err != nil { if err2 := os.RemoveAll(tempFolder); err2 != nil { logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2) } } }() if err = hcsshim.ExportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil { return } archive, err := archive.Tar(tempFolder, archive.Uncompressed) if err != nil { return } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() d.Put(id) if err2 := os.RemoveAll(tempFolder); err2 != nil { logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2) } return err }), nil }
func (daemon *Daemon) containerExport(container *container.Container) (io.ReadCloser, error) { if err := daemon.Mount(container); err != nil { return nil, err } uidMaps, gidMaps := daemon.GetUIDGIDMaps() archive, err := archive.TarWithOptions(container.BaseFS, &archive.TarOptions{ Compression: archive.Uncompressed, UIDMaps: uidMaps, GIDMaps: gidMaps, }) if err != nil { daemon.Unmount(container) return nil, err } arch := ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() daemon.Unmount(container) return err }) daemon.LogContainerEvent(container, "export") return arch, err }
func (container *Container) export() (archive.Archive, error) { if err := container.Mount(); err != nil { return nil, err } uidMaps, gidMaps := container.daemon.GetUIDGIDMaps() archive, err := archive.TarWithOptions(container.basefs, &archive.TarOptions{ Compression: archive.Uncompressed, UIDMaps: uidMaps, GIDMaps: gidMaps, }) if err != nil { container.Unmount() return nil, err } arch := ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() container.Unmount() return err }) container.logEvent("export") return arch, err }
// exportLayer generates an archive from a layer based on the given ID. func (d *Driver) exportLayer(id string, parentLayerPaths []string) (arch archive.Archive, err error) { layerFolder := d.dir(id) tempFolder := layerFolder + "-" + strconv.FormatUint(uint64(random.Rand.Uint32()), 10) if err = os.MkdirAll(tempFolder, 0755); err != nil { logrus.Errorf("Could not create %s %s", tempFolder, err) return } defer func() { if err != nil { _, folderName := filepath.Split(tempFolder) if err2 := hcsshim.DestroyLayer(d.info, folderName); err2 != nil { logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2) } } }() if err = hcsshim.ExportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil { return } archive, err := archive.Tar(tempFolder, archive.Uncompressed) if err != nil { return } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() d.Put(id) _, folderName := filepath.Split(tempFolder) if err2 := hcsshim.DestroyLayer(d.info, folderName); err2 != nil { logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2) } return err }), nil }
func (d *Driver) Diff(id, parent string) (diff archive.Archive, err error) { if d.daemon == nil { if err := d.Setup(); err != nil { return nil, err } } var ( podData string tgtDisk string = "" code int cause string ) srcDisk := fmt.Sprintf("%s/images/%s.vdi", d.RootPath(), id) if parent != "" { tgtDisk = fmt.Sprintf("%s/images/%s.vdi", d.RootPath(), parent) } outDir := path.Join(utils.HYPER_ROOT, "tar") if err := os.MkdirAll(outDir, 0755); err != nil { return nil, err } uuid, err := virtualbox.GetMediumUUID(srcDisk) if err == nil { srcDisk = uuid } // create pod podId := "diff-" + id[:10] podData, err = MakeDiffPod(podId, "puller:latest", id, srcDisk, tgtDisk, outDir) if err != nil { return nil, err } // start or replace pod vm, ok := d.daemon.VmList[d.pullVm] if !ok { return nil, fmt.Errorf("can not find VM(%s)", d.pullVm) } if vm.Status == types.S_VM_IDLE { code, cause, err = d.daemon.RunPod(podId, podData, d.pullVm, nil, false, true, types.VM_KEEP_AFTER_SHUTDOWN, []*hypervisor.TtyIO{}) if err != nil { glog.Errorf("Code is %d, Cause is %s, %s", code, cause, err.Error()) d.daemon.KillVm(d.pullVm) return nil, err } vm := d.daemon.VmList[d.pullVm] // wait for cmd finish Status, err := vm.GetResponseChan() if err != nil { glog.Error(err.Error()) return nil, err } defer vm.ReleaseResponseChan(Status) var vmResponse *types.VmResponse for { vmResponse = <-Status if vmResponse.VmId == d.pullVm { if vmResponse.Code == types.E_POD_FINISHED { glog.Infof("Got E_POD_FINISHED code response") break } } } pod, ok := d.daemon.PodList.Get(podId) if !ok { glog.Errorf("pod %s does not exist", podId) return nil, fmt.Errorf("pod %s does not exist", podId) } pod.SetVM(d.pullVm, vm) // release pod from VM code, cause, err = d.daemon.StopPod(podId, "no") if err != nil { glog.Errorf("Code is %d, Cause is %s, %s", code, cause, err.Error()) d.daemon.KillVm(d.pullVm) return nil, err } d.daemon.CleanPod(podId) } else { glog.Errorf("pull vm should not be associated") return nil, fmt.Errorf("pull vm is not idle") } tarFile := outDir + "/" + id + ".tar" if _, err := os.Stat(tarFile); err != nil { // If the parent is nil, the first layer is also nil. // So we may not got tar file if parent == "" { layerFs := fmt.Sprintf("%s/diff/%s", d.RootPath(), id) archive, err := archive.Tar(layerFs, archive.Uncompressed) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() return err }), nil } else { return nil, fmt.Errorf("the out tar file is not exist") } } f, err := os.Open(tarFile) if err != nil { return nil, err } var archive io.ReadCloser archive = ioutil.NopCloser(f) glog.Infof("Diff between %s and %s", id, parent) return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() return err }), nil }
func (container *Container) copy(resource string) (rc io.ReadCloser, err error) { container.Lock() defer func() { if err != nil { // Wait to unlock the container until the archive is fully read // (see the ReadCloseWrapper func below) or if there is an error // before that occurs. container.Unlock() } }() 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() } }() if err := container.mountVolumes(); 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() container.Unlock() return err }) container.logEvent("copy") return reader, nil }