|
56 | 56 | package lcow // import "github.com/docker/docker/daemon/graphdriver/lcow" |
57 | 57 |
|
58 | 58 | import ( |
| 59 | + "bytes" |
59 | 60 | "encoding/json" |
60 | 61 | "fmt" |
61 | 62 | "io" |
62 | 63 | "io/ioutil" |
63 | 64 | "os" |
| 65 | + "path" |
64 | 66 | "path/filepath" |
65 | 67 | "strconv" |
66 | 68 | "strings" |
@@ -964,3 +966,87 @@ func hostToGuest(hostpath string) string { |
964 | 966 | func unionMountName(disks []hcsshim.MappedVirtualDisk) string { |
965 | 967 | return fmt.Sprintf("%s-mount", disks[0].ContainerPath) |
966 | 968 | } |
| 969 | + |
| 970 | +type nopCloser struct { |
| 971 | + io.Reader |
| 972 | +} |
| 973 | + |
| 974 | +func (nopCloser) Close() error { |
| 975 | + return nil |
| 976 | +} |
| 977 | + |
| 978 | +type fileGetCloserFromSVM struct { |
| 979 | + id string |
| 980 | + svm *serviceVM |
| 981 | + mvd *hcsshim.MappedVirtualDisk |
| 982 | + d *Driver |
| 983 | +} |
| 984 | + |
| 985 | +func (fgc *fileGetCloserFromSVM) Close() error { |
| 986 | + if fgc.svm != nil { |
| 987 | + if fgc.mvd != nil { |
| 988 | + if err := fgc.svm.hotRemoveVHDs(*fgc.mvd); err != nil { |
| 989 | + // We just log this as we're going to tear down the SVM imminently unless in global mode |
| 990 | + logrus.Errorf("failed to remove mvd %s: %s", fgc.mvd.ContainerPath, err) |
| 991 | + } |
| 992 | + } |
| 993 | + } |
| 994 | + if fgc.d != nil && fgc.svm != nil && fgc.id != "" { |
| 995 | + if err := fgc.d.terminateServiceVM(fgc.id, fmt.Sprintf("diffgetter %s", fgc.id), false); err != nil { |
| 996 | + return err |
| 997 | + } |
| 998 | + } |
| 999 | + return nil |
| 1000 | +} |
| 1001 | + |
| 1002 | +func (fgc *fileGetCloserFromSVM) Get(filename string) (io.ReadCloser, error) { |
| 1003 | + errOut := &bytes.Buffer{} |
| 1004 | + outOut := &bytes.Buffer{} |
| 1005 | + file := path.Join(fgc.mvd.ContainerPath, filename) |
| 1006 | + if err := fgc.svm.runProcess(fmt.Sprintf("cat %s", file), nil, outOut, errOut); err != nil { |
| 1007 | + logrus.Debugf("cat %s failed: %s", file, errOut.String()) |
| 1008 | + return nil, err |
| 1009 | + } |
| 1010 | + return nopCloser{bytes.NewReader(outOut.Bytes())}, nil |
| 1011 | +} |
| 1012 | + |
| 1013 | +// DiffGetter returns a FileGetCloser that can read files from the directory that |
| 1014 | +// contains files for the layer differences. Used for direct access for tar-split. |
| 1015 | +func (d *Driver) DiffGetter(id string) (graphdriver.FileGetCloser, error) { |
| 1016 | + title := fmt.Sprintf("lcowdriver: diffgetter: %s", id) |
| 1017 | + logrus.Debugf(title) |
| 1018 | + |
| 1019 | + ld, err := getLayerDetails(d.dir(id)) |
| 1020 | + if err != nil { |
| 1021 | + logrus.Debugf("%s: failed to get vhdx information of %s: %s", title, d.dir(id), err) |
| 1022 | + return nil, err |
| 1023 | + } |
| 1024 | + |
| 1025 | + // Start the SVM with a mapped virtual disk. Note that if the SVM is |
| 1026 | + // already running and we are in global mode, this will be hot-added. |
| 1027 | + mvd := hcsshim.MappedVirtualDisk{ |
| 1028 | + HostPath: ld.filename, |
| 1029 | + ContainerPath: hostToGuest(ld.filename), |
| 1030 | + CreateInUtilityVM: true, |
| 1031 | + ReadOnly: true, |
| 1032 | + } |
| 1033 | + |
| 1034 | + logrus.Debugf("%s: starting service VM", title) |
| 1035 | + svm, err := d.startServiceVMIfNotRunning(id, []hcsshim.MappedVirtualDisk{mvd}, fmt.Sprintf("diffgetter %s", id)) |
| 1036 | + if err != nil { |
| 1037 | + return nil, err |
| 1038 | + } |
| 1039 | + |
| 1040 | + logrus.Debugf("%s: waiting for svm to finish booting", title) |
| 1041 | + err = svm.getStartError() |
| 1042 | + if err != nil { |
| 1043 | + d.terminateServiceVM(id, fmt.Sprintf("diff %s", id), false) |
| 1044 | + return nil, fmt.Errorf("%s: svm failed to boot: %s", title, err) |
| 1045 | + } |
| 1046 | + |
| 1047 | + return &fileGetCloserFromSVM{ |
| 1048 | + id: id, |
| 1049 | + svm: svm, |
| 1050 | + mvd: &mvd, |
| 1051 | + d: d}, nil |
| 1052 | +} |
0 commit comments