github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/worker/storageprovisioner/filesystems.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package storageprovisioner 5 6 import ( 7 "path/filepath" 8 9 "github.com/juju/errors" 10 "github.com/juju/names" 11 12 "github.com/juju/juju/apiserver/params" 13 "github.com/juju/juju/instance" 14 "github.com/juju/juju/storage" 15 ) 16 17 // filesystemsChanged is called when the lifecycle states of the filesystems 18 // with the provided IDs have been seen to have changed. 19 func filesystemsChanged(ctx *context, changes []string) error { 20 tags := make([]names.Tag, len(changes)) 21 for i, change := range changes { 22 tags[i] = names.NewFilesystemTag(change) 23 } 24 alive, dying, dead, err := storageEntityLife(ctx, tags) 25 if err != nil { 26 return errors.Trace(err) 27 } 28 logger.Debugf("filesystems alive: %v, dying: %v, dead: %v", alive, dying, dead) 29 if len(alive)+len(dying)+len(dead) == 0 { 30 return nil 31 } 32 33 // Get filesystem information for filesystems, so we can provision, 34 // deprovision, attach and detach. 35 filesystemTags := make([]names.FilesystemTag, 0, len(alive)+len(dying)+len(dead)) 36 for _, tag := range alive { 37 filesystemTags = append(filesystemTags, tag.(names.FilesystemTag)) 38 } 39 for _, tag := range dying { 40 filesystemTags = append(filesystemTags, tag.(names.FilesystemTag)) 41 } 42 for _, tag := range dead { 43 filesystemTags = append(filesystemTags, tag.(names.FilesystemTag)) 44 } 45 filesystemResults, err := ctx.filesystemAccessor.Filesystems(filesystemTags) 46 if err != nil { 47 return errors.Annotatef(err, "getting filesystem information") 48 } 49 50 aliveFilesystemTags := filesystemTags[:len(alive)] 51 dyingFilesystemTags := filesystemTags[len(alive) : len(alive)+len(dying)] 52 deadFilesystemTags := filesystemTags[len(alive)+len(dying):] 53 aliveFilesystemResults := filesystemResults[:len(alive)] 54 dyingFilesystemResults := filesystemResults[len(alive) : len(alive)+len(dying)] 55 deadFilesystemResults := filesystemResults[len(alive)+len(dying):] 56 57 if err := processDeadFilesystems(ctx, deadFilesystemTags, deadFilesystemResults); err != nil { 58 return errors.Annotate(err, "deprovisioning filesystems") 59 } 60 if err := processDyingFilesystems(ctx, dyingFilesystemTags, dyingFilesystemResults); err != nil { 61 return errors.Annotate(err, "processing dying filesystems") 62 } 63 if err := processAliveFilesystems(ctx, aliveFilesystemTags, aliveFilesystemResults); err != nil { 64 return errors.Annotate(err, "provisioning filesystems") 65 } 66 return nil 67 } 68 69 // filesystemAttachmentsChanged is called when the lifecycle states of the filesystem 70 // attachments with the provided IDs have been seen to have changed. 71 func filesystemAttachmentsChanged(ctx *context, ids []params.MachineStorageId) error { 72 alive, dying, dead, err := attachmentLife(ctx, ids) 73 if err != nil { 74 return errors.Trace(err) 75 } 76 logger.Debugf("filesystem attachment alive: %v, dying: %v, dead: %v", alive, dying, dead) 77 if len(dead) != 0 { 78 // We should not see dead filesystem attachments; 79 // attachments go directly from Dying to removed. 80 logger.Debugf("unexpected dead filesystem attachments: %v", dead) 81 } 82 if len(alive)+len(dying) == 0 { 83 return nil 84 } 85 86 // Get filesystem information for alive and dying filesystem attachments, so 87 // we can attach/detach. 88 ids = append(alive, dying...) 89 filesystemAttachmentResults, err := ctx.filesystemAccessor.FilesystemAttachments(ids) 90 if err != nil { 91 return errors.Annotatef(err, "getting filesystem attachment information") 92 } 93 94 // Deprovision Dying filesystem attachments. 95 dyingFilesystemAttachmentResults := filesystemAttachmentResults[len(alive):] 96 if err := processDyingFilesystemAttachments(ctx, dying, dyingFilesystemAttachmentResults); err != nil { 97 return errors.Annotate(err, "destroying filesystem attachments") 98 } 99 100 // Provision Alive filesystem attachments. 101 aliveFilesystemAttachmentResults := filesystemAttachmentResults[:len(alive)] 102 if err := processAliveFilesystemAttachments(ctx, alive, aliveFilesystemAttachmentResults); err != nil { 103 return errors.Annotate(err, "creating filesystem attachments") 104 } 105 106 return nil 107 } 108 109 // processDyingFilesystems processes the FilesystemResults for Dying filesystems, 110 // removing them from provisioning-pending as necessary, and storing the current 111 // filesystem info for provisioned filesystems so that attachments may be destroyed. 112 func processDyingFilesystems(ctx *context, tags []names.FilesystemTag, filesystemResults []params.FilesystemResult) error { 113 for _, tag := range tags { 114 delete(ctx.pendingFilesystems, tag) 115 } 116 for i, result := range filesystemResults { 117 tag := tags[i] 118 if result.Error == nil { 119 filesystem, err := filesystemFromParams(result.Result) 120 if err != nil { 121 return errors.Annotate(err, "getting filesystem info") 122 } 123 ctx.filesystems[tag] = filesystem 124 } else if !params.IsCodeNotProvisioned(result.Error) { 125 return errors.Annotatef(result.Error, "getting information for filesystem %s", tag.Id()) 126 } 127 } 128 return nil 129 } 130 131 // processDeadFilesystems processes the FilesystemResults for Dead filesystems, 132 // deprovisioning filesystems and removing from state as necessary. 133 func processDeadFilesystems(ctx *context, tags []names.FilesystemTag, filesystemResults []params.FilesystemResult) error { 134 for _, tag := range tags { 135 delete(ctx.pendingFilesystems, tag) 136 } 137 var destroy []names.FilesystemTag 138 var remove []names.Tag 139 for i, result := range filesystemResults { 140 tag := tags[i] 141 if result.Error == nil { 142 logger.Debugf("filesystem %s is provisioned, queuing for deprovisioning", tag.Id()) 143 filesystem, err := filesystemFromParams(result.Result) 144 if err != nil { 145 return errors.Annotate(err, "getting filesystem info") 146 } 147 ctx.filesystems[tag] = filesystem 148 destroy = append(destroy, tag) 149 continue 150 } 151 if params.IsCodeNotProvisioned(result.Error) { 152 logger.Debugf("filesystem %s is not provisioned, queuing for removal", tag.Id()) 153 remove = append(remove, tag) 154 continue 155 } 156 return errors.Annotatef(result.Error, "getting filesystem information for filesystem %s", tag.Id()) 157 } 158 if len(destroy)+len(remove) == 0 { 159 return nil 160 } 161 if len(destroy) > 0 { 162 errorResults, err := destroyFilesystems(ctx, destroy) 163 if err != nil { 164 return errors.Annotate(err, "destroying filesystems") 165 } 166 for i, tag := range destroy { 167 if err := errorResults[i]; err != nil { 168 return errors.Annotatef(err, "destroying %s", names.ReadableString(tag)) 169 } 170 remove = append(remove, tag) 171 } 172 } 173 if err := removeEntities(ctx, remove); err != nil { 174 return errors.Annotate(err, "removing filesystems from state") 175 } 176 return nil 177 } 178 179 // processDyingFilesystemAttachments processes the FilesystemAttachmentResults for 180 // Dying filesystem attachments, detaching filesystems and updating state as necessary. 181 func processDyingFilesystemAttachments( 182 ctx *context, 183 ids []params.MachineStorageId, 184 filesystemAttachmentResults []params.FilesystemAttachmentResult, 185 ) error { 186 if len(ids) == 0 { 187 return nil 188 } 189 for _, id := range ids { 190 delete(ctx.pendingFilesystemAttachments, id) 191 } 192 detach := make([]params.MachineStorageId, 0, len(ids)) 193 remove := make([]params.MachineStorageId, 0, len(ids)) 194 for i, result := range filesystemAttachmentResults { 195 id := ids[i] 196 if result.Error == nil { 197 detach = append(detach, id) 198 continue 199 } 200 if params.IsCodeNotProvisioned(result.Error) { 201 remove = append(remove, id) 202 continue 203 } 204 return errors.Annotatef(result.Error, "getting information for filesystem attachment %v", id) 205 } 206 if len(detach) > 0 { 207 attachmentParams, err := filesystemAttachmentParams(ctx, detach) 208 if err != nil { 209 return errors.Trace(err) 210 } 211 for i, params := range attachmentParams { 212 ctx.pendingDyingFilesystemAttachments[detach[i]] = params 213 } 214 } 215 if len(remove) > 0 { 216 if err := removeAttachments(ctx, remove); err != nil { 217 return errors.Annotate(err, "removing attachments from state") 218 } 219 } 220 return nil 221 } 222 223 // processAliveFilesystems processes the FilesystemResults for Alive filesystems, 224 // provisioning filesystems and setting the info in state as necessary. 225 func processAliveFilesystems(ctx *context, tags []names.FilesystemTag, filesystemResults []params.FilesystemResult) error { 226 // Filter out the already-provisioned filesystems. 227 pending := make([]names.FilesystemTag, 0, len(tags)) 228 for i, result := range filesystemResults { 229 tag := tags[i] 230 if result.Error == nil { 231 // Filesystem is already provisioned: skip. 232 logger.Debugf("filesystem %q is already provisioned, nothing to do", tag.Id()) 233 filesystem, err := filesystemFromParams(result.Result) 234 if err != nil { 235 return errors.Annotate(err, "getting filesystem info") 236 } 237 ctx.filesystems[tag] = filesystem 238 if filesystem.Volume != (names.VolumeTag{}) { 239 // Ensure that volume-backed filesystems' block 240 // devices are present even after creating the 241 // filesystem, so that attachments can be made. 242 maybeAddPendingVolumeBlockDevice(ctx, filesystem.Volume) 243 } 244 continue 245 } 246 if !params.IsCodeNotProvisioned(result.Error) { 247 return errors.Annotatef( 248 result.Error, "getting filesystem information for filesystem %q", tag.Id(), 249 ) 250 } 251 // The filesystem has not yet been provisioned, so record its tag 252 // to enquire about parameters below. 253 pending = append(pending, tag) 254 } 255 if len(pending) == 0 { 256 return nil 257 } 258 paramsResults, err := ctx.filesystemAccessor.FilesystemParams(pending) 259 if err != nil { 260 return errors.Annotate(err, "getting filesystem params") 261 } 262 for i, result := range paramsResults { 263 if result.Error != nil { 264 return errors.Annotate(result.Error, "getting filesystem parameters") 265 } 266 params, err := filesystemParamsFromParams(result.Result) 267 if err != nil { 268 return errors.Annotate(err, "getting filesystem parameters") 269 } 270 ctx.pendingFilesystems[pending[i]] = params 271 if params.Volume != (names.VolumeTag{}) { 272 // The filesystem is volume-backed: we must watch for 273 // the corresponding block device. This will trigger a 274 // one-time (for the volume) forced update of block 275 // devices. If the block device is not immediately 276 // available, then we rely on the watcher. The forced 277 // update is necessary in case the block device was 278 // added to state already, and we didn't observe it. 279 maybeAddPendingVolumeBlockDevice(ctx, params.Volume) 280 } 281 } 282 return nil 283 } 284 285 func maybeAddPendingVolumeBlockDevice(ctx *context, v names.VolumeTag) { 286 if _, ok := ctx.volumeBlockDevices[v]; !ok { 287 ctx.pendingVolumeBlockDevices.Add(v) 288 } 289 } 290 291 // processPendingFilesystems creates as many of the pending filesystems 292 // as possible, first ensuring that their prerequisites have been met. 293 func processPendingFilesystems(ctx *context) error { 294 if len(ctx.pendingFilesystems) == 0 { 295 logger.Tracef("no pending filesystems") 296 return nil 297 } 298 ready := make([]storage.FilesystemParams, 0, len(ctx.pendingFilesystems)) 299 for tag, filesystemParams := range ctx.pendingFilesystems { 300 if filesystemParams.Volume != (names.VolumeTag{}) { 301 // The filesystem is backed by a volume; ensure that 302 // the volume is attached by virtue of there being a 303 // matching block device on the machine. 304 if _, ok := ctx.volumeBlockDevices[filesystemParams.Volume]; !ok { 305 logger.Debugf( 306 "filesystem %v backing-volume %v is not attached yet", 307 filesystemParams.Tag.Id(), 308 filesystemParams.Volume.Id(), 309 ) 310 continue 311 } 312 } 313 ready = append(ready, filesystemParams) 314 delete(ctx.pendingFilesystems, tag) 315 } 316 if len(ready) == 0 { 317 return nil 318 } 319 filesystems, err := createFilesystems(ctx, ready) 320 if err != nil { 321 return errors.Annotate(err, "creating filesystems") 322 } 323 if err := setFilesystemInfo(ctx, filesystems); err != nil { 324 return errors.Trace(err) 325 } 326 return nil 327 } 328 329 func setFilesystemInfo(ctx *context, filesystems []storage.Filesystem) error { 330 if len(filesystems) == 0 { 331 return nil 332 } 333 // TODO(axw) we need to be able to list filesystems in the provider, 334 // by environment, so that we can "harvest" them if they're 335 // unknown. This will take care of killing filesystems that we fail 336 // to record in state. 337 errorResults, err := ctx.filesystemAccessor.SetFilesystemInfo( 338 filesystemsFromStorage(filesystems), 339 ) 340 if err != nil { 341 return errors.Annotate(err, "publishing filesystems to state") 342 } 343 for i, result := range errorResults { 344 if result.Error != nil { 345 return errors.Annotatef( 346 result.Error, "publishing filesystem %s to state", 347 filesystems[i].Tag.Id(), 348 ) 349 } 350 ctx.filesystems[filesystems[i].Tag] = filesystems[i] 351 } 352 return nil 353 } 354 355 // processAliveFilesystemAttachments processes the FilesystemAttachmentResults 356 // for Alive filesystem attachments, attaching filesystems and setting the info 357 // in state as necessary. 358 func processAliveFilesystemAttachments( 359 ctx *context, 360 ids []params.MachineStorageId, 361 filesystemAttachmentResults []params.FilesystemAttachmentResult, 362 ) error { 363 // Filter out the already-attached. 364 pending := make([]params.MachineStorageId, 0, len(ids)) 365 for i, result := range filesystemAttachmentResults { 366 if result.Error == nil { 367 delete(ctx.pendingFilesystemAttachments, ids[i]) 368 // Filesystem attachment is already provisioned: if we 369 // didn't (re)attach in this session, then we must do 370 // so now. 371 action := "nothing to do" 372 if _, ok := ctx.filesystemAttachments[ids[i]]; !ok { 373 // Not yet (re)attached in this session. 374 pending = append(pending, ids[i]) 375 action = "will reattach" 376 } 377 logger.Debugf( 378 "%s is already attached to %s, %s", 379 ids[i].AttachmentTag, ids[i].MachineTag, action, 380 ) 381 continue 382 } 383 if !params.IsCodeNotProvisioned(result.Error) { 384 return errors.Annotatef( 385 result.Error, "getting information for attachment %v", ids[i], 386 ) 387 } 388 // The filesystem has not yet been attached, so 389 // record its tag to enquire about parameters below. 390 pending = append(pending, ids[i]) 391 } 392 if len(pending) == 0 { 393 return nil 394 } 395 params, err := filesystemAttachmentParams(ctx, pending) 396 if err != nil { 397 return errors.Trace(err) 398 } 399 for i, params := range params { 400 if params.InstanceId == "" { 401 watchMachine(ctx, params.Machine) 402 } 403 ctx.pendingFilesystemAttachments[pending[i]] = params 404 } 405 return nil 406 } 407 408 // filesystemAttachmentParams obtains the specified attachments' parameters. 409 func filesystemAttachmentParams( 410 ctx *context, ids []params.MachineStorageId, 411 ) ([]storage.FilesystemAttachmentParams, error) { 412 paramsResults, err := ctx.filesystemAccessor.FilesystemAttachmentParams(ids) 413 if err != nil { 414 return nil, errors.Annotate(err, "getting filesystem attachment params") 415 } 416 attachmentParams := make([]storage.FilesystemAttachmentParams, len(ids)) 417 for i, result := range paramsResults { 418 if result.Error != nil { 419 return nil, errors.Annotate(result.Error, "getting filesystem attachment parameters") 420 } 421 params, err := filesystemAttachmentParamsFromParams(result.Result) 422 if err != nil { 423 return nil, errors.Annotate(err, "getting filesystem attachment parameters") 424 } 425 attachmentParams[i] = params 426 } 427 return attachmentParams, nil 428 } 429 430 func processPendingFilesystemAttachments(ctx *context) error { 431 if len(ctx.pendingFilesystemAttachments) == 0 { 432 logger.Tracef("no pending filesystem attachments") 433 return nil 434 } 435 ready := make([]storage.FilesystemAttachmentParams, 0, len(ctx.pendingFilesystemAttachments)) 436 for id, params := range ctx.pendingFilesystemAttachments { 437 filesystem, ok := ctx.filesystems[params.Filesystem] 438 if !ok { 439 logger.Debugf("filesystem %v has not been provisioned yet", params.Filesystem.Id()) 440 continue 441 } 442 if filesystem.Volume != (names.VolumeTag{}) { 443 // The filesystem is volume-backed: if the filesystem 444 // was created in another session, then the block device 445 // may not have been seen yet. We must wait for the block 446 // device watcher to trigger. 447 if _, ok := ctx.volumeBlockDevices[filesystem.Volume]; !ok { 448 logger.Debugf( 449 "filesystem %v backing-volume %v is not attached yet", 450 filesystem.Tag.Id(), 451 filesystem.Volume.Id(), 452 ) 453 continue 454 } 455 } 456 if params.InstanceId == "" { 457 logger.Debugf("machine %v has not been provisioned yet", params.Machine.Id()) 458 continue 459 } 460 if params.Path == "" { 461 params.Path = filepath.Join(ctx.storageDir, params.Filesystem.Id()) 462 } 463 params.FilesystemId = filesystem.FilesystemId 464 ready = append(ready, params) 465 delete(ctx.pendingFilesystemAttachments, id) 466 } 467 if len(ready) == 0 { 468 return nil 469 } 470 filesystemAttachments, err := createFilesystemAttachments(ctx, ready) 471 if err != nil { 472 return errors.Annotate(err, "creating filesystem attachments") 473 } 474 if err := setFilesystemAttachmentInfo(ctx, filesystemAttachments); err != nil { 475 return errors.Trace(err) 476 } 477 return nil 478 } 479 480 func processPendingDyingFilesystemAttachments(ctx *context) error { 481 if len(ctx.pendingDyingFilesystemAttachments) == 0 { 482 logger.Tracef("no pending, dying filesystem attachments") 483 return nil 484 } 485 var detach []storage.FilesystemAttachmentParams 486 var remove []params.MachineStorageId 487 for id, params := range ctx.pendingDyingFilesystemAttachments { 488 if _, ok := ctx.filesystems[params.Filesystem]; !ok { 489 // Wait until the filesystem info is known. 490 continue 491 } 492 delete(ctx.pendingDyingFilesystemAttachments, id) 493 detach = append(detach, params) 494 remove = append(remove, id) 495 } 496 if len(detach) == 0 { 497 return nil 498 } 499 if err := detachFilesystems(ctx, detach); err != nil { 500 return errors.Annotate(err, "detaching filesystems") 501 } 502 if err := removeAttachments(ctx, remove); err != nil { 503 return errors.Annotate(err, "removing attachments from state") 504 } 505 return nil 506 } 507 508 func setFilesystemAttachmentInfo(ctx *context, filesystemAttachments []storage.FilesystemAttachment) error { 509 if len(filesystemAttachments) == 0 { 510 return nil 511 } 512 // TODO(axw) we need to be able to list filesystem attachments in the 513 // provider, by environment, so that we can "harvest" them if they're 514 // unknown. This will take care of killing filesystems that we fail to 515 // record in state. 516 errorResults, err := ctx.filesystemAccessor.SetFilesystemAttachmentInfo( 517 filesystemAttachmentsFromStorage(filesystemAttachments), 518 ) 519 if err != nil { 520 return errors.Annotate(err, "publishing filesystems to state") 521 } 522 for i, result := range errorResults { 523 if result.Error != nil { 524 return errors.Annotatef( 525 result.Error, "publishing attachment of %s to %s to state", 526 names.ReadableString(filesystemAttachments[i].Filesystem), 527 names.ReadableString(filesystemAttachments[i].Machine), 528 ) 529 } 530 // Record the filesystem attachment in the context. 531 ctx.filesystemAttachments[params.MachineStorageId{ 532 MachineTag: filesystemAttachments[i].Machine.String(), 533 AttachmentTag: filesystemAttachments[i].Filesystem.String(), 534 }] = filesystemAttachments[i] 535 } 536 return nil 537 } 538 539 // createFilesystems creates filesystems with the specified parameters. 540 func createFilesystems(ctx *context, params []storage.FilesystemParams) ([]storage.Filesystem, error) { 541 // TODO(axw) later we may have multiple instantiations (sources) 542 // for a storage provider, e.g. multiple Ceph installations. For 543 // now we assume a single source for each provider type, with no 544 // configuration. 545 546 // Create filesystem sources. 547 filesystemSources := make(map[string]storage.FilesystemSource) 548 for _, params := range params { 549 sourceName := string(params.Provider) 550 if _, ok := filesystemSources[sourceName]; ok { 551 continue 552 } 553 if params.Volume != (names.VolumeTag{}) { 554 filesystemSources[sourceName] = ctx.managedFilesystemSource 555 continue 556 } 557 filesystemSource, err := filesystemSource( 558 ctx.environConfig, ctx.storageDir, sourceName, params.Provider, 559 ) 560 if err != nil { 561 return nil, errors.Annotate(err, "getting filesystem source") 562 } 563 filesystemSources[sourceName] = filesystemSource 564 } 565 566 // Validate and gather filesystem parameters. 567 paramsBySource := make(map[string][]storage.FilesystemParams) 568 for _, params := range params { 569 sourceName := string(params.Provider) 570 filesystemSource := filesystemSources[sourceName] 571 err := filesystemSource.ValidateFilesystemParams(params) 572 if err != nil { 573 // TODO(axw) we should set an error status for params.Tag 574 // here, and we should retry periodically. 575 logger.Errorf("ignoring invalid filesystem: %v", err) 576 continue 577 } 578 paramsBySource[sourceName] = append(paramsBySource[sourceName], params) 579 } 580 581 var allFilesystems []storage.Filesystem 582 for sourceName, params := range paramsBySource { 583 logger.Debugf("creating filesystems: %v", params) 584 filesystemSource := filesystemSources[sourceName] 585 filesystems, err := filesystemSource.CreateFilesystems(params) 586 if err != nil { 587 return nil, errors.Annotatef(err, "creating filesystems from source %q", sourceName) 588 } 589 allFilesystems = append(allFilesystems, filesystems...) 590 } 591 return allFilesystems, nil 592 } 593 594 // createFilesystemAttachments creates filesystem attachments with the specified parameters. 595 func createFilesystemAttachments( 596 ctx *context, 597 params []storage.FilesystemAttachmentParams, 598 ) ([]storage.FilesystemAttachment, error) { 599 paramsBySource, filesystemSources, err := filesystemAttachmentParamsBySource(ctx, params) 600 if err != nil { 601 return nil, errors.Trace(err) 602 } 603 var allFilesystemAttachments []storage.FilesystemAttachment 604 for sourceName, params := range paramsBySource { 605 logger.Debugf("attaching filesystems: %v", params) 606 filesystemSource := filesystemSources[sourceName] 607 filesystemAttachments, err := filesystemSource.AttachFilesystems(params) 608 if err != nil { 609 return nil, errors.Annotatef(err, "attaching filesystems from source %q", sourceName) 610 } 611 allFilesystemAttachments = append(allFilesystemAttachments, filesystemAttachments...) 612 } 613 return allFilesystemAttachments, nil 614 } 615 616 func destroyFilesystems(ctx *context, tags []names.FilesystemTag) ([]error, error) { 617 // TODO(axw) add storage.FilesystemSource.DestroyFilesystems 618 return make([]error, len(tags)), nil 619 } 620 621 func detachFilesystems(ctx *context, attachments []storage.FilesystemAttachmentParams) error { 622 paramsBySource, filesystemSources, err := filesystemAttachmentParamsBySource(ctx, attachments) 623 if err != nil { 624 return errors.Trace(err) 625 } 626 for sourceName, params := range paramsBySource { 627 logger.Debugf("detaching filesystems: %v", params) 628 filesystemSource := filesystemSources[sourceName] 629 if err := filesystemSource.DetachFilesystems(params); err != nil { 630 return errors.Annotatef(err, "detaching filesystems from source %q", sourceName) 631 } 632 } 633 return nil 634 } 635 636 func filesystemAttachmentParamsBySource( 637 ctx *context, params []storage.FilesystemAttachmentParams, 638 ) (map[string][]storage.FilesystemAttachmentParams, map[string]storage.FilesystemSource, error) { 639 // TODO(axw) later we may have multiple instantiations (sources) 640 // for a storage provider, e.g. multiple Ceph installations. For 641 // now we assume a single source for each provider type, with no 642 // configuration. 643 filesystemSources := make(map[string]storage.FilesystemSource) 644 paramsBySource := make(map[string][]storage.FilesystemAttachmentParams) 645 for _, params := range params { 646 sourceName := string(params.Provider) 647 paramsBySource[sourceName] = append(paramsBySource[sourceName], params) 648 if _, ok := filesystemSources[sourceName]; ok { 649 continue 650 } 651 filesystem := ctx.filesystems[params.Filesystem] 652 if filesystem.Volume != (names.VolumeTag{}) { 653 filesystemSources[sourceName] = ctx.managedFilesystemSource 654 continue 655 } 656 filesystemSource, err := filesystemSource( 657 ctx.environConfig, ctx.storageDir, sourceName, params.Provider, 658 ) 659 if err != nil { 660 return nil, nil, errors.Annotate(err, "getting filesystem source") 661 } 662 filesystemSources[sourceName] = filesystemSource 663 } 664 return paramsBySource, filesystemSources, nil 665 } 666 667 func filesystemsFromStorage(in []storage.Filesystem) []params.Filesystem { 668 out := make([]params.Filesystem, len(in)) 669 for i, f := range in { 670 paramsFilesystem := params.Filesystem{ 671 f.Tag.String(), 672 "", 673 params.FilesystemInfo{ 674 f.FilesystemId, 675 f.Size, 676 }, 677 } 678 if f.Volume != (names.VolumeTag{}) { 679 paramsFilesystem.VolumeTag = f.Volume.String() 680 } 681 out[i] = paramsFilesystem 682 } 683 return out 684 } 685 686 func filesystemAttachmentsFromStorage(in []storage.FilesystemAttachment) []params.FilesystemAttachment { 687 out := make([]params.FilesystemAttachment, len(in)) 688 for i, f := range in { 689 out[i] = params.FilesystemAttachment{ 690 f.Filesystem.String(), 691 f.Machine.String(), 692 params.FilesystemAttachmentInfo{ 693 f.Path, 694 f.ReadOnly, 695 }, 696 } 697 } 698 return out 699 } 700 701 func filesystemFromParams(in params.Filesystem) (storage.Filesystem, error) { 702 filesystemTag, err := names.ParseFilesystemTag(in.FilesystemTag) 703 if err != nil { 704 return storage.Filesystem{}, errors.Trace(err) 705 } 706 var volumeTag names.VolumeTag 707 if in.VolumeTag != "" { 708 volumeTag, err = names.ParseVolumeTag(in.VolumeTag) 709 if err != nil { 710 return storage.Filesystem{}, errors.Trace(err) 711 } 712 } 713 return storage.Filesystem{ 714 filesystemTag, 715 volumeTag, 716 storage.FilesystemInfo{ 717 in.Info.FilesystemId, 718 in.Info.Size, 719 }, 720 }, nil 721 } 722 723 func filesystemAttachmentFromParams(in params.FilesystemAttachment) (storage.FilesystemAttachment, error) { 724 filesystemTag, err := names.ParseFilesystemTag(in.FilesystemTag) 725 if err != nil { 726 return storage.FilesystemAttachment{}, errors.Trace(err) 727 } 728 machineTag, err := names.ParseMachineTag(in.MachineTag) 729 if err != nil { 730 return storage.FilesystemAttachment{}, errors.Trace(err) 731 } 732 return storage.FilesystemAttachment{ 733 filesystemTag, 734 machineTag, 735 storage.FilesystemAttachmentInfo{ 736 in.Info.MountPoint, 737 in.Info.ReadOnly, 738 }, 739 }, nil 740 } 741 742 func filesystemParamsFromParams(in params.FilesystemParams) (storage.FilesystemParams, error) { 743 filesystemTag, err := names.ParseFilesystemTag(in.FilesystemTag) 744 if err != nil { 745 return storage.FilesystemParams{}, errors.Trace(err) 746 } 747 var volumeTag names.VolumeTag 748 if in.VolumeTag != "" { 749 volumeTag, err = names.ParseVolumeTag(in.VolumeTag) 750 if err != nil { 751 return storage.FilesystemParams{}, errors.Trace(err) 752 } 753 } 754 providerType := storage.ProviderType(in.Provider) 755 return storage.FilesystemParams{ 756 filesystemTag, 757 volumeTag, 758 in.Size, 759 providerType, 760 in.Attributes, 761 in.Tags, 762 }, nil 763 } 764 765 func filesystemAttachmentParamsFromParams(in params.FilesystemAttachmentParams) (storage.FilesystemAttachmentParams, error) { 766 machineTag, err := names.ParseMachineTag(in.MachineTag) 767 if err != nil { 768 return storage.FilesystemAttachmentParams{}, errors.Trace(err) 769 } 770 filesystemTag, err := names.ParseFilesystemTag(in.FilesystemTag) 771 if err != nil { 772 return storage.FilesystemAttachmentParams{}, errors.Trace(err) 773 } 774 return storage.FilesystemAttachmentParams{ 775 AttachmentParams: storage.AttachmentParams{ 776 Provider: storage.ProviderType(in.Provider), 777 Machine: machineTag, 778 InstanceId: instance.Id(in.InstanceId), 779 ReadOnly: in.ReadOnly, 780 }, 781 Filesystem: filesystemTag, 782 FilesystemId: in.FilesystemId, 783 Path: in.MountPoint, 784 }, nil 785 }