github.com/mheon/docker@v0.11.2-0.20150922122814-44f47903a831/daemon/graphdriver/windows/windows.go (about)

     1  //+build windows
     2  
     3  package windows
     4  
     5  import (
     6  	"crypto/sha512"
     7  	"encoding/json"
     8  	"fmt"
     9  	"io/ioutil"
    10  	"os"
    11  	"path/filepath"
    12  	"runtime"
    13  	"strconv"
    14  	"strings"
    15  	"sync"
    16  	"time"
    17  
    18  	"github.com/Sirupsen/logrus"
    19  	"github.com/docker/docker/autogen/dockerversion"
    20  	"github.com/docker/docker/daemon/graphdriver"
    21  	"github.com/docker/docker/image"
    22  	"github.com/docker/docker/pkg/archive"
    23  	"github.com/docker/docker/pkg/chrootarchive"
    24  	"github.com/docker/docker/pkg/ioutils"
    25  	"github.com/docker/docker/pkg/random"
    26  	"github.com/microsoft/hcsshim"
    27  )
    28  
    29  func init() {
    30  	graphdriver.Register("windowsfilter", InitFilter)
    31  	graphdriver.Register("windowsdiff", InitDiff)
    32  }
    33  
    34  const (
    35  	diffDriver = iota
    36  	filterDriver
    37  )
    38  
    39  type Driver struct {
    40  	info       hcsshim.DriverInfo
    41  	sync.Mutex // Protects concurrent modification to active
    42  	active     map[string]int
    43  }
    44  
    45  // New returns a new Windows storage filter driver.
    46  func InitFilter(home string, options []string) (graphdriver.Driver, error) {
    47  	logrus.Debugf("WindowsGraphDriver InitFilter at %s", home)
    48  	d := &Driver{
    49  		info: hcsshim.DriverInfo{
    50  			HomeDir: home,
    51  			Flavour: filterDriver,
    52  		},
    53  		active: make(map[string]int),
    54  	}
    55  	return d, nil
    56  }
    57  
    58  // New returns a new Windows differencing disk driver.
    59  func InitDiff(home string, options []string) (graphdriver.Driver, error) {
    60  	logrus.Debugf("WindowsGraphDriver InitDiff at %s", home)
    61  	d := &Driver{
    62  		info: hcsshim.DriverInfo{
    63  			HomeDir: home,
    64  			Flavour: diffDriver,
    65  		},
    66  		active: make(map[string]int),
    67  	}
    68  	return d, nil
    69  }
    70  
    71  func (d *Driver) String() string {
    72  	switch d.info.Flavour {
    73  	case diffDriver:
    74  		return "windowsdiff"
    75  	case filterDriver:
    76  		return "windowsfilter"
    77  	default:
    78  		return "Unknown driver flavour"
    79  	}
    80  }
    81  
    82  func (d *Driver) Status() [][2]string {
    83  	return [][2]string{
    84  		{"Windows", ""},
    85  	}
    86  }
    87  
    88  // Exists returns true if the given id is registered with
    89  // this driver
    90  func (d *Driver) Exists(id string) bool {
    91  	rId, err := d.resolveId(id)
    92  	if err != nil {
    93  		return false
    94  	}
    95  	result, err := hcsshim.LayerExists(d.info, rId)
    96  	if err != nil {
    97  		return false
    98  	}
    99  	return result
   100  }
   101  
   102  func (d *Driver) Create(id, parent string) error {
   103  	rPId, err := d.resolveId(parent)
   104  	if err != nil {
   105  		return err
   106  	}
   107  
   108  	parentChain, err := d.getLayerChain(rPId)
   109  	if err != nil {
   110  		return err
   111  	}
   112  
   113  	var layerChain []string
   114  
   115  	parentIsInit := strings.HasSuffix(rPId, "-init")
   116  
   117  	if !parentIsInit && rPId != "" {
   118  		parentPath, err := hcsshim.GetLayerMountPath(d.info, rPId)
   119  		if err != nil {
   120  			return err
   121  		}
   122  		layerChain = []string{parentPath}
   123  	}
   124  
   125  	layerChain = append(layerChain, parentChain...)
   126  
   127  	if parentIsInit {
   128  		if len(layerChain) == 0 {
   129  			return fmt.Errorf("Cannot create a read/write layer without a parent layer.")
   130  		}
   131  		if err := hcsshim.CreateSandboxLayer(d.info, id, layerChain[0], layerChain); err != nil {
   132  			return err
   133  		}
   134  	} else {
   135  		if err := hcsshim.CreateLayer(d.info, id, rPId); err != nil {
   136  			return err
   137  		}
   138  	}
   139  
   140  	if _, err := os.Lstat(d.dir(parent)); err != nil {
   141  		if err2 := hcsshim.DestroyLayer(d.info, id); err2 != nil {
   142  			logrus.Warnf("Failed to DestroyLayer %s: %s", id, err2)
   143  		}
   144  		return fmt.Errorf("Cannot create layer with missing parent %s: %s", parent, err)
   145  	}
   146  
   147  	if err := d.setLayerChain(id, layerChain); err != nil {
   148  		if err2 := hcsshim.DestroyLayer(d.info, id); err2 != nil {
   149  			logrus.Warnf("Failed to DestroyLayer %s: %s", id, err2)
   150  		}
   151  		return err
   152  	}
   153  
   154  	return nil
   155  }
   156  
   157  func (d *Driver) dir(id string) string {
   158  	return filepath.Join(d.info.HomeDir, filepath.Base(id))
   159  }
   160  
   161  // Remove unmounts and removes the dir information
   162  func (d *Driver) Remove(id string) error {
   163  	rId, err := d.resolveId(id)
   164  	if err != nil {
   165  		return err
   166  	}
   167  
   168  	return hcsshim.DestroyLayer(d.info, rId)
   169  }
   170  
   171  // Get returns the rootfs path for the id. This will mount the dir at it's given path
   172  func (d *Driver) Get(id, mountLabel string) (string, error) {
   173  	logrus.Debugf("WindowsGraphDriver Get() id %s mountLabel %s", id, mountLabel)
   174  	var dir string
   175  
   176  	d.Lock()
   177  	defer d.Unlock()
   178  
   179  	rId, err := d.resolveId(id)
   180  	if err != nil {
   181  		return "", err
   182  	}
   183  
   184  	// Getting the layer paths must be done outside of the lock.
   185  	layerChain, err := d.getLayerChain(rId)
   186  	if err != nil {
   187  		return "", err
   188  	}
   189  
   190  	if d.active[rId] == 0 {
   191  		if err := hcsshim.ActivateLayer(d.info, rId); err != nil {
   192  			return "", err
   193  		}
   194  		if err := hcsshim.PrepareLayer(d.info, rId, layerChain); err != nil {
   195  			if err2 := hcsshim.DeactivateLayer(d.info, rId); err2 != nil {
   196  				logrus.Warnf("Failed to Deactivate %s: %s", id, err)
   197  			}
   198  			return "", err
   199  		}
   200  	}
   201  
   202  	mountPath, err := hcsshim.GetLayerMountPath(d.info, rId)
   203  	if err != nil {
   204  		if err2 := hcsshim.DeactivateLayer(d.info, rId); err2 != nil {
   205  			logrus.Warnf("Failed to Deactivate %s: %s", id, err)
   206  		}
   207  		return "", err
   208  	}
   209  
   210  	d.active[rId]++
   211  
   212  	// If the layer has a mount path, use that. Otherwise, use the
   213  	// folder path.
   214  	if mountPath != "" {
   215  		dir = mountPath
   216  	} else {
   217  		dir = d.dir(id)
   218  	}
   219  
   220  	return dir, nil
   221  }
   222  
   223  func (d *Driver) Put(id string) error {
   224  	logrus.Debugf("WindowsGraphDriver Put() id %s", id)
   225  
   226  	rId, err := d.resolveId(id)
   227  	if err != nil {
   228  		return err
   229  	}
   230  
   231  	d.Lock()
   232  	defer d.Unlock()
   233  
   234  	if d.active[rId] > 1 {
   235  		d.active[rId]--
   236  	} else if d.active[rId] == 1 {
   237  		if err := hcsshim.UnprepareLayer(d.info, rId); err != nil {
   238  			return err
   239  		}
   240  		if err := hcsshim.DeactivateLayer(d.info, rId); err != nil {
   241  			return err
   242  		}
   243  		delete(d.active, rId)
   244  	}
   245  
   246  	return nil
   247  }
   248  
   249  func (d *Driver) Cleanup() error {
   250  	return nil
   251  }
   252  
   253  // Diff produces an archive of the changes between the specified
   254  // layer and its parent layer which may be "".
   255  func (d *Driver) Diff(id, parent string) (arch archive.Archive, err error) {
   256  	rId, err := d.resolveId(id)
   257  	if err != nil {
   258  		return
   259  	}
   260  
   261  	// Getting the layer paths must be done outside of the lock.
   262  	layerChain, err := d.getLayerChain(rId)
   263  	if err != nil {
   264  		return
   265  	}
   266  
   267  	d.Lock()
   268  
   269  	// To support export, a layer must be activated but not prepared.
   270  	if d.info.Flavour == filterDriver {
   271  		if d.active[rId] == 0 {
   272  			if err = hcsshim.ActivateLayer(d.info, rId); err != nil {
   273  				d.Unlock()
   274  				return
   275  			}
   276  			defer func() {
   277  				if err := hcsshim.DeactivateLayer(d.info, rId); err != nil {
   278  					logrus.Warnf("Failed to Deactivate %s: %s", rId, err)
   279  				}
   280  			}()
   281  		} else {
   282  			if err = hcsshim.UnprepareLayer(d.info, rId); err != nil {
   283  				d.Unlock()
   284  				return
   285  			}
   286  			defer func() {
   287  				if err := hcsshim.PrepareLayer(d.info, rId, layerChain); err != nil {
   288  					logrus.Warnf("Failed to re-PrepareLayer %s: %s", rId, err)
   289  				}
   290  			}()
   291  		}
   292  	}
   293  
   294  	d.Unlock()
   295  
   296  	return d.exportLayer(rId, layerChain)
   297  }
   298  
   299  // Changes produces a list of changes between the specified layer
   300  // and its parent layer. If parent is "", then all changes will be ADD changes.
   301  func (d *Driver) Changes(id, parent string) ([]archive.Change, error) {
   302  	return nil, fmt.Errorf("The Windows graphdriver does not support Changes()")
   303  }
   304  
   305  // ApplyDiff extracts the changeset from the given diff into the
   306  // layer with the specified id and parent, returning the size of the
   307  // new layer in bytes.
   308  func (d *Driver) ApplyDiff(id, parent string, diff archive.Reader) (size int64, err error) {
   309  	rPId, err := d.resolveId(parent)
   310  	if err != nil {
   311  		return
   312  	}
   313  
   314  	if d.info.Flavour == diffDriver {
   315  		start := time.Now().UTC()
   316  		logrus.Debugf("WindowsGraphDriver ApplyDiff: Start untar layer")
   317  		destination := d.dir(id)
   318  		destination = filepath.Dir(destination)
   319  		if size, err = chrootarchive.ApplyUncompressedLayer(destination, diff); err != nil {
   320  			return
   321  		}
   322  		logrus.Debugf("WindowsGraphDriver ApplyDiff: Untar time: %vs", time.Now().UTC().Sub(start).Seconds())
   323  
   324  		return
   325  	}
   326  
   327  	parentChain, err := d.getLayerChain(rPId)
   328  	if err != nil {
   329  		return
   330  	}
   331  	parentPath, err := hcsshim.GetLayerMountPath(d.info, rPId)
   332  	if err != nil {
   333  		return
   334  	}
   335  	layerChain := []string{parentPath}
   336  	layerChain = append(layerChain, parentChain...)
   337  
   338  	if size, err = d.importLayer(id, diff, layerChain); err != nil {
   339  		return
   340  	}
   341  
   342  	if err = d.setLayerChain(id, layerChain); err != nil {
   343  		return
   344  	}
   345  
   346  	return
   347  }
   348  
   349  // DiffSize calculates the changes between the specified layer
   350  // and its parent and returns the size in bytes of the changes
   351  // relative to its base filesystem directory.
   352  func (d *Driver) DiffSize(id, parent string) (size int64, err error) {
   353  	rPId, err := d.resolveId(parent)
   354  	if err != nil {
   355  		return
   356  	}
   357  
   358  	changes, err := d.Changes(id, rPId)
   359  	if err != nil {
   360  		return
   361  	}
   362  
   363  	layerFs, err := d.Get(id, "")
   364  	if err != nil {
   365  		return
   366  	}
   367  	defer d.Put(id)
   368  
   369  	return archive.ChangesSize(layerFs, changes), nil
   370  }
   371  
   372  func (d *Driver) RestoreCustomImages(tagger graphdriver.Tagger, recorder graphdriver.Recorder) (imageIDs []string, err error) {
   373  	strData, err := hcsshim.GetSharedBaseImages()
   374  	if err != nil {
   375  		return nil, fmt.Errorf("Failed to restore base images: %s", err)
   376  	}
   377  
   378  	type customImageInfo struct {
   379  		Name        string
   380  		Version     string
   381  		Path        string
   382  		Size        int64
   383  		CreatedTime time.Time
   384  	}
   385  	type customImageInfoList struct {
   386  		Images []customImageInfo
   387  	}
   388  
   389  	var infoData customImageInfoList
   390  
   391  	if err = json.Unmarshal([]byte(strData), &infoData); err != nil {
   392  		err = fmt.Errorf("JSON unmarshal returned error=%s", err)
   393  		logrus.Error(err)
   394  		return nil, err
   395  	}
   396  
   397  	for _, imageData := range infoData.Images {
   398  		_, folderName := filepath.Split(imageData.Path)
   399  
   400  		// Use crypto hash of the foldername to generate a docker style id.
   401  		h := sha512.Sum384([]byte(folderName))
   402  		id := fmt.Sprintf("%x", h[:32])
   403  
   404  		if !recorder.Exists(id) {
   405  			// Register the image.
   406  			img := &image.Image{
   407  				ID:            id,
   408  				Created:       imageData.CreatedTime,
   409  				DockerVersion: dockerversion.VERSION,
   410  				Architecture:  runtime.GOARCH,
   411  				OS:            runtime.GOOS,
   412  				Size:          imageData.Size,
   413  			}
   414  
   415  			if err := recorder.Register(img, nil); err != nil {
   416  				return nil, err
   417  			}
   418  
   419  			// Create tags for the new image.
   420  			if err := tagger.Tag(strings.ToLower(imageData.Name), imageData.Version, img.ID, true); err != nil {
   421  				return nil, err
   422  			}
   423  
   424  			// Create the alternate ID file.
   425  			if err := d.setId(img.ID, folderName); err != nil {
   426  				return nil, err
   427  			}
   428  
   429  			imageIDs = append(imageIDs, img.ID)
   430  		}
   431  	}
   432  
   433  	return imageIDs, nil
   434  }
   435  
   436  func (d *Driver) GetMetadata(id string) (map[string]string, error) {
   437  	m := make(map[string]string)
   438  	m["dir"] = d.dir(id)
   439  	return m, nil
   440  }
   441  
   442  func (d *Driver) exportLayer(id string, parentLayerPaths []string) (arch archive.Archive, err error) {
   443  	layerFolder := d.dir(id)
   444  
   445  	tempFolder := layerFolder + "-" + strconv.FormatUint(uint64(random.Rand.Uint32()), 10)
   446  	if err = os.MkdirAll(tempFolder, 0755); err != nil {
   447  		logrus.Errorf("Could not create %s %s", tempFolder, err)
   448  		return
   449  	}
   450  	defer func() {
   451  		if err != nil {
   452  			_, folderName := filepath.Split(tempFolder)
   453  			if err2 := hcsshim.DestroyLayer(d.info, folderName); err2 != nil {
   454  				logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2)
   455  			}
   456  		}
   457  	}()
   458  
   459  	if err = hcsshim.ExportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil {
   460  		return
   461  	}
   462  
   463  	archive, err := archive.Tar(tempFolder, archive.Uncompressed)
   464  	if err != nil {
   465  		return
   466  	}
   467  	return ioutils.NewReadCloserWrapper(archive, func() error {
   468  		err := archive.Close()
   469  		d.Put(id)
   470  		_, folderName := filepath.Split(tempFolder)
   471  		if err2 := hcsshim.DestroyLayer(d.info, folderName); err2 != nil {
   472  			logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2)
   473  		}
   474  		return err
   475  	}), nil
   476  
   477  }
   478  
   479  func (d *Driver) importLayer(id string, layerData archive.Reader, parentLayerPaths []string) (size int64, err error) {
   480  	layerFolder := d.dir(id)
   481  
   482  	tempFolder := layerFolder + "-" + strconv.FormatUint(uint64(random.Rand.Uint32()), 10)
   483  	if err = os.MkdirAll(tempFolder, 0755); err != nil {
   484  		logrus.Errorf("Could not create %s %s", tempFolder, err)
   485  		return
   486  	}
   487  	defer func() {
   488  		_, folderName := filepath.Split(tempFolder)
   489  		if err2 := hcsshim.DestroyLayer(d.info, folderName); err2 != nil {
   490  			logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2)
   491  		}
   492  	}()
   493  
   494  	start := time.Now().UTC()
   495  	logrus.Debugf("Start untar layer")
   496  	if size, err = chrootarchive.ApplyLayer(tempFolder, layerData); err != nil {
   497  		return
   498  	}
   499  	logrus.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds())
   500  
   501  	if err = hcsshim.ImportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil {
   502  		return
   503  	}
   504  
   505  	return
   506  }
   507  
   508  func (d *Driver) resolveId(id string) (string, error) {
   509  	content, err := ioutil.ReadFile(filepath.Join(d.dir(id), "layerId"))
   510  	if os.IsNotExist(err) {
   511  		return id, nil
   512  	} else if err != nil {
   513  		return "", err
   514  	}
   515  	return string(content), nil
   516  }
   517  
   518  func (d *Driver) setId(id, altId string) error {
   519  	err := ioutil.WriteFile(filepath.Join(d.dir(id), "layerId"), []byte(altId), 0600)
   520  	if err != nil {
   521  		return err
   522  	}
   523  	return nil
   524  }
   525  
   526  func (d *Driver) getLayerChain(id string) ([]string, error) {
   527  	jPath := filepath.Join(d.dir(id), "layerchain.json")
   528  	content, err := ioutil.ReadFile(jPath)
   529  	if os.IsNotExist(err) {
   530  		return nil, nil
   531  	} else if err != nil {
   532  		return nil, fmt.Errorf("Unable to read layerchain file - %s", err)
   533  	}
   534  
   535  	var layerChain []string
   536  	err = json.Unmarshal(content, &layerChain)
   537  	if err != nil {
   538  		return nil, fmt.Errorf("Failed to unmarshall layerchain json - %s", err)
   539  	}
   540  
   541  	return layerChain, nil
   542  }
   543  
   544  func (d *Driver) setLayerChain(id string, chain []string) error {
   545  	content, err := json.Marshal(&chain)
   546  	if err != nil {
   547  		return fmt.Errorf("Failed to marshall layerchain json - %s", err)
   548  	}
   549  
   550  	jPath := filepath.Join(d.dir(id), "layerchain.json")
   551  	err = ioutil.WriteFile(jPath, content, 0600)
   552  	if err != nil {
   553  		return fmt.Errorf("Unable to write layerchain file - %s", err)
   554  	}
   555  
   556  	return nil
   557  }