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