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