github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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.AddCleanup(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{Message: "permission denied", Code: "unauthorized access"}}, 195 {Error: ¶ms.Error{Message: "permission denied", Code: "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{Message: "permission denied", Code: "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{Message: "permission denied", Code: "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{Message: "permission denied", Code: "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{Message: "permission denied", Code: "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{Message: "permission denied", Code: "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{Message: "permission denied", Code: "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.JujuController: testing.ModelTag.Id(), 372 tags.JujuModel: testing.ModelTag.Id(), 373 }, 374 Attachment: ¶ms.VolumeAttachmentParams{ 375 MachineTag: "machine-0", 376 VolumeTag: "volume-0-0", 377 Provider: "machinescoped", 378 InstanceId: "inst-id", 379 }, 380 }}, 381 {Result: params.VolumeParams{ 382 VolumeTag: "volume-1", 383 Size: 2048, 384 Provider: "environscoped", 385 Tags: map[string]string{ 386 tags.JujuController: testing.ModelTag.Id(), 387 tags.JujuModel: testing.ModelTag.Id(), 388 }, 389 Attachment: ¶ms.VolumeAttachmentParams{ 390 MachineTag: "machine-0", 391 VolumeTag: "volume-1", 392 Provider: "environscoped", 393 InstanceId: "inst-id", 394 }, 395 }}, 396 {Result: params.VolumeParams{ 397 VolumeTag: "volume-3", 398 Size: 4096, 399 Provider: "environscoped", 400 Tags: map[string]string{ 401 tags.JujuController: testing.ModelTag.Id(), 402 tags.JujuModel: testing.ModelTag.Id(), 403 }, 404 Attachment: ¶ms.VolumeAttachmentParams{ 405 MachineTag: "machine-0", 406 VolumeTag: "volume-3", 407 Provider: "environscoped", 408 InstanceId: "inst-id", 409 ReadOnly: true, 410 }, 411 }}, 412 {Error: ¶ms.Error{Message: "permission denied", Code: "unauthorized access"}}, 413 }, 414 }) 415 } 416 417 func (s *provisionerSuite) TestVolumeParamsEmptyArgs(c *gc.C) { 418 results, err := s.api.VolumeParams(params.Entities{}) 419 c.Assert(err, jc.ErrorIsNil) 420 c.Assert(results.Results, gc.HasLen, 0) 421 } 422 423 func (s *provisionerSuite) TestFilesystemParams(c *gc.C) { 424 s.setupFilesystems(c) 425 results, err := s.api.FilesystemParams(params.Entities{ 426 Entities: []params.Entity{{"filesystem-0-0"}, {"filesystem-1"}, {"filesystem-42"}}, 427 }) 428 c.Assert(err, jc.ErrorIsNil) 429 c.Assert(results, jc.DeepEquals, params.FilesystemParamsResults{ 430 Results: []params.FilesystemParamsResult{ 431 {Result: params.FilesystemParams{ 432 FilesystemTag: "filesystem-0-0", 433 Size: 1024, 434 Provider: "machinescoped", 435 Tags: map[string]string{ 436 tags.JujuController: testing.ModelTag.Id(), 437 tags.JujuModel: testing.ModelTag.Id(), 438 }, 439 }}, 440 {Result: params.FilesystemParams{ 441 FilesystemTag: "filesystem-1", 442 Size: 2048, 443 Provider: "environscoped", 444 Tags: map[string]string{ 445 tags.JujuController: testing.ModelTag.Id(), 446 tags.JujuModel: testing.ModelTag.Id(), 447 }, 448 }}, 449 {Error: ¶ms.Error{Message: "permission denied", Code: "unauthorized access"}}, 450 }, 451 }) 452 } 453 454 func (s *provisionerSuite) TestVolumeAttachmentParams(c *gc.C) { 455 s.setupVolumes(c) 456 457 err := s.State.SetVolumeInfo(names.NewVolumeTag("3"), state.VolumeInfo{ 458 HardwareId: "123", 459 VolumeId: "xyz", 460 Size: 1024, 461 }) 462 c.Assert(err, jc.ErrorIsNil) 463 464 err = s.State.SetVolumeAttachmentInfo( 465 names.NewMachineTag("0"), 466 names.NewVolumeTag("3"), 467 state.VolumeAttachmentInfo{ 468 DeviceName: "xvdf1", 469 ReadOnly: true, 470 }, 471 ) 472 c.Assert(err, jc.ErrorIsNil) 473 474 results, err := s.api.VolumeAttachmentParams(params.MachineStorageIds{ 475 Ids: []params.MachineStorageId{{ 476 MachineTag: "machine-0", 477 AttachmentTag: "volume-0-0", 478 }, { 479 MachineTag: "machine-0", 480 AttachmentTag: "volume-1", 481 }, { 482 MachineTag: "machine-0", 483 AttachmentTag: "volume-3", 484 }, { 485 MachineTag: "machine-2", 486 AttachmentTag: "volume-4", 487 }, { 488 MachineTag: "machine-0", 489 AttachmentTag: "volume-42", 490 }}, 491 }) 492 c.Assert(err, jc.ErrorIsNil) 493 c.Assert(results, jc.DeepEquals, params.VolumeAttachmentParamsResults{ 494 Results: []params.VolumeAttachmentParamsResult{ 495 {Result: params.VolumeAttachmentParams{ 496 MachineTag: "machine-0", 497 VolumeTag: "volume-0-0", 498 InstanceId: "inst-id", 499 VolumeId: "abc", 500 Provider: "machinescoped", 501 }}, 502 {Result: params.VolumeAttachmentParams{ 503 MachineTag: "machine-0", 504 VolumeTag: "volume-1", 505 InstanceId: "inst-id", 506 Provider: "environscoped", 507 }}, 508 {Result: params.VolumeAttachmentParams{ 509 MachineTag: "machine-0", 510 VolumeTag: "volume-3", 511 InstanceId: "inst-id", 512 VolumeId: "xyz", 513 Provider: "environscoped", 514 ReadOnly: true, 515 }}, 516 {Result: params.VolumeAttachmentParams{ 517 MachineTag: "machine-2", 518 VolumeTag: "volume-4", 519 Provider: "environscoped", 520 }}, 521 {Error: ¶ms.Error{Message: "permission denied", Code: "unauthorized access"}}, 522 }, 523 }) 524 } 525 526 func (s *provisionerSuite) TestFilesystemAttachmentParams(c *gc.C) { 527 s.setupFilesystems(c) 528 529 err := s.State.SetFilesystemInfo(names.NewFilesystemTag("1"), state.FilesystemInfo{ 530 FilesystemId: "fsid", 531 Size: 1024, 532 }) 533 c.Assert(err, jc.ErrorIsNil) 534 535 err = s.State.SetFilesystemAttachmentInfo( 536 names.NewMachineTag("0"), 537 names.NewFilesystemTag("1"), 538 state.FilesystemAttachmentInfo{ 539 MountPoint: "/in/the/place", 540 }, 541 ) 542 c.Assert(err, jc.ErrorIsNil) 543 544 results, err := s.api.FilesystemAttachmentParams(params.MachineStorageIds{ 545 Ids: []params.MachineStorageId{{ 546 MachineTag: "machine-0", 547 AttachmentTag: "filesystem-0-0", 548 }, { 549 MachineTag: "machine-0", 550 AttachmentTag: "filesystem-1", 551 }, { 552 MachineTag: "machine-2", 553 AttachmentTag: "filesystem-3", 554 }, { 555 MachineTag: "machine-0", 556 AttachmentTag: "filesystem-42", 557 }}, 558 }) 559 c.Assert(err, jc.ErrorIsNil) 560 c.Assert(results, jc.DeepEquals, params.FilesystemAttachmentParamsResults{ 561 Results: []params.FilesystemAttachmentParamsResult{ 562 {Result: params.FilesystemAttachmentParams{ 563 MachineTag: "machine-0", 564 FilesystemTag: "filesystem-0-0", 565 InstanceId: "inst-id", 566 FilesystemId: "abc", 567 Provider: "machinescoped", 568 MountPoint: "/srv", 569 ReadOnly: true, 570 }}, 571 {Result: params.FilesystemAttachmentParams{ 572 MachineTag: "machine-0", 573 FilesystemTag: "filesystem-1", 574 InstanceId: "inst-id", 575 FilesystemId: "fsid", 576 Provider: "environscoped", 577 MountPoint: "/in/the/place", 578 }}, 579 {Result: params.FilesystemAttachmentParams{ 580 MachineTag: "machine-2", 581 FilesystemTag: "filesystem-3", 582 Provider: "environscoped", 583 }}, 584 {Error: ¶ms.Error{Message: "permission denied", Code: "unauthorized access"}}, 585 }, 586 }) 587 } 588 589 func (s *provisionerSuite) TestSetVolumeAttachmentInfo(c *gc.C) { 590 s.setupVolumes(c) 591 592 err := s.State.SetVolumeInfo(names.NewVolumeTag("4"), state.VolumeInfo{ 593 VolumeId: "whatever", 594 Size: 1024, 595 }) 596 c.Assert(err, jc.ErrorIsNil) 597 598 results, err := s.api.SetVolumeAttachmentInfo(params.VolumeAttachments{ 599 VolumeAttachments: []params.VolumeAttachment{{ 600 MachineTag: "machine-0", 601 VolumeTag: "volume-0-0", 602 Info: params.VolumeAttachmentInfo{ 603 DeviceName: "sda", 604 ReadOnly: true, 605 }, 606 }, { 607 MachineTag: "machine-0", 608 VolumeTag: "volume-1", 609 Info: params.VolumeAttachmentInfo{ 610 DeviceName: "sdb", 611 }, 612 }, { 613 MachineTag: "machine-2", 614 VolumeTag: "volume-4", 615 Info: params.VolumeAttachmentInfo{ 616 DeviceName: "sdc", 617 }, 618 }, { 619 MachineTag: "machine-0", 620 VolumeTag: "volume-42", 621 Info: params.VolumeAttachmentInfo{ 622 DeviceName: "sdd", 623 }, 624 }}, 625 }) 626 c.Assert(err, jc.ErrorIsNil) 627 c.Assert(results, jc.DeepEquals, params.ErrorResults{ 628 Results: []params.ErrorResult{ 629 {}, 630 {Error: ¶ms.Error{Message: `cannot set info for volume attachment 1:0: volume "1" not provisioned`, Code: "not provisioned"}}, 631 {Error: ¶ms.Error{Message: `cannot set info for volume attachment 4:2: machine 2 not provisioned`, Code: "not provisioned"}}, 632 {Error: ¶ms.Error{Message: "permission denied", Code: "unauthorized access"}}, 633 }, 634 }) 635 } 636 637 func (s *provisionerSuite) TestSetFilesystemAttachmentInfo(c *gc.C) { 638 s.setupFilesystems(c) 639 640 err := s.State.SetFilesystemInfo(names.NewFilesystemTag("3"), state.FilesystemInfo{ 641 FilesystemId: "whatever", 642 Size: 1024, 643 }) 644 c.Assert(err, jc.ErrorIsNil) 645 646 results, err := s.api.SetFilesystemAttachmentInfo(params.FilesystemAttachments{ 647 FilesystemAttachments: []params.FilesystemAttachment{{ 648 MachineTag: "machine-0", 649 FilesystemTag: "filesystem-0-0", 650 Info: params.FilesystemAttachmentInfo{ 651 MountPoint: "/srv/a", 652 ReadOnly: true, 653 }, 654 }, { 655 MachineTag: "machine-0", 656 FilesystemTag: "filesystem-1", 657 Info: params.FilesystemAttachmentInfo{ 658 MountPoint: "/srv/b", 659 }, 660 }, { 661 MachineTag: "machine-2", 662 FilesystemTag: "filesystem-3", 663 Info: params.FilesystemAttachmentInfo{ 664 MountPoint: "/srv/c", 665 }, 666 }, { 667 MachineTag: "machine-0", 668 FilesystemTag: "filesystem-42", 669 Info: params.FilesystemAttachmentInfo{ 670 MountPoint: "/srv/d", 671 }, 672 }}, 673 }) 674 c.Assert(err, jc.ErrorIsNil) 675 c.Assert(results, jc.DeepEquals, params.ErrorResults{ 676 Results: []params.ErrorResult{ 677 {}, 678 {Error: ¶ms.Error{Message: `cannot set info for filesystem attachment 1:0: filesystem "1" not provisioned`, Code: "not provisioned"}}, 679 {Error: ¶ms.Error{Message: `cannot set info for filesystem attachment 3:2: machine 2 not provisioned`, Code: "not provisioned"}}, 680 {Error: ¶ms.Error{Message: "permission denied", Code: "unauthorized access"}}, 681 }, 682 }) 683 } 684 685 func (s *provisionerSuite) TestWatchVolumes(c *gc.C) { 686 s.setupVolumes(c) 687 s.factory.MakeMachine(c, nil) 688 c.Assert(s.resources.Count(), gc.Equals, 0) 689 690 args := params.Entities{Entities: []params.Entity{ 691 {"machine-0"}, 692 {s.State.ModelTag().String()}, 693 {"environ-adb650da-b77b-4ee8-9cbb-d57a9a592847"}, 694 {"machine-1"}, 695 {"machine-42"}}, 696 } 697 result, err := s.api.WatchVolumes(args) 698 c.Assert(err, jc.ErrorIsNil) 699 sort.Strings(result.Results[1].Changes) 700 c.Assert(result, jc.DeepEquals, params.StringsWatchResults{ 701 Results: []params.StringsWatchResult{ 702 {StringsWatcherId: "1", Changes: []string{"0/0"}}, 703 {StringsWatcherId: "2", Changes: []string{"1", "2", "3", "4"}}, 704 {Error: apiservertesting.ErrUnauthorized}, 705 {Error: apiservertesting.ErrUnauthorized}, 706 {Error: apiservertesting.ErrUnauthorized}, 707 }, 708 }) 709 710 // Verify the resources were registered and stop them when done. 711 c.Assert(s.resources.Count(), gc.Equals, 2) 712 v0Watcher := s.resources.Get("1") 713 defer statetesting.AssertStop(c, v0Watcher) 714 v1Watcher := s.resources.Get("2") 715 defer statetesting.AssertStop(c, v1Watcher) 716 717 // Check that the Watch has consumed the initial events ("returned" in 718 // the Watch call) 719 wc := statetesting.NewStringsWatcherC(c, s.State, v0Watcher.(state.StringsWatcher)) 720 wc.AssertNoChange() 721 wc = statetesting.NewStringsWatcherC(c, s.State, v1Watcher.(state.StringsWatcher)) 722 wc.AssertNoChange() 723 } 724 725 func (s *provisionerSuite) TestWatchVolumeAttachments(c *gc.C) { 726 s.setupVolumes(c) 727 s.factory.MakeMachine(c, nil) 728 c.Assert(s.resources.Count(), gc.Equals, 0) 729 730 args := params.Entities{Entities: []params.Entity{ 731 {"machine-0"}, 732 {s.State.ModelTag().String()}, 733 {"environ-adb650da-b77b-4ee8-9cbb-d57a9a592847"}, 734 {"machine-1"}, 735 {"machine-42"}}, 736 } 737 result, err := s.api.WatchVolumeAttachments(args) 738 c.Assert(err, jc.ErrorIsNil) 739 sort.Sort(byMachineAndEntity(result.Results[0].Changes)) 740 sort.Sort(byMachineAndEntity(result.Results[1].Changes)) 741 c.Assert(result, jc.DeepEquals, params.MachineStorageIdsWatchResults{ 742 Results: []params.MachineStorageIdsWatchResult{ 743 { 744 MachineStorageIdsWatcherId: "1", 745 Changes: []params.MachineStorageId{{ 746 MachineTag: "machine-0", 747 AttachmentTag: "volume-0-0", 748 }}, 749 }, 750 { 751 MachineStorageIdsWatcherId: "2", 752 Changes: []params.MachineStorageId{{ 753 MachineTag: "machine-0", 754 AttachmentTag: "volume-1", 755 }, { 756 MachineTag: "machine-0", 757 AttachmentTag: "volume-2", 758 }, { 759 MachineTag: "machine-0", 760 AttachmentTag: "volume-3", 761 }, { 762 MachineTag: "machine-2", 763 AttachmentTag: "volume-4", 764 }}, 765 }, 766 {Error: apiservertesting.ErrUnauthorized}, 767 {Error: apiservertesting.ErrUnauthorized}, 768 {Error: apiservertesting.ErrUnauthorized}, 769 }, 770 }) 771 772 // Verify the resources were registered and stop them when done. 773 c.Assert(s.resources.Count(), gc.Equals, 2) 774 v0Watcher := s.resources.Get("1") 775 defer statetesting.AssertStop(c, v0Watcher) 776 v1Watcher := s.resources.Get("2") 777 defer statetesting.AssertStop(c, v1Watcher) 778 779 // Check that the Watch has consumed the initial events ("returned" in 780 // the Watch call) 781 wc := statetesting.NewStringsWatcherC(c, s.State, v0Watcher.(state.StringsWatcher)) 782 wc.AssertNoChange() 783 wc = statetesting.NewStringsWatcherC(c, s.State, v1Watcher.(state.StringsWatcher)) 784 wc.AssertNoChange() 785 } 786 787 func (s *provisionerSuite) TestWatchFilesystems(c *gc.C) { 788 s.setupFilesystems(c) 789 c.Assert(s.resources.Count(), gc.Equals, 0) 790 791 args := params.Entities{Entities: []params.Entity{ 792 {"machine-0"}, 793 {s.State.ModelTag().String()}, 794 {"environ-adb650da-b77b-4ee8-9cbb-d57a9a592847"}, 795 {"machine-1"}, 796 {"machine-42"}}, 797 } 798 result, err := s.api.WatchFilesystems(args) 799 c.Assert(err, jc.ErrorIsNil) 800 sort.Strings(result.Results[1].Changes) 801 c.Assert(result, jc.DeepEquals, params.StringsWatchResults{ 802 Results: []params.StringsWatchResult{ 803 { 804 StringsWatcherId: "1", 805 Changes: []string{"0/0"}, 806 }, 807 { 808 StringsWatcherId: "2", 809 Changes: []string{"1", "2", "3"}, 810 }, 811 {Error: apiservertesting.ErrUnauthorized}, 812 {Error: apiservertesting.ErrUnauthorized}, 813 {Error: apiservertesting.ErrUnauthorized}, 814 }, 815 }) 816 817 // Verify the resources were registered and stop them when done. 818 c.Assert(s.resources.Count(), gc.Equals, 2) 819 v0Watcher := s.resources.Get("1") 820 defer statetesting.AssertStop(c, v0Watcher) 821 v1Watcher := s.resources.Get("2") 822 defer statetesting.AssertStop(c, v1Watcher) 823 824 // Check that the Watch has consumed the initial events ("returned" in 825 // the Watch call) 826 wc := statetesting.NewStringsWatcherC(c, s.State, v0Watcher.(state.StringsWatcher)) 827 wc.AssertNoChange() 828 wc = statetesting.NewStringsWatcherC(c, s.State, v1Watcher.(state.StringsWatcher)) 829 wc.AssertNoChange() 830 } 831 832 func (s *provisionerSuite) TestWatchFilesystemAttachments(c *gc.C) { 833 s.setupFilesystems(c) 834 c.Assert(s.resources.Count(), gc.Equals, 0) 835 836 args := params.Entities{Entities: []params.Entity{ 837 {"machine-0"}, 838 {s.State.ModelTag().String()}, 839 {"environ-adb650da-b77b-4ee8-9cbb-d57a9a592847"}, 840 {"machine-1"}, 841 {"machine-42"}}, 842 } 843 result, err := s.api.WatchFilesystemAttachments(args) 844 c.Assert(err, jc.ErrorIsNil) 845 sort.Sort(byMachineAndEntity(result.Results[0].Changes)) 846 sort.Sort(byMachineAndEntity(result.Results[1].Changes)) 847 c.Assert(result, jc.DeepEquals, params.MachineStorageIdsWatchResults{ 848 Results: []params.MachineStorageIdsWatchResult{ 849 { 850 MachineStorageIdsWatcherId: "1", 851 Changes: []params.MachineStorageId{{ 852 MachineTag: "machine-0", 853 AttachmentTag: "filesystem-0-0", 854 }}, 855 }, 856 { 857 MachineStorageIdsWatcherId: "2", 858 Changes: []params.MachineStorageId{{ 859 MachineTag: "machine-0", 860 AttachmentTag: "filesystem-1", 861 }, { 862 MachineTag: "machine-0", 863 AttachmentTag: "filesystem-2", 864 }, { 865 MachineTag: "machine-2", 866 AttachmentTag: "filesystem-3", 867 }}, 868 }, 869 {Error: apiservertesting.ErrUnauthorized}, 870 {Error: apiservertesting.ErrUnauthorized}, 871 {Error: apiservertesting.ErrUnauthorized}, 872 }, 873 }) 874 875 // Verify the resources were registered and stop them when done. 876 c.Assert(s.resources.Count(), gc.Equals, 2) 877 v0Watcher := s.resources.Get("1") 878 defer statetesting.AssertStop(c, v0Watcher) 879 v1Watcher := s.resources.Get("2") 880 defer statetesting.AssertStop(c, v1Watcher) 881 882 // Check that the Watch has consumed the initial events ("returned" in 883 // the Watch call) 884 wc := statetesting.NewStringsWatcherC(c, s.State, v0Watcher.(state.StringsWatcher)) 885 wc.AssertNoChange() 886 wc = statetesting.NewStringsWatcherC(c, s.State, v1Watcher.(state.StringsWatcher)) 887 wc.AssertNoChange() 888 } 889 890 func (s *provisionerSuite) TestWatchBlockDevices(c *gc.C) { 891 s.factory.MakeMachine(c, nil) 892 c.Assert(s.resources.Count(), gc.Equals, 0) 893 894 args := params.Entities{Entities: []params.Entity{ 895 {"machine-0"}, 896 {"service-mysql"}, 897 {"machine-1"}, 898 {"machine-42"}}, 899 } 900 results, err := s.api.WatchBlockDevices(args) 901 c.Assert(err, jc.ErrorIsNil) 902 c.Assert(results, jc.DeepEquals, params.NotifyWatchResults{ 903 Results: []params.NotifyWatchResult{ 904 {NotifyWatcherId: "1"}, 905 {Error: ¶ms.Error{Message: `"service-mysql" is not a valid machine tag`}}, 906 {Error: apiservertesting.ErrUnauthorized}, 907 {Error: apiservertesting.ErrUnauthorized}, 908 }, 909 }) 910 911 // Verify the resources were registered and stop them when done. 912 c.Assert(s.resources.Count(), gc.Equals, 1) 913 watcher := s.resources.Get("1") 914 defer statetesting.AssertStop(c, watcher) 915 916 // Check that the Watch has consumed the initial event. 917 wc := statetesting.NewNotifyWatcherC(c, s.State, watcher.(state.NotifyWatcher)) 918 wc.AssertNoChange() 919 920 m, err := s.State.Machine("0") 921 c.Assert(err, jc.ErrorIsNil) 922 err = m.SetMachineBlockDevices(state.BlockDeviceInfo{ 923 DeviceName: "sda", 924 Size: 123, 925 }) 926 c.Assert(err, jc.ErrorIsNil) 927 wc.AssertOneChange() 928 } 929 930 func (s *provisionerSuite) TestVolumeBlockDevices(c *gc.C) { 931 s.setupVolumes(c) 932 s.factory.MakeMachine(c, nil) 933 934 err := s.State.SetVolumeAttachmentInfo( 935 names.NewMachineTag("0"), 936 names.NewVolumeTag("0/0"), 937 state.VolumeAttachmentInfo{}, 938 ) 939 c.Assert(err, jc.ErrorIsNil) 940 941 machine0, err := s.State.Machine("0") 942 c.Assert(err, jc.ErrorIsNil) 943 err = machine0.SetMachineBlockDevices(state.BlockDeviceInfo{ 944 DeviceName: "sda", 945 Size: 123, 946 HardwareId: "123", // matches volume-0/0 947 }) 948 c.Assert(err, jc.ErrorIsNil) 949 950 args := params.MachineStorageIds{Ids: []params.MachineStorageId{ 951 {MachineTag: "machine-0", AttachmentTag: "volume-0-0"}, 952 {MachineTag: "machine-0", AttachmentTag: "volume-0-1"}, 953 {MachineTag: "machine-0", AttachmentTag: "volume-0-2"}, 954 {MachineTag: "machine-1", AttachmentTag: "volume-1"}, 955 {MachineTag: "machine-42", AttachmentTag: "volume-42"}, 956 {MachineTag: "service-mysql", AttachmentTag: "volume-1"}, 957 }} 958 results, err := s.api.VolumeBlockDevices(args) 959 c.Assert(err, jc.ErrorIsNil) 960 c.Assert(results, jc.DeepEquals, params.BlockDeviceResults{ 961 Results: []params.BlockDeviceResult{ 962 {Result: storage.BlockDevice{ 963 DeviceName: "sda", 964 Size: 123, 965 HardwareId: "123", 966 }}, 967 {Error: apiservertesting.ErrUnauthorized}, 968 {Error: apiservertesting.ErrUnauthorized}, 969 {Error: apiservertesting.ErrUnauthorized}, 970 {Error: apiservertesting.ErrUnauthorized}, 971 {Error: ¶ms.Error{Message: `"service-mysql" is not a valid machine tag`}}, 972 }, 973 }) 974 } 975 976 func (s *provisionerSuite) TestLife(c *gc.C) { 977 s.setupVolumes(c) 978 args := params.Entities{Entities: []params.Entity{{"volume-0-0"}, {"volume-1"}, {"volume-42"}}} 979 result, err := s.api.Life(args) 980 c.Assert(err, jc.ErrorIsNil) 981 c.Assert(result, gc.DeepEquals, params.LifeResults{ 982 Results: []params.LifeResult{ 983 {Life: params.Alive}, 984 {Life: params.Alive}, 985 {Error: common.ServerError(errors.NotFoundf(`volume "42"`))}, 986 }, 987 }) 988 } 989 990 func (s *provisionerSuite) TestAttachmentLife(c *gc.C) { 991 s.setupVolumes(c) 992 993 // TODO(axw) test filesystem attachment life 994 // TODO(axw) test Dying 995 996 results, err := s.api.AttachmentLife(params.MachineStorageIds{ 997 Ids: []params.MachineStorageId{{ 998 MachineTag: "machine-0", 999 AttachmentTag: "volume-0-0", 1000 }, { 1001 MachineTag: "machine-0", 1002 AttachmentTag: "volume-1", 1003 }, { 1004 MachineTag: "machine-2", 1005 AttachmentTag: "volume-4", 1006 }, { 1007 MachineTag: "machine-0", 1008 AttachmentTag: "volume-42", 1009 }}, 1010 }) 1011 c.Assert(err, jc.ErrorIsNil) 1012 c.Assert(results, jc.DeepEquals, params.LifeResults{ 1013 Results: []params.LifeResult{ 1014 {Life: params.Alive}, 1015 {Life: params.Alive}, 1016 {Life: params.Alive}, 1017 {Error: ¶ms.Error{Message: "permission denied", Code: "unauthorized access"}}, 1018 }, 1019 }) 1020 } 1021 1022 func (s *provisionerSuite) TestEnsureDead(c *gc.C) { 1023 s.setupVolumes(c) 1024 args := params.Entities{Entities: []params.Entity{{"volume-0-0"}, {"volume-1"}, {"volume-42"}}} 1025 result, err := s.api.EnsureDead(args) 1026 c.Assert(err, jc.ErrorIsNil) 1027 // TODO(wallyworld) - this test will be updated when EnsureDead is supported 1028 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1029 Results: []params.ErrorResult{ 1030 {Error: common.ServerError(common.NotSupportedError(names.NewVolumeTag("0/0"), "ensuring death"))}, 1031 {Error: common.ServerError(common.NotSupportedError(names.NewVolumeTag("1"), "ensuring death"))}, 1032 {Error: common.ServerError(errors.NotFoundf(`volume "42"`))}, 1033 }, 1034 }) 1035 } 1036 1037 func (s *provisionerSuite) TestWatchForModelConfigChanges(c *gc.C) { 1038 result, err := s.api.WatchForModelConfigChanges() 1039 c.Assert(err, jc.ErrorIsNil) 1040 c.Assert(result.NotifyWatcherId, gc.Equals, "1") 1041 1042 // Verify the resource was registered and stop it when done. 1043 c.Assert(s.resources.Count(), gc.Equals, 1) 1044 watcher := s.resources.Get("1") 1045 defer statetesting.AssertStop(c, watcher) 1046 1047 // Check that the Watch has consumed the initial events ("returned" in 1048 // the Watch call) 1049 wc := statetesting.NewNotifyWatcherC(c, s.State, watcher.(state.NotifyWatcher)) 1050 wc.AssertNoChange() 1051 1052 // Updating config should trigger the watcher. 1053 err = s.State.UpdateModelConfig(map[string]interface{}{"what": "ever"}, nil, nil) 1054 c.Assert(err, jc.ErrorIsNil) 1055 wc.AssertOneChange() 1056 } 1057 1058 func (s *provisionerSuite) TestModelConfig(c *gc.C) { 1059 stateModelConfig, err := s.State.ModelConfig() 1060 c.Assert(err, jc.ErrorIsNil) 1061 1062 result, err := s.api.ModelConfig() 1063 c.Assert(err, jc.ErrorIsNil) 1064 c.Assert(result.Config, jc.DeepEquals, params.ModelConfig(stateModelConfig.AllAttrs())) 1065 } 1066 1067 func (s *provisionerSuite) TestRemoveVolumesEnvironManager(c *gc.C) { 1068 s.setupVolumes(c) 1069 args := params.Entities{Entities: []params.Entity{ 1070 {"volume-1-0"}, {"volume-1"}, {"volume-2"}, {"volume-42"}, 1071 {"volume-invalid"}, {"machine-0"}, 1072 }} 1073 1074 err := s.State.DetachVolume(names.NewMachineTag("0"), names.NewVolumeTag("1")) 1075 c.Assert(err, jc.ErrorIsNil) 1076 err = s.State.RemoveVolumeAttachment(names.NewMachineTag("0"), names.NewVolumeTag("1")) 1077 c.Assert(err, jc.ErrorIsNil) 1078 err = s.State.DestroyVolume(names.NewVolumeTag("1")) 1079 c.Assert(err, jc.ErrorIsNil) 1080 1081 result, err := s.api.Remove(args) 1082 c.Assert(err, jc.ErrorIsNil) 1083 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1084 Results: []params.ErrorResult{ 1085 {Error: ¶ms.Error{Message: "permission denied", Code: "unauthorized access"}}, 1086 {Error: nil}, 1087 {Error: ¶ms.Error{Message: "removing volume 2: volume is not dead"}}, 1088 {Error: nil}, 1089 {Error: ¶ms.Error{Message: `"volume-invalid" is not a valid volume tag`}}, 1090 {Error: ¶ms.Error{Message: "permission denied", Code: "unauthorized access"}}, 1091 }, 1092 }) 1093 } 1094 1095 func (s *provisionerSuite) TestRemoveFilesystemsEnvironManager(c *gc.C) { 1096 s.setupFilesystems(c) 1097 args := params.Entities{Entities: []params.Entity{ 1098 {"filesystem-1-0"}, {"filesystem-1"}, {"filesystem-2"}, {"filesystem-42"}, 1099 {"filesystem-invalid"}, {"machine-0"}, 1100 }} 1101 1102 err := s.State.DetachFilesystem(names.NewMachineTag("0"), names.NewFilesystemTag("1")) 1103 c.Assert(err, jc.ErrorIsNil) 1104 err = s.State.RemoveFilesystemAttachment(names.NewMachineTag("0"), names.NewFilesystemTag("1")) 1105 c.Assert(err, jc.ErrorIsNil) 1106 err = s.State.DestroyFilesystem(names.NewFilesystemTag("1")) 1107 c.Assert(err, jc.ErrorIsNil) 1108 1109 result, err := s.api.Remove(args) 1110 c.Assert(err, jc.ErrorIsNil) 1111 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1112 Results: []params.ErrorResult{ 1113 {Error: ¶ms.Error{Message: "permission denied", Code: "unauthorized access"}}, 1114 {Error: nil}, 1115 {Error: ¶ms.Error{Message: "removing filesystem 2: filesystem is not dead"}}, 1116 {Error: nil}, 1117 {Error: ¶ms.Error{Message: `"filesystem-invalid" is not a valid filesystem tag`}}, 1118 {Error: ¶ms.Error{Message: "permission denied", Code: "unauthorized access"}}, 1119 }, 1120 }) 1121 } 1122 1123 func (s *provisionerSuite) TestRemoveVolumesMachineAgent(c *gc.C) { 1124 s.setupVolumes(c) 1125 s.authorizer.EnvironManager = false 1126 args := params.Entities{Entities: []params.Entity{ 1127 {"volume-0-0"}, {"volume-0-42"}, {"volume-42"}, 1128 {"volume-invalid"}, {"machine-0"}, 1129 }} 1130 1131 err := s.State.DetachVolume(names.NewMachineTag("0"), names.NewVolumeTag("0/0")) 1132 c.Assert(err, jc.ErrorIsNil) 1133 err = s.State.RemoveVolumeAttachment(names.NewMachineTag("0"), names.NewVolumeTag("0/0")) 1134 c.Assert(err, jc.ErrorIsNil) 1135 err = s.State.DestroyVolume(names.NewVolumeTag("0/0")) 1136 c.Assert(err, jc.ErrorIsNil) 1137 1138 result, err := s.api.Remove(args) 1139 c.Assert(err, jc.ErrorIsNil) 1140 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1141 Results: []params.ErrorResult{ 1142 {Error: nil}, 1143 {Error: nil}, 1144 {Error: ¶ms.Error{Message: "permission denied", Code: "unauthorized access"}}, 1145 {Error: ¶ms.Error{Message: `"volume-invalid" is not a valid volume tag`}}, 1146 {Error: ¶ms.Error{Message: "permission denied", Code: "unauthorized access"}}, 1147 }, 1148 }) 1149 } 1150 1151 func (s *provisionerSuite) TestRemoveFilesystemsMachineAgent(c *gc.C) { 1152 s.setupFilesystems(c) 1153 s.authorizer.EnvironManager = false 1154 args := params.Entities{Entities: []params.Entity{ 1155 {"filesystem-0-0"}, {"filesystem-0-42"}, {"filesystem-42"}, 1156 {"filesystem-invalid"}, {"machine-0"}, 1157 }} 1158 1159 err := s.State.DetachFilesystem(names.NewMachineTag("0"), names.NewFilesystemTag("0/0")) 1160 c.Assert(err, jc.ErrorIsNil) 1161 err = s.State.RemoveFilesystemAttachment(names.NewMachineTag("0"), names.NewFilesystemTag("0/0")) 1162 c.Assert(err, jc.ErrorIsNil) 1163 err = s.State.DestroyFilesystem(names.NewFilesystemTag("0/0")) 1164 c.Assert(err, jc.ErrorIsNil) 1165 1166 result, err := s.api.Remove(args) 1167 c.Assert(err, jc.ErrorIsNil) 1168 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1169 Results: []params.ErrorResult{ 1170 {Error: nil}, 1171 {Error: nil}, 1172 {Error: ¶ms.Error{Message: "permission denied", Code: "unauthorized access"}}, 1173 {Error: ¶ms.Error{Message: `"filesystem-invalid" is not a valid filesystem tag`}}, 1174 {Error: ¶ms.Error{Message: "permission denied", Code: "unauthorized access"}}, 1175 }, 1176 }) 1177 } 1178 1179 func (s *provisionerSuite) TestRemoveVolumeAttachments(c *gc.C) { 1180 s.setupVolumes(c) 1181 s.authorizer.EnvironManager = false 1182 1183 err := s.State.DetachVolume(names.NewMachineTag("0"), names.NewVolumeTag("1")) 1184 c.Assert(err, jc.ErrorIsNil) 1185 1186 results, err := s.api.RemoveAttachment(params.MachineStorageIds{ 1187 Ids: []params.MachineStorageId{{ 1188 MachineTag: "machine-0", 1189 AttachmentTag: "volume-0-0", 1190 }, { 1191 MachineTag: "machine-0", 1192 AttachmentTag: "volume-1", 1193 }, { 1194 MachineTag: "machine-2", 1195 AttachmentTag: "volume-4", 1196 }, { 1197 MachineTag: "machine-0", 1198 AttachmentTag: "volume-42", 1199 }}, 1200 }) 1201 c.Assert(err, jc.ErrorIsNil) 1202 c.Assert(results, jc.DeepEquals, params.ErrorResults{ 1203 Results: []params.ErrorResult{ 1204 {Error: ¶ms.Error{Message: "removing attachment of volume 0/0 from machine 0: volume attachment is not dying"}}, 1205 {Error: nil}, 1206 {Error: ¶ms.Error{Message: "permission denied", Code: "unauthorized access"}}, 1207 {Error: ¶ms.Error{Message: `removing attachment of volume 42 from machine 0: volume "42" on machine "0" not found`, Code: "not found"}}, 1208 }, 1209 }) 1210 } 1211 1212 func (s *provisionerSuite) TestRemoveFilesystemAttachments(c *gc.C) { 1213 s.setupFilesystems(c) 1214 s.authorizer.EnvironManager = false 1215 1216 err := s.State.DetachFilesystem(names.NewMachineTag("0"), names.NewFilesystemTag("1")) 1217 c.Assert(err, jc.ErrorIsNil) 1218 1219 results, err := s.api.RemoveAttachment(params.MachineStorageIds{ 1220 Ids: []params.MachineStorageId{{ 1221 MachineTag: "machine-0", 1222 AttachmentTag: "filesystem-0-0", 1223 }, { 1224 MachineTag: "machine-0", 1225 AttachmentTag: "filesystem-1", 1226 }, { 1227 MachineTag: "machine-2", 1228 AttachmentTag: "filesystem-4", 1229 }, { 1230 MachineTag: "machine-0", 1231 AttachmentTag: "filesystem-42", 1232 }}, 1233 }) 1234 c.Assert(err, jc.ErrorIsNil) 1235 c.Assert(results, jc.DeepEquals, params.ErrorResults{ 1236 Results: []params.ErrorResult{ 1237 {Error: ¶ms.Error{Message: "removing attachment of filesystem 0/0 from machine 0: filesystem attachment is not dying"}}, 1238 {Error: nil}, 1239 {Error: ¶ms.Error{Message: "permission denied", Code: "unauthorized access"}}, 1240 {Error: ¶ms.Error{Message: `removing attachment of filesystem 42 from machine 0: filesystem "42" on machine "0" not found`, Code: "not found"}}, 1241 }, 1242 }) 1243 } 1244 1245 type byMachineAndEntity []params.MachineStorageId 1246 1247 func (b byMachineAndEntity) Len() int { 1248 return len(b) 1249 } 1250 1251 func (b byMachineAndEntity) Less(i, j int) bool { 1252 if b[i].MachineTag == b[j].MachineTag { 1253 return b[i].AttachmentTag < b[j].AttachmentTag 1254 } 1255 return b[i].MachineTag < b[j].MachineTag 1256 } 1257 1258 func (b byMachineAndEntity) Swap(i, j int) { 1259 b[i], b[j] = b[j], b[i] 1260 }