github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/apiserver/storageprovisioner/storageprovisioner_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package storageprovisioner_test 5 6 import ( 7 "sort" 8 9 "github.com/juju/errors" 10 "github.com/juju/names" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 14 "github.com/juju/juju/apiserver/common" 15 "github.com/juju/juju/apiserver/params" 16 "github.com/juju/juju/apiserver/storageprovisioner" 17 apiservertesting "github.com/juju/juju/apiserver/testing" 18 "github.com/juju/juju/environs/tags" 19 "github.com/juju/juju/instance" 20 jujutesting "github.com/juju/juju/juju/testing" 21 "github.com/juju/juju/state" 22 statetesting "github.com/juju/juju/state/testing" 23 "github.com/juju/juju/storage" 24 "github.com/juju/juju/storage/provider/dummy" 25 "github.com/juju/juju/storage/provider/registry" 26 "github.com/juju/juju/testing" 27 "github.com/juju/juju/testing/factory" 28 ) 29 30 var _ = gc.Suite(&provisionerSuite{}) 31 32 type provisionerSuite struct { 33 // TODO(wallyworld) remove JujuConnSuite 34 jujutesting.JujuConnSuite 35 36 factory *factory.Factory 37 resources *common.Resources 38 authorizer *apiservertesting.FakeAuthorizer 39 api *storageprovisioner.StorageProvisionerAPI 40 } 41 42 func (s *provisionerSuite) SetUpSuite(c *gc.C) { 43 s.JujuConnSuite.SetUpSuite(c) 44 45 registry.RegisterProvider("environscoped", &dummy.StorageProvider{ 46 StorageScope: storage.ScopeEnviron, 47 }) 48 registry.RegisterProvider("machinescoped", &dummy.StorageProvider{ 49 StorageScope: storage.ScopeMachine, 50 }) 51 registry.RegisterEnvironStorageProviders( 52 "dummy", "environscoped", "machinescoped", 53 ) 54 s.AddSuiteCleanup(func(c *gc.C) { 55 registry.RegisterProvider("environscoped", nil) 56 registry.RegisterProvider("machinescoped", nil) 57 }) 58 } 59 60 func (s *provisionerSuite) SetUpTest(c *gc.C) { 61 s.JujuConnSuite.SetUpTest(c) 62 s.factory = factory.NewFactory(s.State) 63 s.resources = common.NewResources() 64 // Create the resource registry separately to track invocations to 65 // Register. 66 s.resources = common.NewResources() 67 s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() }) 68 69 var err error 70 s.authorizer = &apiservertesting.FakeAuthorizer{ 71 Tag: names.NewMachineTag("0"), 72 EnvironManager: true, 73 } 74 s.api, err = storageprovisioner.NewStorageProvisionerAPI(s.State, s.resources, s.authorizer) 75 c.Assert(err, jc.ErrorIsNil) 76 } 77 78 func (s *provisionerSuite) TestNewStorageProvisionerAPINonMachine(c *gc.C) { 79 tag := names.NewUnitTag("mysql/0") 80 authorizer := &apiservertesting.FakeAuthorizer{Tag: tag} 81 _, err := storageprovisioner.NewStorageProvisionerAPI(s.State, common.NewResources(), authorizer) 82 c.Assert(err, gc.ErrorMatches, "permission denied") 83 } 84 85 func (s *provisionerSuite) setupVolumes(c *gc.C) { 86 s.factory.MakeMachine(c, &factory.MachineParams{ 87 InstanceId: instance.Id("inst-id"), 88 Volumes: []state.MachineVolumeParams{ 89 {Volume: state.VolumeParams{Pool: "machinescoped", Size: 1024}}, 90 {Volume: state.VolumeParams{Pool: "environscoped", Size: 2048}}, 91 {Volume: state.VolumeParams{Pool: "environscoped", Size: 4096}}, 92 { 93 Volume: state.VolumeParams{Pool: "environscoped", Size: 4096}, 94 Attachment: state.VolumeAttachmentParams{ 95 ReadOnly: true, 96 }, 97 }, 98 }, 99 }) 100 // Only provision the first and third volumes. 101 err := s.State.SetVolumeInfo(names.NewVolumeTag("0/0"), state.VolumeInfo{ 102 HardwareId: "123", 103 VolumeId: "abc", 104 Size: 1024, 105 Persistent: true, 106 }) 107 c.Assert(err, jc.ErrorIsNil) 108 err = s.State.SetVolumeInfo(names.NewVolumeTag("2"), state.VolumeInfo{ 109 HardwareId: "456", 110 VolumeId: "def", 111 Size: 4096, 112 }) 113 c.Assert(err, jc.ErrorIsNil) 114 115 // Make a machine without storage for tests to use. 116 s.factory.MakeMachine(c, nil) 117 118 // Make an unprovisioned machine with storage for tests to use. 119 // TODO(axw) extend testing/factory to allow creating unprovisioned 120 // machines. 121 _, err = s.State.AddOneMachine(state.MachineTemplate{ 122 Series: "quantal", 123 Jobs: []state.MachineJob{state.JobHostUnits}, 124 Volumes: []state.MachineVolumeParams{ 125 {Volume: state.VolumeParams{Pool: "environscoped", Size: 2048}}, 126 }, 127 }) 128 c.Assert(err, jc.ErrorIsNil) 129 } 130 131 func (s *provisionerSuite) setupFilesystems(c *gc.C) { 132 s.factory.MakeMachine(c, &factory.MachineParams{ 133 InstanceId: instance.Id("inst-id"), 134 Filesystems: []state.MachineFilesystemParams{{ 135 Filesystem: state.FilesystemParams{Pool: "machinescoped", Size: 1024}, 136 Attachment: state.FilesystemAttachmentParams{ 137 Location: "/srv", 138 ReadOnly: true, 139 }, 140 }, { 141 Filesystem: state.FilesystemParams{Pool: "environscoped", Size: 2048}, 142 }, { 143 Filesystem: state.FilesystemParams{Pool: "environscoped", Size: 4096}, 144 }}, 145 }) 146 147 // Only provision the first and third filesystems. 148 err := s.State.SetFilesystemInfo(names.NewFilesystemTag("0/0"), state.FilesystemInfo{ 149 FilesystemId: "abc", 150 Size: 1024, 151 }) 152 c.Assert(err, jc.ErrorIsNil) 153 err = s.State.SetFilesystemInfo(names.NewFilesystemTag("2"), state.FilesystemInfo{ 154 FilesystemId: "def", 155 Size: 4096, 156 }) 157 c.Assert(err, jc.ErrorIsNil) 158 159 // Make a machine without storage for tests to use. 160 s.factory.MakeMachine(c, nil) 161 162 // Make an unprovisioned machine with storage for tests to use. 163 // TODO(axw) extend testing/factory to allow creating unprovisioned 164 // machines. 165 _, err = s.State.AddOneMachine(state.MachineTemplate{ 166 Series: "quantal", 167 Jobs: []state.MachineJob{state.JobHostUnits}, 168 Filesystems: []state.MachineFilesystemParams{{ 169 Filesystem: state.FilesystemParams{Pool: "environscoped", Size: 2048}, 170 }}, 171 }) 172 c.Assert(err, jc.ErrorIsNil) 173 } 174 175 func (s *provisionerSuite) TestVolumesMachine(c *gc.C) { 176 s.setupVolumes(c) 177 s.authorizer.EnvironManager = false 178 179 results, err := s.api.Volumes(params.Entities{ 180 Entities: []params.Entity{{"volume-0-0"}, {"volume-1"}, {"volume-42"}}, 181 }) 182 c.Assert(err, jc.ErrorIsNil) 183 c.Assert(results, gc.DeepEquals, params.VolumeResults{ 184 Results: []params.VolumeResult{ 185 {Result: params.Volume{ 186 VolumeTag: "volume-0-0", 187 Info: params.VolumeInfo{ 188 VolumeId: "abc", 189 HardwareId: "123", 190 Size: 1024, 191 Persistent: true, 192 }, 193 }}, 194 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 195 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 196 }, 197 }) 198 } 199 200 func (s *provisionerSuite) TestVolumesEnviron(c *gc.C) { 201 s.setupVolumes(c) 202 s.authorizer.Tag = names.NewMachineTag("2") // neither 0 nor 1 203 204 results, err := s.api.Volumes(params.Entities{ 205 Entities: []params.Entity{ 206 {"volume-0-0"}, 207 {"volume-1"}, 208 {"volume-2"}, 209 {"volume-42"}, 210 }, 211 }) 212 c.Assert(err, jc.ErrorIsNil) 213 c.Assert(results, gc.DeepEquals, params.VolumeResults{ 214 Results: []params.VolumeResult{ 215 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 216 {Error: common.ServerError(errors.NotProvisionedf(`volume "1"`))}, 217 {Result: params.Volume{ 218 VolumeTag: "volume-2", 219 Info: params.VolumeInfo{ 220 VolumeId: "def", 221 HardwareId: "456", 222 Size: 4096, 223 }, 224 }}, 225 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 226 }, 227 }) 228 } 229 230 func (s *provisionerSuite) TestVolumesEmptyArgs(c *gc.C) { 231 results, err := s.api.Volumes(params.Entities{}) 232 c.Assert(err, jc.ErrorIsNil) 233 c.Assert(results.Results, gc.HasLen, 0) 234 } 235 236 func (s *provisionerSuite) TestFilesystems(c *gc.C) { 237 s.setupFilesystems(c) 238 s.authorizer.Tag = names.NewMachineTag("2") // neither 0 nor 1 239 240 results, err := s.api.Filesystems(params.Entities{ 241 Entities: []params.Entity{ 242 {"filesystem-0-0"}, 243 {"filesystem-1"}, 244 {"filesystem-2"}, 245 {"filesystem-42"}, 246 }, 247 }) 248 c.Assert(err, jc.ErrorIsNil) 249 c.Assert(results, jc.DeepEquals, params.FilesystemResults{ 250 Results: []params.FilesystemResult{ 251 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 252 {Error: common.ServerError(errors.NotProvisionedf(`filesystem "1"`))}, 253 {Result: params.Filesystem{ 254 FilesystemTag: "filesystem-2", 255 Info: params.FilesystemInfo{ 256 FilesystemId: "def", 257 Size: 4096, 258 }, 259 }}, 260 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 261 }, 262 }) 263 } 264 265 func (s *provisionerSuite) TestVolumeAttachments(c *gc.C) { 266 s.setupVolumes(c) 267 s.authorizer.EnvironManager = false 268 269 err := s.State.SetVolumeAttachmentInfo( 270 names.NewMachineTag("0"), 271 names.NewVolumeTag("0/0"), 272 state.VolumeAttachmentInfo{DeviceName: "xvdf1"}, 273 ) 274 c.Assert(err, jc.ErrorIsNil) 275 276 results, err := s.api.VolumeAttachments(params.MachineStorageIds{ 277 Ids: []params.MachineStorageId{{ 278 MachineTag: "machine-0", 279 AttachmentTag: "volume-0-0", 280 }, { 281 MachineTag: "machine-0", 282 AttachmentTag: "volume-2", // volume attachment not provisioned 283 }, { 284 MachineTag: "machine-0", 285 AttachmentTag: "volume-42", 286 }}, 287 }) 288 c.Assert(err, jc.ErrorIsNil) 289 c.Assert(results, jc.DeepEquals, params.VolumeAttachmentResults{ 290 Results: []params.VolumeAttachmentResult{ 291 {Result: params.VolumeAttachment{ 292 VolumeTag: "volume-0-0", 293 MachineTag: "machine-0", 294 Info: params.VolumeAttachmentInfo{ 295 DeviceName: "xvdf1", 296 }, 297 }}, 298 {Error: ¶ms.Error{ 299 Code: params.CodeNotProvisioned, 300 Message: `volume attachment "2" on "0" not provisioned`, 301 }}, 302 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 303 }, 304 }) 305 } 306 307 func (s *provisionerSuite) TestFilesystemAttachments(c *gc.C) { 308 s.setupFilesystems(c) 309 s.authorizer.EnvironManager = false 310 311 err := s.State.SetFilesystemAttachmentInfo( 312 names.NewMachineTag("0"), 313 names.NewFilesystemTag("0/0"), 314 state.FilesystemAttachmentInfo{ 315 MountPoint: "/srv", 316 ReadOnly: true, 317 }, 318 ) 319 c.Assert(err, jc.ErrorIsNil) 320 321 results, err := s.api.FilesystemAttachments(params.MachineStorageIds{ 322 Ids: []params.MachineStorageId{{ 323 MachineTag: "machine-0", 324 AttachmentTag: "filesystem-0-0", 325 }, { 326 MachineTag: "machine-0", 327 AttachmentTag: "filesystem-2", // filesystem attachment not provisioned 328 }, { 329 MachineTag: "machine-0", 330 AttachmentTag: "filesystem-42", 331 }}, 332 }) 333 c.Assert(err, jc.ErrorIsNil) 334 c.Assert(results, jc.DeepEquals, params.FilesystemAttachmentResults{ 335 Results: []params.FilesystemAttachmentResult{ 336 {Result: params.FilesystemAttachment{ 337 FilesystemTag: "filesystem-0-0", 338 MachineTag: "machine-0", 339 Info: params.FilesystemAttachmentInfo{ 340 MountPoint: "/srv", 341 ReadOnly: true, 342 }, 343 }}, 344 {Error: ¶ms.Error{ 345 Code: params.CodeNotProvisioned, 346 Message: `filesystem attachment "2" on "0" not provisioned`, 347 }}, 348 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 349 }, 350 }) 351 } 352 353 func (s *provisionerSuite) TestVolumeParams(c *gc.C) { 354 s.setupVolumes(c) 355 results, err := s.api.VolumeParams(params.Entities{ 356 Entities: []params.Entity{ 357 {"volume-0-0"}, 358 {"volume-1"}, 359 {"volume-3"}, 360 {"volume-42"}, 361 }, 362 }) 363 c.Assert(err, jc.ErrorIsNil) 364 c.Assert(results, jc.DeepEquals, params.VolumeParamsResults{ 365 Results: []params.VolumeParamsResult{ 366 {Result: params.VolumeParams{ 367 VolumeTag: "volume-0-0", 368 Size: 1024, 369 Provider: "machinescoped", 370 Tags: map[string]string{ 371 tags.JujuEnv: testing.EnvironmentTag.Id(), 372 }, 373 Attachment: ¶ms.VolumeAttachmentParams{ 374 MachineTag: "machine-0", 375 VolumeTag: "volume-0-0", 376 Provider: "machinescoped", 377 InstanceId: "inst-id", 378 }, 379 }}, 380 {Result: params.VolumeParams{ 381 VolumeTag: "volume-1", 382 Size: 2048, 383 Provider: "environscoped", 384 Tags: map[string]string{ 385 tags.JujuEnv: testing.EnvironmentTag.Id(), 386 }, 387 Attachment: ¶ms.VolumeAttachmentParams{ 388 MachineTag: "machine-0", 389 VolumeTag: "volume-1", 390 Provider: "environscoped", 391 InstanceId: "inst-id", 392 }, 393 }}, 394 {Result: params.VolumeParams{ 395 VolumeTag: "volume-3", 396 Size: 4096, 397 Provider: "environscoped", 398 Tags: map[string]string{ 399 tags.JujuEnv: testing.EnvironmentTag.Id(), 400 }, 401 Attachment: ¶ms.VolumeAttachmentParams{ 402 MachineTag: "machine-0", 403 VolumeTag: "volume-3", 404 Provider: "environscoped", 405 InstanceId: "inst-id", 406 ReadOnly: true, 407 }, 408 }}, 409 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 410 }, 411 }) 412 } 413 414 func (s *provisionerSuite) TestVolumeParamsEmptyArgs(c *gc.C) { 415 results, err := s.api.VolumeParams(params.Entities{}) 416 c.Assert(err, jc.ErrorIsNil) 417 c.Assert(results.Results, gc.HasLen, 0) 418 } 419 420 func (s *provisionerSuite) TestFilesystemParams(c *gc.C) { 421 s.setupFilesystems(c) 422 results, err := s.api.FilesystemParams(params.Entities{ 423 Entities: []params.Entity{{"filesystem-0-0"}, {"filesystem-1"}, {"filesystem-42"}}, 424 }) 425 c.Assert(err, jc.ErrorIsNil) 426 c.Assert(results, jc.DeepEquals, params.FilesystemParamsResults{ 427 Results: []params.FilesystemParamsResult{ 428 {Result: params.FilesystemParams{ 429 FilesystemTag: "filesystem-0-0", 430 Size: 1024, 431 Provider: "machinescoped", 432 Tags: map[string]string{ 433 tags.JujuEnv: testing.EnvironmentTag.Id(), 434 }, 435 }}, 436 {Result: params.FilesystemParams{ 437 FilesystemTag: "filesystem-1", 438 Size: 2048, 439 Provider: "environscoped", 440 Tags: map[string]string{ 441 tags.JujuEnv: testing.EnvironmentTag.Id(), 442 }, 443 }}, 444 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 445 }, 446 }) 447 } 448 449 func (s *provisionerSuite) TestVolumeAttachmentParams(c *gc.C) { 450 s.setupVolumes(c) 451 452 err := s.State.SetVolumeInfo(names.NewVolumeTag("3"), state.VolumeInfo{ 453 HardwareId: "123", 454 VolumeId: "xyz", 455 Size: 1024, 456 }) 457 c.Assert(err, jc.ErrorIsNil) 458 459 err = s.State.SetVolumeAttachmentInfo( 460 names.NewMachineTag("0"), 461 names.NewVolumeTag("3"), 462 state.VolumeAttachmentInfo{ 463 DeviceName: "xvdf1", 464 ReadOnly: true, 465 }, 466 ) 467 c.Assert(err, jc.ErrorIsNil) 468 469 results, err := s.api.VolumeAttachmentParams(params.MachineStorageIds{ 470 Ids: []params.MachineStorageId{{ 471 MachineTag: "machine-0", 472 AttachmentTag: "volume-0-0", 473 }, { 474 MachineTag: "machine-0", 475 AttachmentTag: "volume-1", 476 }, { 477 MachineTag: "machine-0", 478 AttachmentTag: "volume-3", 479 }, { 480 MachineTag: "machine-2", 481 AttachmentTag: "volume-4", 482 }, { 483 MachineTag: "machine-0", 484 AttachmentTag: "volume-42", 485 }}, 486 }) 487 c.Assert(err, jc.ErrorIsNil) 488 c.Assert(results, jc.DeepEquals, params.VolumeAttachmentParamsResults{ 489 Results: []params.VolumeAttachmentParamsResult{ 490 {Result: params.VolumeAttachmentParams{ 491 MachineTag: "machine-0", 492 VolumeTag: "volume-0-0", 493 InstanceId: "inst-id", 494 VolumeId: "abc", 495 Provider: "machinescoped", 496 }}, 497 {Result: params.VolumeAttachmentParams{ 498 MachineTag: "machine-0", 499 VolumeTag: "volume-1", 500 InstanceId: "inst-id", 501 Provider: "environscoped", 502 }}, 503 {Result: params.VolumeAttachmentParams{ 504 MachineTag: "machine-0", 505 VolumeTag: "volume-3", 506 InstanceId: "inst-id", 507 VolumeId: "xyz", 508 Provider: "environscoped", 509 ReadOnly: true, 510 }}, 511 {Result: params.VolumeAttachmentParams{ 512 MachineTag: "machine-2", 513 VolumeTag: "volume-4", 514 Provider: "environscoped", 515 }}, 516 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 517 }, 518 }) 519 } 520 521 func (s *provisionerSuite) TestFilesystemAttachmentParams(c *gc.C) { 522 s.setupFilesystems(c) 523 524 err := s.State.SetFilesystemInfo(names.NewFilesystemTag("1"), state.FilesystemInfo{ 525 FilesystemId: "fsid", 526 Size: 1024, 527 }) 528 c.Assert(err, jc.ErrorIsNil) 529 530 err = s.State.SetFilesystemAttachmentInfo( 531 names.NewMachineTag("0"), 532 names.NewFilesystemTag("1"), 533 state.FilesystemAttachmentInfo{ 534 MountPoint: "/in/the/place", 535 }, 536 ) 537 c.Assert(err, jc.ErrorIsNil) 538 539 results, err := s.api.FilesystemAttachmentParams(params.MachineStorageIds{ 540 Ids: []params.MachineStorageId{{ 541 MachineTag: "machine-0", 542 AttachmentTag: "filesystem-0-0", 543 }, { 544 MachineTag: "machine-0", 545 AttachmentTag: "filesystem-1", 546 }, { 547 MachineTag: "machine-2", 548 AttachmentTag: "filesystem-3", 549 }, { 550 MachineTag: "machine-0", 551 AttachmentTag: "filesystem-42", 552 }}, 553 }) 554 c.Assert(err, jc.ErrorIsNil) 555 c.Assert(results, jc.DeepEquals, params.FilesystemAttachmentParamsResults{ 556 Results: []params.FilesystemAttachmentParamsResult{ 557 {Result: params.FilesystemAttachmentParams{ 558 MachineTag: "machine-0", 559 FilesystemTag: "filesystem-0-0", 560 InstanceId: "inst-id", 561 FilesystemId: "abc", 562 Provider: "machinescoped", 563 MountPoint: "/srv", 564 ReadOnly: true, 565 }}, 566 {Result: params.FilesystemAttachmentParams{ 567 MachineTag: "machine-0", 568 FilesystemTag: "filesystem-1", 569 InstanceId: "inst-id", 570 FilesystemId: "fsid", 571 Provider: "environscoped", 572 MountPoint: "/in/the/place", 573 }}, 574 {Result: params.FilesystemAttachmentParams{ 575 MachineTag: "machine-2", 576 FilesystemTag: "filesystem-3", 577 Provider: "environscoped", 578 }}, 579 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 580 }, 581 }) 582 } 583 584 func (s *provisionerSuite) TestSetVolumeAttachmentInfo(c *gc.C) { 585 s.setupVolumes(c) 586 587 err := s.State.SetVolumeInfo(names.NewVolumeTag("4"), state.VolumeInfo{ 588 VolumeId: "whatever", 589 Size: 1024, 590 }) 591 c.Assert(err, jc.ErrorIsNil) 592 593 results, err := s.api.SetVolumeAttachmentInfo(params.VolumeAttachments{ 594 VolumeAttachments: []params.VolumeAttachment{{ 595 MachineTag: "machine-0", 596 VolumeTag: "volume-0-0", 597 Info: params.VolumeAttachmentInfo{ 598 DeviceName: "sda", 599 ReadOnly: true, 600 }, 601 }, { 602 MachineTag: "machine-0", 603 VolumeTag: "volume-1", 604 Info: params.VolumeAttachmentInfo{ 605 DeviceName: "sdb", 606 }, 607 }, { 608 MachineTag: "machine-2", 609 VolumeTag: "volume-4", 610 Info: params.VolumeAttachmentInfo{ 611 DeviceName: "sdc", 612 }, 613 }, { 614 MachineTag: "machine-0", 615 VolumeTag: "volume-42", 616 Info: params.VolumeAttachmentInfo{ 617 DeviceName: "sdd", 618 }, 619 }}, 620 }) 621 c.Assert(err, jc.ErrorIsNil) 622 c.Assert(results, jc.DeepEquals, params.ErrorResults{ 623 Results: []params.ErrorResult{ 624 {}, 625 {Error: ¶ms.Error{`cannot set info for volume attachment 1:0: volume "1" not provisioned`, "not provisioned"}}, 626 {Error: ¶ms.Error{`cannot set info for volume attachment 4:2: machine 2 not provisioned`, "not provisioned"}}, 627 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 628 }, 629 }) 630 } 631 632 func (s *provisionerSuite) TestSetFilesystemAttachmentInfo(c *gc.C) { 633 s.setupFilesystems(c) 634 635 err := s.State.SetFilesystemInfo(names.NewFilesystemTag("3"), state.FilesystemInfo{ 636 FilesystemId: "whatever", 637 Size: 1024, 638 }) 639 c.Assert(err, jc.ErrorIsNil) 640 641 results, err := s.api.SetFilesystemAttachmentInfo(params.FilesystemAttachments{ 642 FilesystemAttachments: []params.FilesystemAttachment{{ 643 MachineTag: "machine-0", 644 FilesystemTag: "filesystem-0-0", 645 Info: params.FilesystemAttachmentInfo{ 646 MountPoint: "/srv/a", 647 ReadOnly: true, 648 }, 649 }, { 650 MachineTag: "machine-0", 651 FilesystemTag: "filesystem-1", 652 Info: params.FilesystemAttachmentInfo{ 653 MountPoint: "/srv/b", 654 }, 655 }, { 656 MachineTag: "machine-2", 657 FilesystemTag: "filesystem-3", 658 Info: params.FilesystemAttachmentInfo{ 659 MountPoint: "/srv/c", 660 }, 661 }, { 662 MachineTag: "machine-0", 663 FilesystemTag: "filesystem-42", 664 Info: params.FilesystemAttachmentInfo{ 665 MountPoint: "/srv/d", 666 }, 667 }}, 668 }) 669 c.Assert(err, jc.ErrorIsNil) 670 c.Assert(results, jc.DeepEquals, params.ErrorResults{ 671 Results: []params.ErrorResult{ 672 {}, 673 {Error: ¶ms.Error{`cannot set info for filesystem attachment 1:0: filesystem "1" not provisioned`, "not provisioned"}}, 674 {Error: ¶ms.Error{`cannot set info for filesystem attachment 3:2: machine 2 not provisioned`, "not provisioned"}}, 675 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 676 }, 677 }) 678 } 679 680 func (s *provisionerSuite) TestWatchVolumes(c *gc.C) { 681 s.setupVolumes(c) 682 s.factory.MakeMachine(c, nil) 683 c.Assert(s.resources.Count(), gc.Equals, 0) 684 685 args := params.Entities{Entities: []params.Entity{ 686 {"machine-0"}, 687 {s.State.EnvironTag().String()}, 688 {"environ-adb650da-b77b-4ee8-9cbb-d57a9a592847"}, 689 {"machine-1"}, 690 {"machine-42"}}, 691 } 692 result, err := s.api.WatchVolumes(args) 693 c.Assert(err, jc.ErrorIsNil) 694 sort.Strings(result.Results[1].Changes) 695 c.Assert(result, jc.DeepEquals, params.StringsWatchResults{ 696 Results: []params.StringsWatchResult{ 697 {StringsWatcherId: "1", Changes: []string{"0/0"}}, 698 {StringsWatcherId: "2", Changes: []string{"1", "2", "3", "4"}}, 699 {Error: apiservertesting.ErrUnauthorized}, 700 {Error: apiservertesting.ErrUnauthorized}, 701 {Error: apiservertesting.ErrUnauthorized}, 702 }, 703 }) 704 705 // Verify the resources were registered and stop them when done. 706 c.Assert(s.resources.Count(), gc.Equals, 2) 707 v0Watcher := s.resources.Get("1") 708 defer statetesting.AssertStop(c, v0Watcher) 709 v1Watcher := s.resources.Get("2") 710 defer statetesting.AssertStop(c, v1Watcher) 711 712 // Check that the Watch has consumed the initial events ("returned" in 713 // the Watch call) 714 wc := statetesting.NewStringsWatcherC(c, s.State, v0Watcher.(state.StringsWatcher)) 715 wc.AssertNoChange() 716 wc = statetesting.NewStringsWatcherC(c, s.State, v1Watcher.(state.StringsWatcher)) 717 wc.AssertNoChange() 718 } 719 720 func (s *provisionerSuite) TestWatchVolumeAttachments(c *gc.C) { 721 s.setupVolumes(c) 722 s.factory.MakeMachine(c, nil) 723 c.Assert(s.resources.Count(), gc.Equals, 0) 724 725 args := params.Entities{Entities: []params.Entity{ 726 {"machine-0"}, 727 {s.State.EnvironTag().String()}, 728 {"environ-adb650da-b77b-4ee8-9cbb-d57a9a592847"}, 729 {"machine-1"}, 730 {"machine-42"}}, 731 } 732 result, err := s.api.WatchVolumeAttachments(args) 733 c.Assert(err, jc.ErrorIsNil) 734 sort.Sort(byMachineAndEntity(result.Results[0].Changes)) 735 sort.Sort(byMachineAndEntity(result.Results[1].Changes)) 736 c.Assert(result, jc.DeepEquals, params.MachineStorageIdsWatchResults{ 737 Results: []params.MachineStorageIdsWatchResult{ 738 { 739 MachineStorageIdsWatcherId: "1", 740 Changes: []params.MachineStorageId{{ 741 MachineTag: "machine-0", 742 AttachmentTag: "volume-0-0", 743 }}, 744 }, 745 { 746 MachineStorageIdsWatcherId: "2", 747 Changes: []params.MachineStorageId{{ 748 MachineTag: "machine-0", 749 AttachmentTag: "volume-1", 750 }, { 751 MachineTag: "machine-0", 752 AttachmentTag: "volume-2", 753 }, { 754 MachineTag: "machine-0", 755 AttachmentTag: "volume-3", 756 }, { 757 MachineTag: "machine-2", 758 AttachmentTag: "volume-4", 759 }}, 760 }, 761 {Error: apiservertesting.ErrUnauthorized}, 762 {Error: apiservertesting.ErrUnauthorized}, 763 {Error: apiservertesting.ErrUnauthorized}, 764 }, 765 }) 766 767 // Verify the resources were registered and stop them when done. 768 c.Assert(s.resources.Count(), gc.Equals, 2) 769 v0Watcher := s.resources.Get("1") 770 defer statetesting.AssertStop(c, v0Watcher) 771 v1Watcher := s.resources.Get("2") 772 defer statetesting.AssertStop(c, v1Watcher) 773 774 // Check that the Watch has consumed the initial events ("returned" in 775 // the Watch call) 776 wc := statetesting.NewStringsWatcherC(c, s.State, v0Watcher.(state.StringsWatcher)) 777 wc.AssertNoChange() 778 wc = statetesting.NewStringsWatcherC(c, s.State, v1Watcher.(state.StringsWatcher)) 779 wc.AssertNoChange() 780 } 781 782 func (s *provisionerSuite) TestWatchFilesystems(c *gc.C) { 783 s.setupFilesystems(c) 784 c.Assert(s.resources.Count(), gc.Equals, 0) 785 786 args := params.Entities{Entities: []params.Entity{ 787 {"machine-0"}, 788 {s.State.EnvironTag().String()}, 789 {"environ-adb650da-b77b-4ee8-9cbb-d57a9a592847"}, 790 {"machine-1"}, 791 {"machine-42"}}, 792 } 793 result, err := s.api.WatchFilesystems(args) 794 c.Assert(err, jc.ErrorIsNil) 795 sort.Strings(result.Results[1].Changes) 796 c.Assert(result, jc.DeepEquals, params.StringsWatchResults{ 797 Results: []params.StringsWatchResult{ 798 { 799 StringsWatcherId: "1", 800 Changes: []string{"0/0"}, 801 }, 802 { 803 StringsWatcherId: "2", 804 Changes: []string{"1", "2", "3"}, 805 }, 806 {Error: apiservertesting.ErrUnauthorized}, 807 {Error: apiservertesting.ErrUnauthorized}, 808 {Error: apiservertesting.ErrUnauthorized}, 809 }, 810 }) 811 812 // Verify the resources were registered and stop them when done. 813 c.Assert(s.resources.Count(), gc.Equals, 2) 814 v0Watcher := s.resources.Get("1") 815 defer statetesting.AssertStop(c, v0Watcher) 816 v1Watcher := s.resources.Get("2") 817 defer statetesting.AssertStop(c, v1Watcher) 818 819 // Check that the Watch has consumed the initial events ("returned" in 820 // the Watch call) 821 wc := statetesting.NewStringsWatcherC(c, s.State, v0Watcher.(state.StringsWatcher)) 822 wc.AssertNoChange() 823 wc = statetesting.NewStringsWatcherC(c, s.State, v1Watcher.(state.StringsWatcher)) 824 wc.AssertNoChange() 825 } 826 827 func (s *provisionerSuite) TestWatchFilesystemAttachments(c *gc.C) { 828 s.setupFilesystems(c) 829 c.Assert(s.resources.Count(), gc.Equals, 0) 830 831 args := params.Entities{Entities: []params.Entity{ 832 {"machine-0"}, 833 {s.State.EnvironTag().String()}, 834 {"environ-adb650da-b77b-4ee8-9cbb-d57a9a592847"}, 835 {"machine-1"}, 836 {"machine-42"}}, 837 } 838 result, err := s.api.WatchFilesystemAttachments(args) 839 c.Assert(err, jc.ErrorIsNil) 840 sort.Sort(byMachineAndEntity(result.Results[0].Changes)) 841 sort.Sort(byMachineAndEntity(result.Results[1].Changes)) 842 c.Assert(result, jc.DeepEquals, params.MachineStorageIdsWatchResults{ 843 Results: []params.MachineStorageIdsWatchResult{ 844 { 845 MachineStorageIdsWatcherId: "1", 846 Changes: []params.MachineStorageId{{ 847 MachineTag: "machine-0", 848 AttachmentTag: "filesystem-0-0", 849 }}, 850 }, 851 { 852 MachineStorageIdsWatcherId: "2", 853 Changes: []params.MachineStorageId{{ 854 MachineTag: "machine-0", 855 AttachmentTag: "filesystem-1", 856 }, { 857 MachineTag: "machine-0", 858 AttachmentTag: "filesystem-2", 859 }, { 860 MachineTag: "machine-2", 861 AttachmentTag: "filesystem-3", 862 }}, 863 }, 864 {Error: apiservertesting.ErrUnauthorized}, 865 {Error: apiservertesting.ErrUnauthorized}, 866 {Error: apiservertesting.ErrUnauthorized}, 867 }, 868 }) 869 870 // Verify the resources were registered and stop them when done. 871 c.Assert(s.resources.Count(), gc.Equals, 2) 872 v0Watcher := s.resources.Get("1") 873 defer statetesting.AssertStop(c, v0Watcher) 874 v1Watcher := s.resources.Get("2") 875 defer statetesting.AssertStop(c, v1Watcher) 876 877 // Check that the Watch has consumed the initial events ("returned" in 878 // the Watch call) 879 wc := statetesting.NewStringsWatcherC(c, s.State, v0Watcher.(state.StringsWatcher)) 880 wc.AssertNoChange() 881 wc = statetesting.NewStringsWatcherC(c, s.State, v1Watcher.(state.StringsWatcher)) 882 wc.AssertNoChange() 883 } 884 885 func (s *provisionerSuite) TestWatchBlockDevices(c *gc.C) { 886 s.factory.MakeMachine(c, nil) 887 c.Assert(s.resources.Count(), gc.Equals, 0) 888 889 args := params.Entities{Entities: []params.Entity{ 890 {"machine-0"}, 891 {"service-mysql"}, 892 {"machine-1"}, 893 {"machine-42"}}, 894 } 895 results, err := s.api.WatchBlockDevices(args) 896 c.Assert(err, jc.ErrorIsNil) 897 c.Assert(results, jc.DeepEquals, params.NotifyWatchResults{ 898 Results: []params.NotifyWatchResult{ 899 {NotifyWatcherId: "1"}, 900 {Error: ¶ms.Error{Message: `"service-mysql" is not a valid machine tag`}}, 901 {Error: apiservertesting.ErrUnauthorized}, 902 {Error: apiservertesting.ErrUnauthorized}, 903 }, 904 }) 905 906 // Verify the resources were registered and stop them when done. 907 c.Assert(s.resources.Count(), gc.Equals, 1) 908 watcher := s.resources.Get("1") 909 defer statetesting.AssertStop(c, watcher) 910 911 // Check that the Watch has consumed the initial event. 912 wc := statetesting.NewNotifyWatcherC(c, s.State, watcher.(state.NotifyWatcher)) 913 wc.AssertNoChange() 914 915 m, err := s.State.Machine("0") 916 c.Assert(err, jc.ErrorIsNil) 917 err = m.SetMachineBlockDevices(state.BlockDeviceInfo{ 918 DeviceName: "sda", 919 Size: 123, 920 }) 921 c.Assert(err, jc.ErrorIsNil) 922 wc.AssertOneChange() 923 } 924 925 func (s *provisionerSuite) TestVolumeBlockDevices(c *gc.C) { 926 s.setupVolumes(c) 927 s.factory.MakeMachine(c, nil) 928 929 err := s.State.SetVolumeAttachmentInfo( 930 names.NewMachineTag("0"), 931 names.NewVolumeTag("0/0"), 932 state.VolumeAttachmentInfo{}, 933 ) 934 c.Assert(err, jc.ErrorIsNil) 935 936 machine0, err := s.State.Machine("0") 937 c.Assert(err, jc.ErrorIsNil) 938 err = machine0.SetMachineBlockDevices(state.BlockDeviceInfo{ 939 DeviceName: "sda", 940 Size: 123, 941 HardwareId: "123", // matches volume-0/0 942 }) 943 c.Assert(err, jc.ErrorIsNil) 944 945 args := params.MachineStorageIds{Ids: []params.MachineStorageId{ 946 {MachineTag: "machine-0", AttachmentTag: "volume-0-0"}, 947 {MachineTag: "machine-0", AttachmentTag: "volume-0-1"}, 948 {MachineTag: "machine-0", AttachmentTag: "volume-0-2"}, 949 {MachineTag: "machine-1", AttachmentTag: "volume-1"}, 950 {MachineTag: "machine-42", AttachmentTag: "volume-42"}, 951 {MachineTag: "service-mysql", AttachmentTag: "volume-1"}, 952 }} 953 results, err := s.api.VolumeBlockDevices(args) 954 c.Assert(err, jc.ErrorIsNil) 955 c.Assert(results, jc.DeepEquals, params.BlockDeviceResults{ 956 Results: []params.BlockDeviceResult{ 957 {Result: storage.BlockDevice{ 958 DeviceName: "sda", 959 Size: 123, 960 HardwareId: "123", 961 }}, 962 {Error: apiservertesting.ErrUnauthorized}, 963 {Error: apiservertesting.ErrUnauthorized}, 964 {Error: apiservertesting.ErrUnauthorized}, 965 {Error: apiservertesting.ErrUnauthorized}, 966 {Error: ¶ms.Error{Message: `"service-mysql" is not a valid machine tag`}}, 967 }, 968 }) 969 } 970 971 func (s *provisionerSuite) TestLife(c *gc.C) { 972 s.setupVolumes(c) 973 args := params.Entities{Entities: []params.Entity{{"volume-0-0"}, {"volume-1"}, {"volume-42"}}} 974 result, err := s.api.Life(args) 975 c.Assert(err, jc.ErrorIsNil) 976 c.Assert(result, gc.DeepEquals, params.LifeResults{ 977 Results: []params.LifeResult{ 978 {Life: params.Alive}, 979 {Life: params.Alive}, 980 {Error: common.ServerError(errors.NotFoundf(`volume "42"`))}, 981 }, 982 }) 983 } 984 985 func (s *provisionerSuite) TestAttachmentLife(c *gc.C) { 986 s.setupVolumes(c) 987 988 // TODO(axw) test filesystem attachment life 989 // TODO(axw) test Dying 990 991 results, err := s.api.AttachmentLife(params.MachineStorageIds{ 992 Ids: []params.MachineStorageId{{ 993 MachineTag: "machine-0", 994 AttachmentTag: "volume-0-0", 995 }, { 996 MachineTag: "machine-0", 997 AttachmentTag: "volume-1", 998 }, { 999 MachineTag: "machine-2", 1000 AttachmentTag: "volume-4", 1001 }, { 1002 MachineTag: "machine-0", 1003 AttachmentTag: "volume-42", 1004 }}, 1005 }) 1006 c.Assert(err, jc.ErrorIsNil) 1007 c.Assert(results, jc.DeepEquals, params.LifeResults{ 1008 Results: []params.LifeResult{ 1009 {Life: params.Alive}, 1010 {Life: params.Alive}, 1011 {Life: params.Alive}, 1012 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1013 }, 1014 }) 1015 } 1016 1017 func (s *provisionerSuite) TestEnsureDead(c *gc.C) { 1018 s.setupVolumes(c) 1019 args := params.Entities{Entities: []params.Entity{{"volume-0-0"}, {"volume-1"}, {"volume-42"}}} 1020 result, err := s.api.EnsureDead(args) 1021 c.Assert(err, jc.ErrorIsNil) 1022 // TODO(wallyworld) - this test will be updated when EnsureDead is supported 1023 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1024 Results: []params.ErrorResult{ 1025 {Error: common.ServerError(common.NotSupportedError(names.NewVolumeTag("0/0"), "ensuring death"))}, 1026 {Error: common.ServerError(common.NotSupportedError(names.NewVolumeTag("1"), "ensuring death"))}, 1027 {Error: common.ServerError(errors.NotFoundf(`volume "42"`))}, 1028 }, 1029 }) 1030 } 1031 1032 func (s *provisionerSuite) TestWatchForEnvironConfigChanges(c *gc.C) { 1033 result, err := s.api.WatchForEnvironConfigChanges() 1034 c.Assert(err, jc.ErrorIsNil) 1035 c.Assert(result.NotifyWatcherId, gc.Equals, "1") 1036 1037 // Verify the resource was registered and stop it when done. 1038 c.Assert(s.resources.Count(), gc.Equals, 1) 1039 watcher := s.resources.Get("1") 1040 defer statetesting.AssertStop(c, watcher) 1041 1042 // Check that the Watch has consumed the initial events ("returned" in 1043 // the Watch call) 1044 wc := statetesting.NewNotifyWatcherC(c, s.State, watcher.(state.NotifyWatcher)) 1045 wc.AssertNoChange() 1046 1047 // Updating config should trigger the watcher. 1048 err = s.State.UpdateEnvironConfig(map[string]interface{}{"what": "ever"}, nil, nil) 1049 c.Assert(err, jc.ErrorIsNil) 1050 wc.AssertOneChange() 1051 } 1052 1053 func (s *provisionerSuite) TestEnvironConfig(c *gc.C) { 1054 stateEnvironConfig, err := s.State.EnvironConfig() 1055 c.Assert(err, jc.ErrorIsNil) 1056 1057 result, err := s.api.EnvironConfig() 1058 c.Assert(err, jc.ErrorIsNil) 1059 c.Assert(result.Config, jc.DeepEquals, params.EnvironConfig(stateEnvironConfig.AllAttrs())) 1060 } 1061 1062 func (s *provisionerSuite) TestRemoveVolumesEnvironManager(c *gc.C) { 1063 s.setupVolumes(c) 1064 args := params.Entities{Entities: []params.Entity{ 1065 {"volume-1-0"}, {"volume-1"}, {"volume-2"}, {"volume-42"}, 1066 {"volume-invalid"}, {"machine-0"}, 1067 }} 1068 1069 err := s.State.DetachVolume(names.NewMachineTag("0"), names.NewVolumeTag("1")) 1070 c.Assert(err, jc.ErrorIsNil) 1071 err = s.State.RemoveVolumeAttachment(names.NewMachineTag("0"), names.NewVolumeTag("1")) 1072 c.Assert(err, jc.ErrorIsNil) 1073 err = s.State.DestroyVolume(names.NewVolumeTag("1")) 1074 c.Assert(err, jc.ErrorIsNil) 1075 1076 result, err := s.api.Remove(args) 1077 c.Assert(err, jc.ErrorIsNil) 1078 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1079 Results: []params.ErrorResult{ 1080 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1081 {Error: nil}, 1082 {Error: ¶ms.Error{Message: "removing volume 2: volume is not dead"}}, 1083 {Error: nil}, 1084 {Error: ¶ms.Error{Message: `"volume-invalid" is not a valid volume tag`}}, 1085 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1086 }, 1087 }) 1088 } 1089 1090 func (s *provisionerSuite) TestRemoveFilesystemsEnvironManager(c *gc.C) { 1091 s.setupFilesystems(c) 1092 args := params.Entities{Entities: []params.Entity{ 1093 {"filesystem-1-0"}, {"filesystem-1"}, {"filesystem-2"}, {"filesystem-42"}, 1094 {"filesystem-invalid"}, {"machine-0"}, 1095 }} 1096 1097 err := s.State.DetachFilesystem(names.NewMachineTag("0"), names.NewFilesystemTag("1")) 1098 c.Assert(err, jc.ErrorIsNil) 1099 err = s.State.RemoveFilesystemAttachment(names.NewMachineTag("0"), names.NewFilesystemTag("1")) 1100 c.Assert(err, jc.ErrorIsNil) 1101 err = s.State.DestroyFilesystem(names.NewFilesystemTag("1")) 1102 c.Assert(err, jc.ErrorIsNil) 1103 1104 result, err := s.api.Remove(args) 1105 c.Assert(err, jc.ErrorIsNil) 1106 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1107 Results: []params.ErrorResult{ 1108 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1109 {Error: nil}, 1110 {Error: ¶ms.Error{Message: "removing filesystem 2: filesystem is not dead"}}, 1111 {Error: nil}, 1112 {Error: ¶ms.Error{Message: `"filesystem-invalid" is not a valid filesystem tag`}}, 1113 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1114 }, 1115 }) 1116 } 1117 1118 func (s *provisionerSuite) TestRemoveVolumesMachineAgent(c *gc.C) { 1119 s.setupVolumes(c) 1120 s.authorizer.EnvironManager = false 1121 args := params.Entities{Entities: []params.Entity{ 1122 {"volume-0-0"}, {"volume-0-42"}, {"volume-42"}, 1123 {"volume-invalid"}, {"machine-0"}, 1124 }} 1125 1126 err := s.State.DetachVolume(names.NewMachineTag("0"), names.NewVolumeTag("0/0")) 1127 c.Assert(err, jc.ErrorIsNil) 1128 err = s.State.RemoveVolumeAttachment(names.NewMachineTag("0"), names.NewVolumeTag("0/0")) 1129 c.Assert(err, jc.ErrorIsNil) 1130 err = s.State.DestroyVolume(names.NewVolumeTag("0/0")) 1131 c.Assert(err, jc.ErrorIsNil) 1132 1133 result, err := s.api.Remove(args) 1134 c.Assert(err, jc.ErrorIsNil) 1135 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1136 Results: []params.ErrorResult{ 1137 {Error: nil}, 1138 {Error: nil}, 1139 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1140 {Error: ¶ms.Error{Message: `"volume-invalid" is not a valid volume tag`}}, 1141 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1142 }, 1143 }) 1144 } 1145 1146 func (s *provisionerSuite) TestRemoveFilesystemsMachineAgent(c *gc.C) { 1147 s.setupFilesystems(c) 1148 s.authorizer.EnvironManager = false 1149 args := params.Entities{Entities: []params.Entity{ 1150 {"filesystem-0-0"}, {"filesystem-0-42"}, {"filesystem-42"}, 1151 {"filesystem-invalid"}, {"machine-0"}, 1152 }} 1153 1154 err := s.State.DetachFilesystem(names.NewMachineTag("0"), names.NewFilesystemTag("0/0")) 1155 c.Assert(err, jc.ErrorIsNil) 1156 err = s.State.RemoveFilesystemAttachment(names.NewMachineTag("0"), names.NewFilesystemTag("0/0")) 1157 c.Assert(err, jc.ErrorIsNil) 1158 err = s.State.DestroyFilesystem(names.NewFilesystemTag("0/0")) 1159 c.Assert(err, jc.ErrorIsNil) 1160 1161 result, err := s.api.Remove(args) 1162 c.Assert(err, jc.ErrorIsNil) 1163 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1164 Results: []params.ErrorResult{ 1165 {Error: nil}, 1166 {Error: nil}, 1167 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1168 {Error: ¶ms.Error{Message: `"filesystem-invalid" is not a valid filesystem tag`}}, 1169 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1170 }, 1171 }) 1172 } 1173 1174 func (s *provisionerSuite) TestRemoveVolumeAttachments(c *gc.C) { 1175 s.setupVolumes(c) 1176 s.authorizer.EnvironManager = false 1177 1178 err := s.State.DetachVolume(names.NewMachineTag("0"), names.NewVolumeTag("1")) 1179 c.Assert(err, jc.ErrorIsNil) 1180 1181 results, err := s.api.RemoveAttachment(params.MachineStorageIds{ 1182 Ids: []params.MachineStorageId{{ 1183 MachineTag: "machine-0", 1184 AttachmentTag: "volume-0-0", 1185 }, { 1186 MachineTag: "machine-0", 1187 AttachmentTag: "volume-1", 1188 }, { 1189 MachineTag: "machine-2", 1190 AttachmentTag: "volume-4", 1191 }, { 1192 MachineTag: "machine-0", 1193 AttachmentTag: "volume-42", 1194 }}, 1195 }) 1196 c.Assert(err, jc.ErrorIsNil) 1197 c.Assert(results, jc.DeepEquals, params.ErrorResults{ 1198 Results: []params.ErrorResult{ 1199 {Error: ¶ms.Error{Message: "removing attachment of volume 0/0 from machine 0: volume attachment is not dying"}}, 1200 {Error: nil}, 1201 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1202 {Error: ¶ms.Error{`removing attachment of volume 42 from machine 0: volume "42" on machine "0" not found`, "not found"}}, 1203 }, 1204 }) 1205 } 1206 1207 func (s *provisionerSuite) TestRemoveFilesystemAttachments(c *gc.C) { 1208 s.setupFilesystems(c) 1209 s.authorizer.EnvironManager = false 1210 1211 err := s.State.DetachFilesystem(names.NewMachineTag("0"), names.NewFilesystemTag("1")) 1212 c.Assert(err, jc.ErrorIsNil) 1213 1214 results, err := s.api.RemoveAttachment(params.MachineStorageIds{ 1215 Ids: []params.MachineStorageId{{ 1216 MachineTag: "machine-0", 1217 AttachmentTag: "filesystem-0-0", 1218 }, { 1219 MachineTag: "machine-0", 1220 AttachmentTag: "filesystem-1", 1221 }, { 1222 MachineTag: "machine-2", 1223 AttachmentTag: "filesystem-4", 1224 }, { 1225 MachineTag: "machine-0", 1226 AttachmentTag: "filesystem-42", 1227 }}, 1228 }) 1229 c.Assert(err, jc.ErrorIsNil) 1230 c.Assert(results, jc.DeepEquals, params.ErrorResults{ 1231 Results: []params.ErrorResult{ 1232 {Error: ¶ms.Error{Message: "removing attachment of filesystem 0/0 from machine 0: filesystem attachment is not dying"}}, 1233 {Error: nil}, 1234 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1235 {Error: ¶ms.Error{`removing attachment of filesystem 42 from machine 0: filesystem "42" on machine "0" not found`, "not found"}}, 1236 }, 1237 }) 1238 } 1239 1240 type byMachineAndEntity []params.MachineStorageId 1241 1242 func (b byMachineAndEntity) Len() int { 1243 return len(b) 1244 } 1245 1246 func (b byMachineAndEntity) Less(i, j int) bool { 1247 if b[i].MachineTag == b[j].MachineTag { 1248 return b[i].AttachmentTag < b[j].AttachmentTag 1249 } 1250 return b[i].MachineTag < b[j].MachineTag 1251 } 1252 1253 func (b byMachineAndEntity) Swap(i, j int) { 1254 b[i], b[j] = b[j], b[i] 1255 }