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 }