github.com/endocode/docker@v1.4.2-0.20160113120958-46eb4700391e/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" 10 "io/ioutil" 11 "os" 12 "path/filepath" 13 "strconv" 14 "strings" 15 "sync" 16 "time" 17 18 "github.com/Sirupsen/logrus" 19 "github.com/docker/docker/daemon/graphdriver" 20 "github.com/docker/docker/pkg/archive" 21 "github.com/docker/docker/pkg/chrootarchive" 22 "github.com/docker/docker/pkg/idtools" 23 "github.com/docker/docker/pkg/ioutils" 24 "github.com/docker/docker/pkg/random" 25 "github.com/microsoft/hcsshim" 26 ) 27 28 // init registers the windows graph drivers to the register. 29 func init() { 30 graphdriver.Register("windowsfilter", InitFilter) 31 graphdriver.Register("windowsdiff", InitDiff) 32 } 33 34 const ( 35 // diffDriver is an hcsshim driver type 36 diffDriver = iota 37 // filterDriver is an hcsshim driver type 38 filterDriver 39 ) 40 41 // Driver represents a windows graph driver. 42 type Driver struct { 43 // info stores the shim driver information 44 info hcsshim.DriverInfo 45 // Mutex protects concurrent modification to active 46 sync.Mutex 47 // active stores references to the activated layers 48 active map[string]int 49 } 50 51 // InitFilter returns a new Windows storage filter driver. 52 func InitFilter(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) { 53 logrus.Debugf("WindowsGraphDriver InitFilter at %s", home) 54 d := &Driver{ 55 info: hcsshim.DriverInfo{ 56 HomeDir: home, 57 Flavour: filterDriver, 58 }, 59 active: make(map[string]int), 60 } 61 return d, nil 62 } 63 64 // InitDiff returns a new Windows differencing disk driver. 65 func InitDiff(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) { 66 logrus.Debugf("WindowsGraphDriver InitDiff at %s", home) 67 d := &Driver{ 68 info: hcsshim.DriverInfo{ 69 HomeDir: home, 70 Flavour: diffDriver, 71 }, 72 active: make(map[string]int), 73 } 74 return d, nil 75 } 76 77 // String returns the string representation of a driver. 78 func (d *Driver) String() string { 79 switch d.info.Flavour { 80 case diffDriver: 81 return "windowsdiff" 82 case filterDriver: 83 return "windowsfilter" 84 default: 85 return "Unknown driver flavour" 86 } 87 } 88 89 // Status returns the status of the driver. 90 func (d *Driver) Status() [][2]string { 91 return [][2]string{ 92 {"Windows", ""}, 93 } 94 } 95 96 // Exists returns true if the given id is registered with this driver. 97 func (d *Driver) Exists(id string) bool { 98 rID, err := d.resolveID(id) 99 if err != nil { 100 return false 101 } 102 result, err := hcsshim.LayerExists(d.info, rID) 103 if err != nil { 104 return false 105 } 106 return result 107 } 108 109 // Create creates a new layer with the given id. 110 func (d *Driver) Create(id, parent, mountLabel string) error { 111 rPId, err := d.resolveID(parent) 112 if err != nil { 113 return err 114 } 115 116 parentChain, err := d.getLayerChain(rPId) 117 if err != nil { 118 return err 119 } 120 121 var layerChain []string 122 123 parentIsInit := strings.HasSuffix(rPId, "-init") 124 125 if !parentIsInit && rPId != "" { 126 parentPath, err := hcsshim.GetLayerMountPath(d.info, rPId) 127 if err != nil { 128 return err 129 } 130 layerChain = []string{parentPath} 131 } 132 133 layerChain = append(layerChain, parentChain...) 134 135 if parentIsInit { 136 if len(layerChain) == 0 { 137 return fmt.Errorf("Cannot create a read/write layer without a parent layer.") 138 } 139 if err := hcsshim.CreateSandboxLayer(d.info, id, layerChain[0], layerChain); err != nil { 140 return err 141 } 142 } else { 143 if err := hcsshim.CreateLayer(d.info, id, rPId); err != nil { 144 return err 145 } 146 } 147 148 if _, err := os.Lstat(d.dir(parent)); err != nil { 149 if err2 := hcsshim.DestroyLayer(d.info, id); err2 != nil { 150 logrus.Warnf("Failed to DestroyLayer %s: %s", id, err2) 151 } 152 return fmt.Errorf("Cannot create layer with missing parent %s: %s", parent, err) 153 } 154 155 if err := d.setLayerChain(id, layerChain); err != nil { 156 if err2 := hcsshim.DestroyLayer(d.info, id); err2 != nil { 157 logrus.Warnf("Failed to DestroyLayer %s: %s", id, err2) 158 } 159 return err 160 } 161 162 return nil 163 } 164 165 // dir returns the absolute path to the layer. 166 func (d *Driver) dir(id string) string { 167 return filepath.Join(d.info.HomeDir, filepath.Base(id)) 168 } 169 170 // Remove unmounts and removes the dir information. 171 func (d *Driver) Remove(id string) error { 172 rID, err := d.resolveID(id) 173 if err != nil { 174 return err 175 } 176 os.RemoveAll(filepath.Join(d.info.HomeDir, "sysfile-backups", rID)) // ok to fail 177 return hcsshim.DestroyLayer(d.info, rID) 178 } 179 180 // Get returns the rootfs path for the id. This will mount the dir at it's given path. 181 func (d *Driver) Get(id, mountLabel string) (string, error) { 182 logrus.Debugf("WindowsGraphDriver Get() id %s mountLabel %s", id, mountLabel) 183 var dir string 184 185 d.Lock() 186 defer d.Unlock() 187 188 rID, err := d.resolveID(id) 189 if err != nil { 190 return "", err 191 } 192 193 // Getting the layer paths must be done outside of the lock. 194 layerChain, err := d.getLayerChain(rID) 195 if err != nil { 196 return "", err 197 } 198 199 if d.active[rID] == 0 { 200 if err := hcsshim.ActivateLayer(d.info, rID); err != nil { 201 return "", err 202 } 203 if err := hcsshim.PrepareLayer(d.info, rID, layerChain); 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 211 mountPath, err := hcsshim.GetLayerMountPath(d.info, rID) 212 if err != nil { 213 if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil { 214 logrus.Warnf("Failed to Deactivate %s: %s", id, err) 215 } 216 return "", err 217 } 218 219 d.active[rID]++ 220 221 // If the layer has a mount path, use that. Otherwise, use the 222 // folder path. 223 if mountPath != "" { 224 dir = mountPath 225 } else { 226 dir = d.dir(id) 227 } 228 229 return dir, nil 230 } 231 232 // Put adds a new layer to the driver. 233 func (d *Driver) Put(id string) error { 234 logrus.Debugf("WindowsGraphDriver Put() id %s", id) 235 236 rID, err := d.resolveID(id) 237 if err != nil { 238 return err 239 } 240 241 d.Lock() 242 defer d.Unlock() 243 244 if d.active[rID] > 1 { 245 d.active[rID]-- 246 } else if d.active[rID] == 1 { 247 if err := hcsshim.UnprepareLayer(d.info, rID); err != nil { 248 return err 249 } 250 if err := hcsshim.DeactivateLayer(d.info, rID); err != nil { 251 return err 252 } 253 delete(d.active, rID) 254 } 255 256 return nil 257 } 258 259 // Cleanup ensures the information the driver stores is properly removed. 260 func (d *Driver) Cleanup() error { 261 return nil 262 } 263 264 // Diff produces an archive of the changes between the specified 265 // layer and its parent layer which may be "". 266 func (d *Driver) Diff(id, parent string) (arch archive.Archive, err error) { 267 rID, err := d.resolveID(id) 268 if err != nil { 269 return 270 } 271 272 // Getting the layer paths must be done outside of the lock. 273 layerChain, err := d.getLayerChain(rID) 274 if err != nil { 275 return 276 } 277 278 d.Lock() 279 280 // To support export, a layer must be activated but not prepared. 281 if d.info.Flavour == filterDriver { 282 if d.active[rID] == 0 { 283 if err = hcsshim.ActivateLayer(d.info, rID); err != nil { 284 d.Unlock() 285 return 286 } 287 defer func() { 288 if err := hcsshim.DeactivateLayer(d.info, rID); err != nil { 289 logrus.Warnf("Failed to Deactivate %s: %s", rID, err) 290 } 291 }() 292 } else { 293 if err = hcsshim.UnprepareLayer(d.info, rID); err != nil { 294 d.Unlock() 295 return 296 } 297 defer func() { 298 if err := hcsshim.PrepareLayer(d.info, rID, layerChain); err != nil { 299 logrus.Warnf("Failed to re-PrepareLayer %s: %s", rID, err) 300 } 301 }() 302 } 303 } 304 305 d.Unlock() 306 307 return d.exportLayer(rID, layerChain) 308 } 309 310 // Changes produces a list of changes between the specified layer 311 // and its parent layer. If parent is "", then all changes will be ADD changes. 312 func (d *Driver) Changes(id, parent string) ([]archive.Change, error) { 313 return nil, fmt.Errorf("The Windows graphdriver does not support Changes()") 314 } 315 316 // ApplyDiff extracts the changeset from the given diff into the 317 // layer with the specified id and parent, returning the size of the 318 // new layer in bytes. 319 func (d *Driver) ApplyDiff(id, parent string, diff archive.Reader) (size int64, err error) { 320 rPId, err := d.resolveID(parent) 321 if err != nil { 322 return 323 } 324 325 if d.info.Flavour == diffDriver { 326 start := time.Now().UTC() 327 logrus.Debugf("WindowsGraphDriver ApplyDiff: Start untar layer") 328 destination := d.dir(id) 329 destination = filepath.Dir(destination) 330 if size, err = chrootarchive.ApplyUncompressedLayer(destination, diff, nil); err != nil { 331 return 332 } 333 logrus.Debugf("WindowsGraphDriver ApplyDiff: Untar time: %vs", time.Now().UTC().Sub(start).Seconds()) 334 335 return 336 } 337 338 parentChain, err := d.getLayerChain(rPId) 339 if err != nil { 340 return 341 } 342 parentPath, err := hcsshim.GetLayerMountPath(d.info, rPId) 343 if err != nil { 344 return 345 } 346 layerChain := []string{parentPath} 347 layerChain = append(layerChain, parentChain...) 348 349 if size, err = d.importLayer(id, diff, layerChain); err != nil { 350 return 351 } 352 353 if err = d.setLayerChain(id, layerChain); err != nil { 354 return 355 } 356 357 return 358 } 359 360 // DiffSize calculates the changes between the specified layer 361 // and its parent and returns the size in bytes of the changes 362 // relative to its base filesystem directory. 363 func (d *Driver) DiffSize(id, parent string) (size int64, err error) { 364 rPId, err := d.resolveID(parent) 365 if err != nil { 366 return 367 } 368 369 changes, err := d.Changes(id, rPId) 370 if err != nil { 371 return 372 } 373 374 layerFs, err := d.Get(id, "") 375 if err != nil { 376 return 377 } 378 defer d.Put(id) 379 380 return archive.ChangesSize(layerFs, changes), nil 381 } 382 383 // CustomImageInfo is the object returned by the driver describing the base 384 // image. 385 type CustomImageInfo struct { 386 ID string 387 Name string 388 Version string 389 Path string 390 Size int64 391 CreatedTime time.Time 392 } 393 394 // GetCustomImageInfos returns the image infos for window specific 395 // base images which should always be present. 396 func (d *Driver) GetCustomImageInfos() ([]CustomImageInfo, error) { 397 strData, err := hcsshim.GetSharedBaseImages() 398 if err != nil { 399 return nil, fmt.Errorf("Failed to restore base images: %s", err) 400 } 401 402 type customImageInfoList struct { 403 Images []CustomImageInfo 404 } 405 406 var infoData customImageInfoList 407 408 if err = json.Unmarshal([]byte(strData), &infoData); err != nil { 409 err = fmt.Errorf("JSON unmarshal returned error=%s", err) 410 logrus.Error(err) 411 return nil, err 412 } 413 414 var images []CustomImageInfo 415 416 for _, imageData := range infoData.Images { 417 folderName := filepath.Base(imageData.Path) 418 419 // Use crypto hash of the foldername to generate a docker style id. 420 h := sha512.Sum384([]byte(folderName)) 421 id := fmt.Sprintf("%x", h[:32]) 422 423 if err := d.Create(id, "", ""); err != nil { 424 return nil, err 425 } 426 // Create the alternate ID file. 427 if err := d.setID(id, folderName); err != nil { 428 return nil, err 429 } 430 431 imageData.ID = id 432 images = append(images, imageData) 433 } 434 435 return images, nil 436 } 437 438 // GetMetadata returns custom driver information. 439 func (d *Driver) GetMetadata(id string) (map[string]string, error) { 440 m := make(map[string]string) 441 m["dir"] = d.dir(id) 442 return m, nil 443 } 444 445 // exportLayer generates an archive from a layer based on the given ID. 446 func (d *Driver) exportLayer(id string, parentLayerPaths []string) (arch archive.Archive, err error) { 447 layerFolder := d.dir(id) 448 449 tempFolder := layerFolder + "-" + strconv.FormatUint(uint64(random.Rand.Uint32()), 10) 450 if err = os.MkdirAll(tempFolder, 0755); err != nil { 451 logrus.Errorf("Could not create %s %s", tempFolder, err) 452 return 453 } 454 defer func() { 455 if err != nil { 456 _, folderName := filepath.Split(tempFolder) 457 if err2 := hcsshim.DestroyLayer(d.info, folderName); err2 != nil { 458 logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2) 459 } 460 } 461 }() 462 463 if err = hcsshim.ExportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil { 464 return 465 } 466 467 archive, err := archive.Tar(tempFolder, archive.Uncompressed) 468 if err != nil { 469 return 470 } 471 return ioutils.NewReadCloserWrapper(archive, func() error { 472 err := archive.Close() 473 d.Put(id) 474 _, folderName := filepath.Split(tempFolder) 475 if err2 := hcsshim.DestroyLayer(d.info, folderName); err2 != nil { 476 logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2) 477 } 478 return err 479 }), nil 480 481 } 482 483 // importLayer adds a new layer to the tag and graph store based on the given data. 484 func (d *Driver) importLayer(id string, layerData archive.Reader, parentLayerPaths []string) (size int64, err error) { 485 layerFolder := d.dir(id) 486 487 tempFolder := layerFolder + "-" + strconv.FormatUint(uint64(random.Rand.Uint32()), 10) 488 if err = os.MkdirAll(tempFolder, 0755); err != nil { 489 logrus.Errorf("Could not create %s %s", tempFolder, err) 490 return 491 } 492 defer func() { 493 _, folderName := filepath.Split(tempFolder) 494 if err2 := hcsshim.DestroyLayer(d.info, folderName); err2 != nil { 495 logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2) 496 } 497 }() 498 499 start := time.Now().UTC() 500 logrus.Debugf("Start untar layer") 501 if size, err = chrootarchive.ApplyLayer(tempFolder, layerData); err != nil { 502 return 503 } 504 err = copySysFiles(tempFolder, filepath.Join(d.info.HomeDir, "sysfile-backups", id)) 505 if err != nil { 506 return 507 } 508 logrus.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds()) 509 510 if err = hcsshim.ImportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil { 511 return 512 } 513 514 return 515 } 516 517 // resolveID computes the layerID information based on the given id. 518 func (d *Driver) resolveID(id string) (string, error) { 519 content, err := ioutil.ReadFile(filepath.Join(d.dir(id), "layerID")) 520 if os.IsNotExist(err) { 521 return id, nil 522 } else if err != nil { 523 return "", err 524 } 525 return string(content), nil 526 } 527 528 // setID stores the layerId in disk. 529 func (d *Driver) setID(id, altID string) error { 530 err := ioutil.WriteFile(filepath.Join(d.dir(id), "layerId"), []byte(altID), 0600) 531 if err != nil { 532 return err 533 } 534 return nil 535 } 536 537 // getLayerChain returns the layer chain information. 538 func (d *Driver) getLayerChain(id string) ([]string, error) { 539 jPath := filepath.Join(d.dir(id), "layerchain.json") 540 content, err := ioutil.ReadFile(jPath) 541 if os.IsNotExist(err) { 542 return nil, nil 543 } else if err != nil { 544 return nil, fmt.Errorf("Unable to read layerchain file - %s", err) 545 } 546 547 var layerChain []string 548 err = json.Unmarshal(content, &layerChain) 549 if err != nil { 550 return nil, fmt.Errorf("Failed to unmarshall layerchain json - %s", err) 551 } 552 553 return layerChain, nil 554 } 555 556 // setLayerChain stores the layer chain information in disk. 557 func (d *Driver) setLayerChain(id string, chain []string) error { 558 content, err := json.Marshal(&chain) 559 if err != nil { 560 return fmt.Errorf("Failed to marshall layerchain json - %s", err) 561 } 562 563 jPath := filepath.Join(d.dir(id), "layerchain.json") 564 err = ioutil.WriteFile(jPath, content, 0600) 565 if err != nil { 566 return fmt.Errorf("Unable to write layerchain file - %s", err) 567 } 568 569 return nil 570 } 571 572 // DiffPath returns a directory that contains files needed to construct layer diff. 573 func (d *Driver) DiffPath(id string) (path string, release func() error, err error) { 574 id, err = d.resolveID(id) 575 if err != nil { 576 return 577 } 578 579 // Getting the layer paths must be done outside of the lock. 580 layerChain, err := d.getLayerChain(id) 581 if err != nil { 582 return 583 } 584 585 layerFolder := d.dir(id) 586 tempFolder := layerFolder + "-" + strconv.FormatUint(uint64(random.Rand.Uint32()), 10) 587 if err = os.MkdirAll(tempFolder, 0755); err != nil { 588 logrus.Errorf("Could not create %s %s", tempFolder, err) 589 return 590 } 591 592 defer func() { 593 if err != nil { 594 _, folderName := filepath.Split(tempFolder) 595 if err2 := hcsshim.DestroyLayer(d.info, folderName); err2 != nil { 596 logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2) 597 } 598 } 599 }() 600 601 if err = hcsshim.ExportLayer(d.info, id, tempFolder, layerChain); err != nil { 602 return 603 } 604 605 err = copySysFiles(filepath.Join(d.info.HomeDir, "sysfile-backups", id), tempFolder) 606 if err != nil { 607 return 608 } 609 610 return tempFolder, func() error { 611 // TODO: activate layers and release here? 612 _, folderName := filepath.Split(tempFolder) 613 return hcsshim.DestroyLayer(d.info, folderName) 614 }, nil 615 } 616 617 var sysFileWhiteList = []string{ 618 "Hives\\*", 619 "Files\\BOOTNXT", 620 "tombstones.txt", 621 } 622 623 // note this only handles files 624 func copySysFiles(src string, dest string) error { 625 if err := os.MkdirAll(dest, 0700); err != nil { 626 return err 627 } 628 return filepath.Walk(src, func(path string, info os.FileInfo, err error) error { 629 rel, err := filepath.Rel(src, path) 630 if err != nil { 631 return err 632 } 633 for _, sysfile := range sysFileWhiteList { 634 if matches, err := filepath.Match(sysfile, rel); err != nil || !matches { 635 continue 636 } 637 638 fi, err := os.Lstat(path) 639 if err != nil { 640 return err 641 } 642 643 if !fi.Mode().IsRegular() { 644 continue 645 } 646 647 targetPath := filepath.Join(dest, rel) 648 if err = os.MkdirAll(filepath.Dir(targetPath), 0700); err != nil { 649 return err 650 } 651 652 in, err := os.Open(path) 653 if err != nil { 654 return err 655 } 656 out, err := os.Create(targetPath) 657 if err != nil { 658 in.Close() 659 return err 660 } 661 _, err = io.Copy(out, in) 662 in.Close() 663 out.Close() 664 if err != nil { 665 return err 666 } 667 } 668 return nil 669 }) 670 }