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