github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/apiserver/storageprovisioner/storageprovisioner.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 "github.com/juju/errors" 8 "github.com/juju/loggo" 9 "github.com/juju/names" 10 11 "github.com/juju/juju/apiserver/common" 12 "github.com/juju/juju/apiserver/common/storagecommon" 13 "github.com/juju/juju/apiserver/params" 14 "github.com/juju/juju/state" 15 "github.com/juju/juju/state/watcher" 16 "github.com/juju/juju/storage" 17 "github.com/juju/juju/storage/poolmanager" 18 ) 19 20 var logger = loggo.GetLogger("juju.apiserver.storageprovisioner") 21 22 func init() { 23 common.RegisterStandardFacade("StorageProvisioner", 2, NewStorageProvisionerAPI) 24 } 25 26 // StorageProvisionerAPI provides access to the Provisioner API facade. 27 type StorageProvisionerAPI struct { 28 *common.LifeGetter 29 *common.DeadEnsurer 30 *common.ModelWatcher 31 *common.InstanceIdGetter 32 *common.StatusSetter 33 34 st provisionerState 35 settings poolmanager.SettingsManager 36 resources *common.Resources 37 authorizer common.Authorizer 38 getScopeAuthFunc common.GetAuthFunc 39 getStorageEntityAuthFunc common.GetAuthFunc 40 getMachineAuthFunc common.GetAuthFunc 41 getBlockDevicesAuthFunc common.GetAuthFunc 42 getAttachmentAuthFunc func() (func(names.MachineTag, names.Tag) bool, error) 43 } 44 45 var getState = func(st *state.State) provisionerState { 46 return stateShim{st} 47 } 48 49 var getSettingsManager = func(st *state.State) poolmanager.SettingsManager { 50 return state.NewStateSettings(st) 51 } 52 53 // NewStorageProvisionerAPI creates a new server-side StorageProvisionerAPI facade. 54 func NewStorageProvisionerAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*StorageProvisionerAPI, error) { 55 if !authorizer.AuthMachineAgent() { 56 return nil, common.ErrPerm 57 } 58 canAccessStorageMachine := func(tag names.MachineTag, allowEnvironManager bool) bool { 59 authEntityTag := authorizer.GetAuthTag() 60 if tag == authEntityTag { 61 // Machine agents can access volumes 62 // scoped to their own machine. 63 return true 64 } 65 parentId := state.ParentId(tag.Id()) 66 if parentId == "" { 67 return allowEnvironManager && authorizer.AuthModelManager() 68 } 69 // All containers with the authenticated 70 // machine as a parent are accessible by it. 71 return names.NewMachineTag(parentId) == authEntityTag 72 } 73 getScopeAuthFunc := func() (common.AuthFunc, error) { 74 return func(tag names.Tag) bool { 75 switch tag := tag.(type) { 76 case names.ModelTag: 77 // Environment managers can access all volumes 78 // and filesystems scoped to the environment. 79 isModelManager := authorizer.AuthModelManager() 80 return isModelManager && tag == st.ModelTag() 81 case names.MachineTag: 82 return canAccessStorageMachine(tag, false) 83 default: 84 return false 85 } 86 }, nil 87 } 88 canAccessStorageEntity := func(tag names.Tag, allowMachines bool) bool { 89 switch tag := tag.(type) { 90 case names.VolumeTag: 91 machineTag, ok := names.VolumeMachine(tag) 92 if ok { 93 return canAccessStorageMachine(machineTag, false) 94 } 95 return authorizer.AuthModelManager() 96 case names.FilesystemTag: 97 machineTag, ok := names.FilesystemMachine(tag) 98 if ok { 99 return canAccessStorageMachine(machineTag, false) 100 } 101 return authorizer.AuthModelManager() 102 case names.MachineTag: 103 return allowMachines && canAccessStorageMachine(tag, true) 104 default: 105 return false 106 } 107 } 108 getStorageEntityAuthFunc := func() (common.AuthFunc, error) { 109 return func(tag names.Tag) bool { 110 return canAccessStorageEntity(tag, false) 111 }, nil 112 } 113 getLifeAuthFunc := func() (common.AuthFunc, error) { 114 return func(tag names.Tag) bool { 115 return canAccessStorageEntity(tag, true) 116 }, nil 117 } 118 getAttachmentAuthFunc := func() (func(names.MachineTag, names.Tag) bool, error) { 119 // getAttachmentAuthFunc returns a function that validates 120 // access by the authenticated user to an attachment. 121 return func(machineTag names.MachineTag, attachmentTag names.Tag) bool { 122 // Machine agents can access their own machine, and 123 // machines contained. Environment managers can access 124 // top-level machines. 125 if !canAccessStorageMachine(machineTag, true) { 126 return false 127 } 128 // Environment managers can access model-scoped 129 // volumes and volumes scoped to their own machines. 130 // Other machine agents can access volumes regardless 131 // of their scope. 132 if !authorizer.AuthModelManager() { 133 return true 134 } 135 var machineScope names.MachineTag 136 var hasMachineScope bool 137 switch attachmentTag := attachmentTag.(type) { 138 case names.VolumeTag: 139 machineScope, hasMachineScope = names.VolumeMachine(attachmentTag) 140 case names.FilesystemTag: 141 machineScope, hasMachineScope = names.FilesystemMachine(attachmentTag) 142 } 143 return !hasMachineScope || machineScope == authorizer.GetAuthTag() 144 }, nil 145 } 146 getMachineAuthFunc := func() (common.AuthFunc, error) { 147 return func(tag names.Tag) bool { 148 if tag, ok := tag.(names.MachineTag); ok { 149 return canAccessStorageMachine(tag, true) 150 } 151 return false 152 }, nil 153 } 154 getBlockDevicesAuthFunc := func() (common.AuthFunc, error) { 155 return func(tag names.Tag) bool { 156 if tag, ok := tag.(names.MachineTag); ok { 157 return canAccessStorageMachine(tag, false) 158 } 159 return false 160 }, nil 161 } 162 stateInterface := getState(st) 163 settings := getSettingsManager(st) 164 return &StorageProvisionerAPI{ 165 LifeGetter: common.NewLifeGetter(stateInterface, getLifeAuthFunc), 166 DeadEnsurer: common.NewDeadEnsurer(stateInterface, getStorageEntityAuthFunc), 167 ModelWatcher: common.NewModelWatcher(stateInterface, resources, authorizer), 168 InstanceIdGetter: common.NewInstanceIdGetter(st, getMachineAuthFunc), 169 StatusSetter: common.NewStatusSetter(st, getStorageEntityAuthFunc), 170 171 st: stateInterface, 172 settings: settings, 173 resources: resources, 174 authorizer: authorizer, 175 getScopeAuthFunc: getScopeAuthFunc, 176 getStorageEntityAuthFunc: getStorageEntityAuthFunc, 177 getAttachmentAuthFunc: getAttachmentAuthFunc, 178 getMachineAuthFunc: getMachineAuthFunc, 179 getBlockDevicesAuthFunc: getBlockDevicesAuthFunc, 180 }, nil 181 } 182 183 // WatchBlockDevices watches for changes to the specified machines' block devices. 184 func (s *StorageProvisionerAPI) WatchBlockDevices(args params.Entities) (params.NotifyWatchResults, error) { 185 canAccess, err := s.getBlockDevicesAuthFunc() 186 if err != nil { 187 return params.NotifyWatchResults{}, common.ServerError(common.ErrPerm) 188 } 189 results := params.NotifyWatchResults{ 190 Results: make([]params.NotifyWatchResult, len(args.Entities)), 191 } 192 one := func(arg params.Entity) (string, error) { 193 machineTag, err := names.ParseMachineTag(arg.Tag) 194 if err != nil { 195 return "", err 196 } 197 if !canAccess(machineTag) { 198 return "", common.ErrPerm 199 } 200 w := s.st.WatchBlockDevices(machineTag) 201 if _, ok := <-w.Changes(); ok { 202 return s.resources.Register(w), nil 203 } 204 return "", watcher.EnsureErr(w) 205 } 206 for i, arg := range args.Entities { 207 var result params.NotifyWatchResult 208 id, err := one(arg) 209 if err != nil { 210 result.Error = common.ServerError(err) 211 } else { 212 result.NotifyWatcherId = id 213 } 214 results.Results[i] = result 215 } 216 return results, nil 217 } 218 219 // WatchMachines watches for changes to the specified machines. 220 func (s *StorageProvisionerAPI) WatchMachines(args params.Entities) (params.NotifyWatchResults, error) { 221 canAccess, err := s.getMachineAuthFunc() 222 if err != nil { 223 return params.NotifyWatchResults{}, common.ServerError(common.ErrPerm) 224 } 225 results := params.NotifyWatchResults{ 226 Results: make([]params.NotifyWatchResult, len(args.Entities)), 227 } 228 one := func(arg params.Entity) (string, error) { 229 machineTag, err := names.ParseMachineTag(arg.Tag) 230 if err != nil { 231 return "", err 232 } 233 if !canAccess(machineTag) { 234 return "", common.ErrPerm 235 } 236 w, err := s.st.WatchMachine(machineTag) 237 if err != nil { 238 return "", errors.Trace(err) 239 } 240 if _, ok := <-w.Changes(); ok { 241 return s.resources.Register(w), nil 242 } 243 return "", watcher.EnsureErr(w) 244 } 245 for i, arg := range args.Entities { 246 var result params.NotifyWatchResult 247 id, err := one(arg) 248 if err != nil { 249 result.Error = common.ServerError(err) 250 } else { 251 result.NotifyWatcherId = id 252 } 253 results.Results[i] = result 254 } 255 return results, nil 256 } 257 258 // WatchVolumes watches for changes to volumes scoped to the 259 // entity with the tag passed to NewState. 260 func (s *StorageProvisionerAPI) WatchVolumes(args params.Entities) (params.StringsWatchResults, error) { 261 return s.watchStorageEntities(args, s.st.WatchModelVolumes, s.st.WatchMachineVolumes) 262 } 263 264 // WatchFilesystems watches for changes to filesystems scoped 265 // to the entity with the tag passed to NewState. 266 func (s *StorageProvisionerAPI) WatchFilesystems(args params.Entities) (params.StringsWatchResults, error) { 267 return s.watchStorageEntities(args, s.st.WatchModelFilesystems, s.st.WatchMachineFilesystems) 268 } 269 270 func (s *StorageProvisionerAPI) watchStorageEntities( 271 args params.Entities, 272 watchEnvironStorage func() state.StringsWatcher, 273 watchMachineStorage func(names.MachineTag) state.StringsWatcher, 274 ) (params.StringsWatchResults, error) { 275 canAccess, err := s.getScopeAuthFunc() 276 if err != nil { 277 return params.StringsWatchResults{}, common.ServerError(common.ErrPerm) 278 } 279 results := params.StringsWatchResults{ 280 Results: make([]params.StringsWatchResult, len(args.Entities)), 281 } 282 one := func(arg params.Entity) (string, []string, error) { 283 tag, err := names.ParseTag(arg.Tag) 284 if err != nil || !canAccess(tag) { 285 return "", nil, common.ErrPerm 286 } 287 var w state.StringsWatcher 288 if tag, ok := tag.(names.MachineTag); ok { 289 w = watchMachineStorage(tag) 290 } else { 291 w = watchEnvironStorage() 292 } 293 if changes, ok := <-w.Changes(); ok { 294 return s.resources.Register(w), changes, nil 295 } 296 return "", nil, watcher.EnsureErr(w) 297 } 298 for i, arg := range args.Entities { 299 var result params.StringsWatchResult 300 id, changes, err := one(arg) 301 if err != nil { 302 result.Error = common.ServerError(err) 303 } else { 304 result.StringsWatcherId = id 305 result.Changes = changes 306 } 307 results.Results[i] = result 308 } 309 return results, nil 310 } 311 312 // WatchVolumeAttachments watches for changes to volume attachments scoped to 313 // the entity with the tag passed to NewState. 314 func (s *StorageProvisionerAPI) WatchVolumeAttachments(args params.Entities) (params.MachineStorageIdsWatchResults, error) { 315 return s.watchAttachments( 316 args, 317 s.st.WatchEnvironVolumeAttachments, 318 s.st.WatchMachineVolumeAttachments, 319 storagecommon.ParseVolumeAttachmentIds, 320 ) 321 } 322 323 // WatchFilesystemAttachments watches for changes to filesystem attachments 324 // scoped to the entity with the tag passed to NewState. 325 func (s *StorageProvisionerAPI) WatchFilesystemAttachments(args params.Entities) (params.MachineStorageIdsWatchResults, error) { 326 return s.watchAttachments( 327 args, 328 s.st.WatchEnvironFilesystemAttachments, 329 s.st.WatchMachineFilesystemAttachments, 330 storagecommon.ParseFilesystemAttachmentIds, 331 ) 332 } 333 334 func (s *StorageProvisionerAPI) watchAttachments( 335 args params.Entities, 336 watchEnvironAttachments func() state.StringsWatcher, 337 watchMachineAttachments func(names.MachineTag) state.StringsWatcher, 338 parseAttachmentIds func([]string) ([]params.MachineStorageId, error), 339 ) (params.MachineStorageIdsWatchResults, error) { 340 canAccess, err := s.getScopeAuthFunc() 341 if err != nil { 342 return params.MachineStorageIdsWatchResults{}, common.ServerError(common.ErrPerm) 343 } 344 results := params.MachineStorageIdsWatchResults{ 345 Results: make([]params.MachineStorageIdsWatchResult, len(args.Entities)), 346 } 347 one := func(arg params.Entity) (string, []params.MachineStorageId, error) { 348 tag, err := names.ParseTag(arg.Tag) 349 if err != nil || !canAccess(tag) { 350 return "", nil, common.ErrPerm 351 } 352 var w state.StringsWatcher 353 if tag, ok := tag.(names.MachineTag); ok { 354 w = watchMachineAttachments(tag) 355 } else { 356 w = watchEnvironAttachments() 357 } 358 if stringChanges, ok := <-w.Changes(); ok { 359 changes, err := parseAttachmentIds(stringChanges) 360 if err != nil { 361 w.Stop() 362 return "", nil, err 363 } 364 return s.resources.Register(w), changes, nil 365 } 366 return "", nil, watcher.EnsureErr(w) 367 } 368 for i, arg := range args.Entities { 369 var result params.MachineStorageIdsWatchResult 370 id, changes, err := one(arg) 371 if err != nil { 372 result.Error = common.ServerError(err) 373 } else { 374 result.MachineStorageIdsWatcherId = id 375 result.Changes = changes 376 } 377 results.Results[i] = result 378 } 379 return results, nil 380 } 381 382 // Volumes returns details of volumes with the specified tags. 383 func (s *StorageProvisionerAPI) Volumes(args params.Entities) (params.VolumeResults, error) { 384 canAccess, err := s.getStorageEntityAuthFunc() 385 if err != nil { 386 return params.VolumeResults{}, common.ServerError(common.ErrPerm) 387 } 388 results := params.VolumeResults{ 389 Results: make([]params.VolumeResult, len(args.Entities)), 390 } 391 one := func(arg params.Entity) (params.Volume, error) { 392 tag, err := names.ParseVolumeTag(arg.Tag) 393 if err != nil || !canAccess(tag) { 394 return params.Volume{}, common.ErrPerm 395 } 396 volume, err := s.st.Volume(tag) 397 if errors.IsNotFound(err) { 398 return params.Volume{}, common.ErrPerm 399 } else if err != nil { 400 return params.Volume{}, err 401 } 402 return storagecommon.VolumeFromState(volume) 403 } 404 for i, arg := range args.Entities { 405 var result params.VolumeResult 406 volume, err := one(arg) 407 if err != nil { 408 result.Error = common.ServerError(err) 409 } else { 410 result.Result = volume 411 } 412 results.Results[i] = result 413 } 414 return results, nil 415 } 416 417 // Filesystems returns details of filesystems with the specified tags. 418 func (s *StorageProvisionerAPI) Filesystems(args params.Entities) (params.FilesystemResults, error) { 419 canAccess, err := s.getStorageEntityAuthFunc() 420 if err != nil { 421 return params.FilesystemResults{}, common.ServerError(common.ErrPerm) 422 } 423 results := params.FilesystemResults{ 424 Results: make([]params.FilesystemResult, len(args.Entities)), 425 } 426 one := func(arg params.Entity) (params.Filesystem, error) { 427 tag, err := names.ParseFilesystemTag(arg.Tag) 428 if err != nil || !canAccess(tag) { 429 return params.Filesystem{}, common.ErrPerm 430 } 431 filesystem, err := s.st.Filesystem(tag) 432 if errors.IsNotFound(err) { 433 return params.Filesystem{}, common.ErrPerm 434 } else if err != nil { 435 return params.Filesystem{}, err 436 } 437 return storagecommon.FilesystemFromState(filesystem) 438 } 439 for i, arg := range args.Entities { 440 var result params.FilesystemResult 441 filesystem, err := one(arg) 442 if err != nil { 443 result.Error = common.ServerError(err) 444 } else { 445 result.Result = filesystem 446 } 447 results.Results[i] = result 448 } 449 return results, nil 450 } 451 452 // VolumeAttachments returns details of volume attachments with the specified IDs. 453 func (s *StorageProvisionerAPI) VolumeAttachments(args params.MachineStorageIds) (params.VolumeAttachmentResults, error) { 454 canAccess, err := s.getAttachmentAuthFunc() 455 if err != nil { 456 return params.VolumeAttachmentResults{}, common.ServerError(common.ErrPerm) 457 } 458 results := params.VolumeAttachmentResults{ 459 Results: make([]params.VolumeAttachmentResult, len(args.Ids)), 460 } 461 one := func(arg params.MachineStorageId) (params.VolumeAttachment, error) { 462 volumeAttachment, err := s.oneVolumeAttachment(arg, canAccess) 463 if err != nil { 464 return params.VolumeAttachment{}, err 465 } 466 return storagecommon.VolumeAttachmentFromState(volumeAttachment) 467 } 468 for i, arg := range args.Ids { 469 var result params.VolumeAttachmentResult 470 volumeAttachment, err := one(arg) 471 if err != nil { 472 result.Error = common.ServerError(err) 473 } else { 474 result.Result = volumeAttachment 475 } 476 results.Results[i] = result 477 } 478 return results, nil 479 } 480 481 // VolumeBlockDevices returns details of the block devices corresponding to the 482 // volume attachments with the specified IDs. 483 func (s *StorageProvisionerAPI) VolumeBlockDevices(args params.MachineStorageIds) (params.BlockDeviceResults, error) { 484 canAccess, err := s.getAttachmentAuthFunc() 485 if err != nil { 486 return params.BlockDeviceResults{}, common.ServerError(common.ErrPerm) 487 } 488 results := params.BlockDeviceResults{ 489 Results: make([]params.BlockDeviceResult, len(args.Ids)), 490 } 491 one := func(arg params.MachineStorageId) (storage.BlockDevice, error) { 492 stateBlockDevice, err := s.oneVolumeBlockDevice(arg, canAccess) 493 if err != nil { 494 return storage.BlockDevice{}, err 495 } 496 return storagecommon.BlockDeviceFromState(stateBlockDevice), nil 497 } 498 for i, arg := range args.Ids { 499 var result params.BlockDeviceResult 500 blockDevice, err := one(arg) 501 if err != nil { 502 result.Error = common.ServerError(err) 503 } else { 504 result.Result = blockDevice 505 } 506 results.Results[i] = result 507 } 508 return results, nil 509 } 510 511 // FilesystemAttachments returns details of filesystem attachments with the specified IDs. 512 func (s *StorageProvisionerAPI) FilesystemAttachments(args params.MachineStorageIds) (params.FilesystemAttachmentResults, error) { 513 canAccess, err := s.getAttachmentAuthFunc() 514 if err != nil { 515 return params.FilesystemAttachmentResults{}, common.ServerError(common.ErrPerm) 516 } 517 results := params.FilesystemAttachmentResults{ 518 Results: make([]params.FilesystemAttachmentResult, len(args.Ids)), 519 } 520 one := func(arg params.MachineStorageId) (params.FilesystemAttachment, error) { 521 filesystemAttachment, err := s.oneFilesystemAttachment(arg, canAccess) 522 if err != nil { 523 return params.FilesystemAttachment{}, err 524 } 525 return storagecommon.FilesystemAttachmentFromState(filesystemAttachment) 526 } 527 for i, arg := range args.Ids { 528 var result params.FilesystemAttachmentResult 529 filesystemAttachment, err := one(arg) 530 if err != nil { 531 result.Error = common.ServerError(err) 532 } else { 533 result.Result = filesystemAttachment 534 } 535 results.Results[i] = result 536 } 537 return results, nil 538 } 539 540 // VolumeParams returns the parameters for creating or destroying 541 // the volumes with the specified tags. 542 func (s *StorageProvisionerAPI) VolumeParams(args params.Entities) (params.VolumeParamsResults, error) { 543 canAccess, err := s.getStorageEntityAuthFunc() 544 if err != nil { 545 return params.VolumeParamsResults{}, err 546 } 547 envConfig, err := s.st.ModelConfig() 548 if err != nil { 549 return params.VolumeParamsResults{}, err 550 } 551 results := params.VolumeParamsResults{ 552 Results: make([]params.VolumeParamsResult, len(args.Entities)), 553 } 554 poolManager := poolmanager.New(s.settings) 555 one := func(arg params.Entity) (params.VolumeParams, error) { 556 tag, err := names.ParseVolumeTag(arg.Tag) 557 if err != nil || !canAccess(tag) { 558 return params.VolumeParams{}, common.ErrPerm 559 } 560 volume, err := s.st.Volume(tag) 561 if errors.IsNotFound(err) { 562 return params.VolumeParams{}, common.ErrPerm 563 } else if err != nil { 564 return params.VolumeParams{}, err 565 } 566 volumeAttachments, err := s.st.VolumeAttachments(tag) 567 if err != nil { 568 return params.VolumeParams{}, err 569 } 570 storageInstance, err := storagecommon.MaybeAssignedStorageInstance( 571 volume.StorageInstance, 572 s.st.StorageInstance, 573 ) 574 if err != nil { 575 return params.VolumeParams{}, err 576 } 577 volumeParams, err := storagecommon.VolumeParams(volume, storageInstance, envConfig, poolManager) 578 if err != nil { 579 return params.VolumeParams{}, err 580 } 581 if len(volumeAttachments) == 1 { 582 // There is exactly one attachment to be made, so make 583 // it immediately. Otherwise we will defer attachments 584 // until later. 585 volumeAttachment := volumeAttachments[0] 586 volumeAttachmentParams, ok := volumeAttachment.Params() 587 if !ok { 588 return params.VolumeParams{}, errors.Errorf( 589 "volume %q is already attached to machine %q", 590 volumeAttachment.Volume().Id(), 591 volumeAttachment.Machine().Id(), 592 ) 593 } 594 machineTag := volumeAttachment.Machine() 595 instanceId, err := s.st.MachineInstanceId(machineTag) 596 if errors.IsNotProvisioned(err) { 597 // Leave the attachment until later. 598 instanceId = "" 599 } else if err != nil { 600 return params.VolumeParams{}, err 601 } 602 volumeParams.Attachment = ¶ms.VolumeAttachmentParams{ 603 tag.String(), 604 machineTag.String(), 605 "", // volume ID 606 string(instanceId), 607 volumeParams.Provider, 608 volumeAttachmentParams.ReadOnly, 609 } 610 } 611 return volumeParams, nil 612 } 613 for i, arg := range args.Entities { 614 var result params.VolumeParamsResult 615 volumeParams, err := one(arg) 616 if err != nil { 617 result.Error = common.ServerError(err) 618 } else { 619 result.Result = volumeParams 620 } 621 results.Results[i] = result 622 } 623 return results, nil 624 } 625 626 // FilesystemParams returns the parameters for creating the filesystems 627 // with the specified tags. 628 func (s *StorageProvisionerAPI) FilesystemParams(args params.Entities) (params.FilesystemParamsResults, error) { 629 canAccess, err := s.getStorageEntityAuthFunc() 630 if err != nil { 631 return params.FilesystemParamsResults{}, err 632 } 633 envConfig, err := s.st.ModelConfig() 634 if err != nil { 635 return params.FilesystemParamsResults{}, err 636 } 637 results := params.FilesystemParamsResults{ 638 Results: make([]params.FilesystemParamsResult, len(args.Entities)), 639 } 640 poolManager := poolmanager.New(s.settings) 641 one := func(arg params.Entity) (params.FilesystemParams, error) { 642 tag, err := names.ParseFilesystemTag(arg.Tag) 643 if err != nil || !canAccess(tag) { 644 return params.FilesystemParams{}, common.ErrPerm 645 } 646 filesystem, err := s.st.Filesystem(tag) 647 if errors.IsNotFound(err) { 648 return params.FilesystemParams{}, common.ErrPerm 649 } else if err != nil { 650 return params.FilesystemParams{}, err 651 } 652 storageInstance, err := storagecommon.MaybeAssignedStorageInstance( 653 filesystem.Storage, 654 s.st.StorageInstance, 655 ) 656 if err != nil { 657 return params.FilesystemParams{}, err 658 } 659 filesystemParams, err := storagecommon.FilesystemParams( 660 filesystem, storageInstance, envConfig, poolManager, 661 ) 662 if err != nil { 663 return params.FilesystemParams{}, err 664 } 665 return filesystemParams, nil 666 } 667 for i, arg := range args.Entities { 668 var result params.FilesystemParamsResult 669 filesystemParams, err := one(arg) 670 if err != nil { 671 result.Error = common.ServerError(err) 672 } else { 673 result.Result = filesystemParams 674 } 675 results.Results[i] = result 676 } 677 return results, nil 678 } 679 680 // VolumeAttachmentParams returns the parameters for creating the volume 681 // attachments with the specified IDs. 682 func (s *StorageProvisionerAPI) VolumeAttachmentParams( 683 args params.MachineStorageIds, 684 ) (params.VolumeAttachmentParamsResults, error) { 685 canAccess, err := s.getAttachmentAuthFunc() 686 if err != nil { 687 return params.VolumeAttachmentParamsResults{}, common.ServerError(common.ErrPerm) 688 } 689 results := params.VolumeAttachmentParamsResults{ 690 Results: make([]params.VolumeAttachmentParamsResult, len(args.Ids)), 691 } 692 poolManager := poolmanager.New(s.settings) 693 one := func(arg params.MachineStorageId) (params.VolumeAttachmentParams, error) { 694 volumeAttachment, err := s.oneVolumeAttachment(arg, canAccess) 695 if err != nil { 696 return params.VolumeAttachmentParams{}, err 697 } 698 instanceId, err := s.st.MachineInstanceId(volumeAttachment.Machine()) 699 if errors.IsNotProvisioned(err) { 700 // The worker must watch for machine provisioning events. 701 instanceId = "" 702 } else if err != nil { 703 return params.VolumeAttachmentParams{}, err 704 } 705 volume, err := s.st.Volume(volumeAttachment.Volume()) 706 if err != nil { 707 return params.VolumeAttachmentParams{}, err 708 } 709 var volumeId string 710 var pool string 711 if volumeParams, ok := volume.Params(); ok { 712 pool = volumeParams.Pool 713 } else { 714 volumeInfo, err := volume.Info() 715 if err != nil { 716 return params.VolumeAttachmentParams{}, err 717 } 718 volumeId = volumeInfo.VolumeId 719 pool = volumeInfo.Pool 720 } 721 providerType, _, err := storagecommon.StoragePoolConfig(pool, poolManager) 722 if err != nil { 723 return params.VolumeAttachmentParams{}, errors.Trace(err) 724 } 725 var readOnly bool 726 if volumeAttachmentParams, ok := volumeAttachment.Params(); ok { 727 readOnly = volumeAttachmentParams.ReadOnly 728 } else { 729 // Attachment parameters may be requested even if the 730 // attachment exists; i.e. for reattachment. 731 volumeAttachmentInfo, err := volumeAttachment.Info() 732 if err != nil { 733 return params.VolumeAttachmentParams{}, errors.Trace(err) 734 } 735 readOnly = volumeAttachmentInfo.ReadOnly 736 } 737 return params.VolumeAttachmentParams{ 738 volumeAttachment.Volume().String(), 739 volumeAttachment.Machine().String(), 740 volumeId, 741 string(instanceId), 742 string(providerType), 743 readOnly, 744 }, nil 745 } 746 for i, arg := range args.Ids { 747 var result params.VolumeAttachmentParamsResult 748 volumeAttachment, err := one(arg) 749 if err != nil { 750 result.Error = common.ServerError(err) 751 } else { 752 result.Result = volumeAttachment 753 } 754 results.Results[i] = result 755 } 756 return results, nil 757 } 758 759 // FilesystemAttachmentParams returns the parameters for creating the filesystem 760 // attachments with the specified IDs. 761 func (s *StorageProvisionerAPI) FilesystemAttachmentParams( 762 args params.MachineStorageIds, 763 ) (params.FilesystemAttachmentParamsResults, error) { 764 canAccess, err := s.getAttachmentAuthFunc() 765 if err != nil { 766 return params.FilesystemAttachmentParamsResults{}, common.ServerError(common.ErrPerm) 767 } 768 results := params.FilesystemAttachmentParamsResults{ 769 Results: make([]params.FilesystemAttachmentParamsResult, len(args.Ids)), 770 } 771 poolManager := poolmanager.New(s.settings) 772 one := func(arg params.MachineStorageId) (params.FilesystemAttachmentParams, error) { 773 filesystemAttachment, err := s.oneFilesystemAttachment(arg, canAccess) 774 if err != nil { 775 return params.FilesystemAttachmentParams{}, err 776 } 777 instanceId, err := s.st.MachineInstanceId(filesystemAttachment.Machine()) 778 if errors.IsNotProvisioned(err) { 779 // The worker must watch for machine provisioning events. 780 instanceId = "" 781 } else if err != nil { 782 return params.FilesystemAttachmentParams{}, err 783 } 784 filesystem, err := s.st.Filesystem(filesystemAttachment.Filesystem()) 785 if err != nil { 786 return params.FilesystemAttachmentParams{}, err 787 } 788 var filesystemId string 789 var pool string 790 if filesystemParams, ok := filesystem.Params(); ok { 791 pool = filesystemParams.Pool 792 } else { 793 filesystemInfo, err := filesystem.Info() 794 if err != nil { 795 return params.FilesystemAttachmentParams{}, err 796 } 797 filesystemId = filesystemInfo.FilesystemId 798 pool = filesystemInfo.Pool 799 } 800 providerType, _, err := storagecommon.StoragePoolConfig(pool, poolManager) 801 if err != nil { 802 return params.FilesystemAttachmentParams{}, errors.Trace(err) 803 } 804 var location string 805 var readOnly bool 806 if filesystemAttachmentParams, ok := filesystemAttachment.Params(); ok { 807 location = filesystemAttachmentParams.Location 808 readOnly = filesystemAttachmentParams.ReadOnly 809 } else { 810 // Attachment parameters may be requested even if the 811 // attachment exists; i.e. for reattachment. 812 filesystemAttachmentInfo, err := filesystemAttachment.Info() 813 if err != nil { 814 return params.FilesystemAttachmentParams{}, errors.Trace(err) 815 } 816 location = filesystemAttachmentInfo.MountPoint 817 readOnly = filesystemAttachmentInfo.ReadOnly 818 } 819 return params.FilesystemAttachmentParams{ 820 filesystemAttachment.Filesystem().String(), 821 filesystemAttachment.Machine().String(), 822 filesystemId, 823 string(instanceId), 824 string(providerType), 825 // TODO(axw) dealias MountPoint. We now have 826 // Path, MountPoint and Location in different 827 // parts of the codebase. 828 location, 829 readOnly, 830 }, nil 831 } 832 for i, arg := range args.Ids { 833 var result params.FilesystemAttachmentParamsResult 834 filesystemAttachment, err := one(arg) 835 if err != nil { 836 result.Error = common.ServerError(err) 837 } else { 838 result.Result = filesystemAttachment 839 } 840 results.Results[i] = result 841 } 842 return results, nil 843 } 844 845 func (s *StorageProvisionerAPI) oneVolumeAttachment( 846 id params.MachineStorageId, canAccess func(names.MachineTag, names.Tag) bool, 847 ) (state.VolumeAttachment, error) { 848 machineTag, err := names.ParseMachineTag(id.MachineTag) 849 if err != nil { 850 return nil, err 851 } 852 volumeTag, err := names.ParseVolumeTag(id.AttachmentTag) 853 if err != nil { 854 return nil, err 855 } 856 if !canAccess(machineTag, volumeTag) { 857 return nil, common.ErrPerm 858 } 859 volumeAttachment, err := s.st.VolumeAttachment(machineTag, volumeTag) 860 if errors.IsNotFound(err) { 861 return nil, common.ErrPerm 862 } else if err != nil { 863 return nil, err 864 } 865 return volumeAttachment, nil 866 } 867 868 func (s *StorageProvisionerAPI) oneVolumeBlockDevice( 869 id params.MachineStorageId, canAccess func(names.MachineTag, names.Tag) bool, 870 ) (state.BlockDeviceInfo, error) { 871 volumeAttachment, err := s.oneVolumeAttachment(id, canAccess) 872 if err != nil { 873 return state.BlockDeviceInfo{}, err 874 } 875 volume, err := s.st.Volume(volumeAttachment.Volume()) 876 if err != nil { 877 return state.BlockDeviceInfo{}, err 878 } 879 volumeInfo, err := volume.Info() 880 if err != nil { 881 return state.BlockDeviceInfo{}, err 882 } 883 volumeAttachmentInfo, err := volumeAttachment.Info() 884 if err != nil { 885 return state.BlockDeviceInfo{}, err 886 } 887 blockDevices, err := s.st.BlockDevices(volumeAttachment.Machine()) 888 if err != nil { 889 return state.BlockDeviceInfo{}, err 890 } 891 blockDevice, ok := storagecommon.MatchingBlockDevice( 892 blockDevices, 893 volumeInfo, 894 volumeAttachmentInfo, 895 ) 896 if !ok { 897 return state.BlockDeviceInfo{}, errors.NotFoundf( 898 "block device for volume %v on machine %v", 899 volumeAttachment.Volume().Id(), 900 volumeAttachment.Machine().Id(), 901 ) 902 } 903 return *blockDevice, nil 904 } 905 906 func (s *StorageProvisionerAPI) oneFilesystemAttachment( 907 id params.MachineStorageId, canAccess func(names.MachineTag, names.Tag) bool, 908 ) (state.FilesystemAttachment, error) { 909 machineTag, err := names.ParseMachineTag(id.MachineTag) 910 if err != nil { 911 return nil, err 912 } 913 filesystemTag, err := names.ParseFilesystemTag(id.AttachmentTag) 914 if err != nil { 915 return nil, err 916 } 917 if !canAccess(machineTag, filesystemTag) { 918 return nil, common.ErrPerm 919 } 920 filesystemAttachment, err := s.st.FilesystemAttachment(machineTag, filesystemTag) 921 if errors.IsNotFound(err) { 922 return nil, common.ErrPerm 923 } else if err != nil { 924 return nil, err 925 } 926 return filesystemAttachment, nil 927 } 928 929 // SetVolumeInfo records the details of newly provisioned volumes. 930 func (s *StorageProvisionerAPI) SetVolumeInfo(args params.Volumes) (params.ErrorResults, error) { 931 canAccessVolume, err := s.getStorageEntityAuthFunc() 932 if err != nil { 933 return params.ErrorResults{}, err 934 } 935 results := params.ErrorResults{ 936 Results: make([]params.ErrorResult, len(args.Volumes)), 937 } 938 one := func(arg params.Volume) error { 939 volumeTag, volumeInfo, err := storagecommon.VolumeToState(arg) 940 if err != nil { 941 return errors.Trace(err) 942 } else if !canAccessVolume(volumeTag) { 943 return common.ErrPerm 944 } 945 err = s.st.SetVolumeInfo(volumeTag, volumeInfo) 946 if errors.IsNotFound(err) { 947 return common.ErrPerm 948 } 949 return errors.Trace(err) 950 } 951 for i, arg := range args.Volumes { 952 err := one(arg) 953 results.Results[i].Error = common.ServerError(err) 954 } 955 return results, nil 956 } 957 958 // SetFilesystemInfo records the details of newly provisioned filesystems. 959 func (s *StorageProvisionerAPI) SetFilesystemInfo(args params.Filesystems) (params.ErrorResults, error) { 960 canAccessFilesystem, err := s.getStorageEntityAuthFunc() 961 if err != nil { 962 return params.ErrorResults{}, err 963 } 964 results := params.ErrorResults{ 965 Results: make([]params.ErrorResult, len(args.Filesystems)), 966 } 967 one := func(arg params.Filesystem) error { 968 filesystemTag, filesystemInfo, err := storagecommon.FilesystemToState(arg) 969 if err != nil { 970 return errors.Trace(err) 971 } else if !canAccessFilesystem(filesystemTag) { 972 return common.ErrPerm 973 } 974 err = s.st.SetFilesystemInfo(filesystemTag, filesystemInfo) 975 if errors.IsNotFound(err) { 976 return common.ErrPerm 977 } 978 return errors.Trace(err) 979 } 980 for i, arg := range args.Filesystems { 981 err := one(arg) 982 results.Results[i].Error = common.ServerError(err) 983 } 984 return results, nil 985 } 986 987 // SetVolumeAttachmentInfo records the details of newly provisioned volume 988 // attachments. 989 func (s *StorageProvisionerAPI) SetVolumeAttachmentInfo( 990 args params.VolumeAttachments, 991 ) (params.ErrorResults, error) { 992 canAccess, err := s.getAttachmentAuthFunc() 993 if err != nil { 994 return params.ErrorResults{}, err 995 } 996 results := params.ErrorResults{ 997 Results: make([]params.ErrorResult, len(args.VolumeAttachments)), 998 } 999 one := func(arg params.VolumeAttachment) error { 1000 machineTag, volumeTag, volumeAttachmentInfo, err := storagecommon.VolumeAttachmentToState(arg) 1001 if err != nil { 1002 return errors.Trace(err) 1003 } 1004 if !canAccess(machineTag, volumeTag) { 1005 return common.ErrPerm 1006 } 1007 err = s.st.SetVolumeAttachmentInfo(machineTag, volumeTag, volumeAttachmentInfo) 1008 if errors.IsNotFound(err) { 1009 return common.ErrPerm 1010 } 1011 return errors.Trace(err) 1012 } 1013 for i, arg := range args.VolumeAttachments { 1014 err := one(arg) 1015 results.Results[i].Error = common.ServerError(err) 1016 } 1017 return results, nil 1018 } 1019 1020 // SetFilesystemAttachmentInfo records the details of newly provisioned filesystem 1021 // attachments. 1022 func (s *StorageProvisionerAPI) SetFilesystemAttachmentInfo( 1023 args params.FilesystemAttachments, 1024 ) (params.ErrorResults, error) { 1025 canAccess, err := s.getAttachmentAuthFunc() 1026 if err != nil { 1027 return params.ErrorResults{}, err 1028 } 1029 results := params.ErrorResults{ 1030 Results: make([]params.ErrorResult, len(args.FilesystemAttachments)), 1031 } 1032 one := func(arg params.FilesystemAttachment) error { 1033 machineTag, filesystemTag, filesystemAttachmentInfo, err := storagecommon.FilesystemAttachmentToState(arg) 1034 if err != nil { 1035 return errors.Trace(err) 1036 } 1037 if !canAccess(machineTag, filesystemTag) { 1038 return common.ErrPerm 1039 } 1040 err = s.st.SetFilesystemAttachmentInfo(machineTag, filesystemTag, filesystemAttachmentInfo) 1041 if errors.IsNotFound(err) { 1042 return common.ErrPerm 1043 } 1044 return errors.Trace(err) 1045 } 1046 for i, arg := range args.FilesystemAttachments { 1047 err := one(arg) 1048 results.Results[i].Error = common.ServerError(err) 1049 } 1050 return results, nil 1051 } 1052 1053 // AttachmentLife returns the lifecycle state of each specified machine 1054 // storage attachment. 1055 func (s *StorageProvisionerAPI) AttachmentLife(args params.MachineStorageIds) (params.LifeResults, error) { 1056 canAccess, err := s.getAttachmentAuthFunc() 1057 if err != nil { 1058 return params.LifeResults{}, err 1059 } 1060 results := params.LifeResults{ 1061 Results: make([]params.LifeResult, len(args.Ids)), 1062 } 1063 one := func(arg params.MachineStorageId) (params.Life, error) { 1064 machineTag, err := names.ParseMachineTag(arg.MachineTag) 1065 if err != nil { 1066 return "", err 1067 } 1068 attachmentTag, err := names.ParseTag(arg.AttachmentTag) 1069 if err != nil { 1070 return "", err 1071 } 1072 if !canAccess(machineTag, attachmentTag) { 1073 return "", common.ErrPerm 1074 } 1075 var lifer state.Lifer 1076 switch attachmentTag := attachmentTag.(type) { 1077 case names.VolumeTag: 1078 lifer, err = s.st.VolumeAttachment(machineTag, attachmentTag) 1079 case names.FilesystemTag: 1080 lifer, err = s.st.FilesystemAttachment(machineTag, attachmentTag) 1081 } 1082 if errors.IsNotFound(err) { 1083 return "", common.ErrPerm 1084 } else if err != nil { 1085 return "", errors.Trace(err) 1086 } 1087 return params.Life(lifer.Life().String()), nil 1088 } 1089 for i, arg := range args.Ids { 1090 life, err := one(arg) 1091 if err != nil { 1092 results.Results[i].Error = common.ServerError(err) 1093 } else { 1094 results.Results[i].Life = life 1095 } 1096 } 1097 return results, nil 1098 } 1099 1100 // Remove removes volumes and filesystems from state. 1101 func (s *StorageProvisionerAPI) Remove(args params.Entities) (params.ErrorResults, error) { 1102 canAccess, err := s.getStorageEntityAuthFunc() 1103 if err != nil { 1104 return params.ErrorResults{}, err 1105 } 1106 results := params.ErrorResults{ 1107 Results: make([]params.ErrorResult, len(args.Entities)), 1108 } 1109 one := func(arg params.Entity) error { 1110 tag, err := names.ParseTag(arg.Tag) 1111 if err != nil { 1112 return errors.Trace(err) 1113 } 1114 if !canAccess(tag) { 1115 return common.ErrPerm 1116 } 1117 switch tag := tag.(type) { 1118 case names.FilesystemTag: 1119 return s.st.RemoveFilesystem(tag) 1120 case names.VolumeTag: 1121 return s.st.RemoveVolume(tag) 1122 default: 1123 // should have been picked up by canAccess 1124 logger.Debugf("unexpected %v tag", tag.Kind()) 1125 return common.ErrPerm 1126 } 1127 } 1128 for i, arg := range args.Entities { 1129 err := one(arg) 1130 results.Results[i].Error = common.ServerError(err) 1131 } 1132 return results, nil 1133 } 1134 1135 // RemoveAttachments removes the specified machine storage attachments 1136 // from state. 1137 func (s *StorageProvisionerAPI) RemoveAttachment(args params.MachineStorageIds) (params.ErrorResults, error) { 1138 canAccess, err := s.getAttachmentAuthFunc() 1139 if err != nil { 1140 return params.ErrorResults{}, err 1141 } 1142 results := params.ErrorResults{ 1143 Results: make([]params.ErrorResult, len(args.Ids)), 1144 } 1145 removeAttachment := func(arg params.MachineStorageId) error { 1146 machineTag, err := names.ParseMachineTag(arg.MachineTag) 1147 if err != nil { 1148 return err 1149 } 1150 attachmentTag, err := names.ParseTag(arg.AttachmentTag) 1151 if err != nil { 1152 return err 1153 } 1154 if !canAccess(machineTag, attachmentTag) { 1155 return common.ErrPerm 1156 } 1157 switch attachmentTag := attachmentTag.(type) { 1158 case names.VolumeTag: 1159 return s.st.RemoveVolumeAttachment(machineTag, attachmentTag) 1160 case names.FilesystemTag: 1161 return s.st.RemoveFilesystemAttachment(machineTag, attachmentTag) 1162 default: 1163 return common.ErrPerm 1164 } 1165 } 1166 for i, arg := range args.Ids { 1167 if err := removeAttachment(arg); err != nil { 1168 results.Results[i].Error = common.ServerError(err) 1169 } 1170 } 1171 return results, nil 1172 }