github.com/afein/docker@v1.8.2/daemon/graphdriver/windows/windows.go (about)

     1  //+build windows
     2  
     3  package windows
     4  
     5  import (
     6  	"fmt"
     7  	"os"
     8  	"path/filepath"
     9  	"sync"
    10  	"time"
    11  
    12  	"github.com/Sirupsen/logrus"
    13  	"github.com/docker/docker/daemon/graphdriver"
    14  	"github.com/docker/docker/pkg/archive"
    15  	"github.com/docker/docker/pkg/chrootarchive"
    16  	"github.com/docker/docker/pkg/ioutils"
    17  	"github.com/microsoft/hcsshim"
    18  )
    19  
    20  func init() {
    21  	graphdriver.Register("windowsfilter", InitFilter)
    22  	graphdriver.Register("windowsdiff", InitDiff)
    23  }
    24  
    25  const (
    26  	diffDriver = iota
    27  	filterDriver
    28  )
    29  
    30  type WindowsGraphDriver struct {
    31  	info       hcsshim.DriverInfo
    32  	sync.Mutex // Protects concurrent modification to active
    33  	active     map[string]int
    34  }
    35  
    36  // New returns a new Windows storage filter driver.
    37  func InitFilter(home string, options []string) (graphdriver.Driver, error) {
    38  	logrus.Debugf("WindowsGraphDriver InitFilter at %s", home)
    39  	d := &WindowsGraphDriver{
    40  		info: hcsshim.DriverInfo{
    41  			HomeDir: home,
    42  			Flavour: filterDriver,
    43  		},
    44  		active: make(map[string]int),
    45  	}
    46  	return d, nil
    47  }
    48  
    49  // New returns a new Windows differencing disk driver.
    50  func InitDiff(home string, options []string) (graphdriver.Driver, error) {
    51  	logrus.Debugf("WindowsGraphDriver InitDiff at %s", home)
    52  	d := &WindowsGraphDriver{
    53  		info: hcsshim.DriverInfo{
    54  			HomeDir: home,
    55  			Flavour: diffDriver,
    56  		},
    57  		active: make(map[string]int),
    58  	}
    59  	return d, nil
    60  }
    61  
    62  func (d *WindowsGraphDriver) Info() hcsshim.DriverInfo {
    63  	return d.info
    64  }
    65  
    66  func (d *WindowsGraphDriver) String() string {
    67  	switch d.info.Flavour {
    68  	case diffDriver:
    69  		return "windowsdiff"
    70  	case filterDriver:
    71  		return "windowsfilter"
    72  	default:
    73  		return "Unknown driver flavour"
    74  	}
    75  }
    76  
    77  func (d *WindowsGraphDriver) Status() [][2]string {
    78  	return [][2]string{
    79  		{"Windows", ""},
    80  	}
    81  }
    82  
    83  // Exists returns true if the given id is registered with
    84  // this driver
    85  func (d *WindowsGraphDriver) Exists(id string) bool {
    86  	result, err := hcsshim.LayerExists(d.info, id)
    87  	if err != nil {
    88  		return false
    89  	}
    90  	return result
    91  }
    92  
    93  func (d *WindowsGraphDriver) Create(id, parent string) error {
    94  	return hcsshim.CreateLayer(d.info, id, parent)
    95  }
    96  
    97  func (d *WindowsGraphDriver) dir(id string) string {
    98  	return filepath.Join(d.info.HomeDir, filepath.Base(id))
    99  }
   100  
   101  // Remove unmounts and removes the dir information
   102  func (d *WindowsGraphDriver) Remove(id string) error {
   103  	return hcsshim.DestroyLayer(d.info, id)
   104  }
   105  
   106  // Get returns the rootfs path for the id. This will mount the dir at it's given path
   107  func (d *WindowsGraphDriver) Get(id, mountLabel string) (string, error) {
   108  	var dir string
   109  
   110  	d.Lock()
   111  	defer d.Unlock()
   112  
   113  	if d.active[id] == 0 {
   114  		if err := hcsshim.ActivateLayer(d.info, id); err != nil {
   115  			return "", err
   116  		}
   117  	}
   118  
   119  	mountPath, err := hcsshim.GetLayerMountPath(d.info, id)
   120  	if err != nil {
   121  		return "", err
   122  	}
   123  
   124  	// If the layer has a mount path, use that. Otherwise, use the
   125  	// folder path.
   126  	if mountPath != "" {
   127  		dir = mountPath
   128  	} else {
   129  		dir = d.dir(id)
   130  	}
   131  
   132  	d.active[id]++
   133  
   134  	return dir, nil
   135  }
   136  
   137  func (d *WindowsGraphDriver) Put(id string) error {
   138  	logrus.Debugf("WindowsGraphDriver Put() id %s", id)
   139  
   140  	d.Lock()
   141  	defer d.Unlock()
   142  
   143  	if d.active[id] > 1 {
   144  		d.active[id]--
   145  	} else if d.active[id] == 1 {
   146  		if err := hcsshim.DeactivateLayer(d.info, id); err != nil {
   147  			return err
   148  		}
   149  		delete(d.active, id)
   150  	}
   151  
   152  	return nil
   153  }
   154  
   155  func (d *WindowsGraphDriver) Cleanup() error {
   156  	return nil
   157  }
   158  
   159  // Diff produces an archive of the changes between the specified
   160  // layer and its parent layer which may be "".
   161  func (d *WindowsGraphDriver) Diff(id, parent string) (arch archive.Archive, err error) {
   162  	return nil, fmt.Errorf("The Windows graphdriver does not support Diff()")
   163  }
   164  
   165  // Changes produces a list of changes between the specified layer
   166  // and its parent layer. If parent is "", then all changes will be ADD changes.
   167  func (d *WindowsGraphDriver) Changes(id, parent string) ([]archive.Change, error) {
   168  	return nil, fmt.Errorf("The Windows graphdriver does not support Changes()")
   169  }
   170  
   171  // ApplyDiff extracts the changeset from the given diff into the
   172  // layer with the specified id and parent, returning the size of the
   173  // new layer in bytes.
   174  func (d *WindowsGraphDriver) ApplyDiff(id, parent string, diff archive.ArchiveReader) (size int64, err error) {
   175  	start := time.Now().UTC()
   176  	logrus.Debugf("WindowsGraphDriver ApplyDiff: Start untar layer")
   177  
   178  	destination := d.dir(id)
   179  	if d.info.Flavour == diffDriver {
   180  		destination = filepath.Dir(destination)
   181  	}
   182  
   183  	if size, err = chrootarchive.ApplyLayer(destination, diff); err != nil {
   184  		return
   185  	}
   186  	logrus.Debugf("WindowsGraphDriver ApplyDiff: Untar time: %vs", time.Now().UTC().Sub(start).Seconds())
   187  
   188  	return
   189  }
   190  
   191  // DiffSize calculates the changes between the specified layer
   192  // and its parent and returns the size in bytes of the changes
   193  // relative to its base filesystem directory.
   194  func (d *WindowsGraphDriver) DiffSize(id, parent string) (size int64, err error) {
   195  	changes, err := d.Changes(id, parent)
   196  	if err != nil {
   197  		return
   198  	}
   199  
   200  	layerFs, err := d.Get(id, "")
   201  	if err != nil {
   202  		return
   203  	}
   204  	defer d.Put(id)
   205  
   206  	return archive.ChangesSize(layerFs, changes), nil
   207  }
   208  
   209  func (d *WindowsGraphDriver) CopyDiff(sourceId, id string, parentLayerPaths []string) error {
   210  	d.Lock()
   211  	defer d.Unlock()
   212  
   213  	if d.info.Flavour == filterDriver && d.active[sourceId] == 0 {
   214  		if err := hcsshim.ActivateLayer(d.info, sourceId); err != nil {
   215  			return err
   216  		}
   217  		defer func() {
   218  			err := hcsshim.DeactivateLayer(d.info, sourceId)
   219  			if err != nil {
   220  				logrus.Warnf("Failed to Deactivate %s: %s", sourceId, err)
   221  			}
   222  		}()
   223  	}
   224  
   225  	return hcsshim.CopyLayer(d.info, sourceId, id, parentLayerPaths)
   226  }
   227  
   228  func (d *WindowsGraphDriver) LayerIdsToPaths(ids []string) []string {
   229  	var paths []string
   230  	for _, id := range ids {
   231  		path, err := d.Get(id, "")
   232  		if err != nil {
   233  			logrus.Debug("LayerIdsToPaths: Error getting mount path for id", id, ":", err.Error())
   234  			return nil
   235  		}
   236  		if d.Put(id) != nil {
   237  			logrus.Debug("LayerIdsToPaths: Error putting mount path for id", id, ":", err.Error())
   238  			return nil
   239  		}
   240  		paths = append(paths, path)
   241  	}
   242  	return paths
   243  }
   244  
   245  func (d *WindowsGraphDriver) GetMetadata(id string) (map[string]string, error) {
   246  	return nil, nil
   247  }
   248  
   249  func (d *WindowsGraphDriver) Export(id string, parentLayerPaths []string) (arch archive.Archive, err error) {
   250  	layerFs, err := d.Get(id, "")
   251  	if err != nil {
   252  		return
   253  	}
   254  	defer func() {
   255  		if err != nil {
   256  			d.Put(id)
   257  		}
   258  	}()
   259  
   260  	tempFolder := layerFs + "-temp"
   261  	if err = os.MkdirAll(tempFolder, 0755); err != nil {
   262  		logrus.Errorf("Could not create %s %s", tempFolder, err)
   263  		return
   264  	}
   265  	defer func() {
   266  		if err != nil {
   267  			if err2 := os.RemoveAll(tempFolder); err2 != nil {
   268  				logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2)
   269  			}
   270  		}
   271  	}()
   272  
   273  	if err = hcsshim.ExportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil {
   274  		return
   275  	}
   276  
   277  	archive, err := archive.Tar(tempFolder, archive.Uncompressed)
   278  	if err != nil {
   279  		return
   280  	}
   281  	return ioutils.NewReadCloserWrapper(archive, func() error {
   282  		err := archive.Close()
   283  		d.Put(id)
   284  		if err2 := os.RemoveAll(tempFolder); err2 != nil {
   285  			logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2)
   286  		}
   287  		return err
   288  	}), nil
   289  
   290  }
   291  
   292  func (d *WindowsGraphDriver) Import(id string, layerData archive.ArchiveReader, parentLayerPaths []string) (size int64, err error) {
   293  	layerFs, err := d.Get(id, "")
   294  	if err != nil {
   295  		return
   296  	}
   297  	defer func() {
   298  		if err != nil {
   299  			d.Put(id)
   300  		}
   301  	}()
   302  
   303  	tempFolder := layerFs + "-temp"
   304  	if err = os.MkdirAll(tempFolder, 0755); err != nil {
   305  		logrus.Errorf("Could not create %s %s", tempFolder, err)
   306  		return
   307  	}
   308  	defer func() {
   309  		if err2 := os.RemoveAll(tempFolder); err2 != nil {
   310  			logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2)
   311  		}
   312  	}()
   313  
   314  	start := time.Now().UTC()
   315  	logrus.Debugf("Start untar layer")
   316  	if size, err = chrootarchive.ApplyLayer(tempFolder, layerData); err != nil {
   317  		return
   318  	}
   319  	logrus.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds())
   320  
   321  	if err = hcsshim.ImportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil {
   322  		return
   323  	}
   324  
   325  	return
   326  }