github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/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 MachineTag: "machine-0", 745 AttachmentTag: "volume-1", 746 }, { 747 MachineTag: "machine-0", 748 AttachmentTag: "volume-2", 749 }, { 750 MachineTag: "machine-0", 751 AttachmentTag: "volume-3", 752 }}, 753 }, 754 { 755 MachineStorageIdsWatcherId: "2", 756 Changes: []params.MachineStorageId{{ 757 MachineTag: "machine-0", 758 AttachmentTag: "volume-1", 759 }, { 760 MachineTag: "machine-0", 761 AttachmentTag: "volume-2", 762 }, { 763 MachineTag: "machine-0", 764 AttachmentTag: "volume-3", 765 }, { 766 MachineTag: "machine-2", 767 AttachmentTag: "volume-4", 768 }}, 769 }, 770 {Error: apiservertesting.ErrUnauthorized}, 771 {Error: apiservertesting.ErrUnauthorized}, 772 {Error: apiservertesting.ErrUnauthorized}, 773 }, 774 }) 775 776 // Verify the resources were registered and stop them when done. 777 c.Assert(s.resources.Count(), gc.Equals, 2) 778 v0Watcher := s.resources.Get("1") 779 defer statetesting.AssertStop(c, v0Watcher) 780 v1Watcher := s.resources.Get("2") 781 defer statetesting.AssertStop(c, v1Watcher) 782 783 // Check that the Watch has consumed the initial events ("returned" in 784 // the Watch call) 785 wc := statetesting.NewStringsWatcherC(c, s.State, v0Watcher.(state.StringsWatcher)) 786 wc.AssertNoChange() 787 wc = statetesting.NewStringsWatcherC(c, s.State, v1Watcher.(state.StringsWatcher)) 788 wc.AssertNoChange() 789 } 790 791 func (s *provisionerSuite) TestWatchFilesystems(c *gc.C) { 792 s.setupFilesystems(c) 793 c.Assert(s.resources.Count(), gc.Equals, 0) 794 795 args := params.Entities{Entities: []params.Entity{ 796 {"machine-0"}, 797 {s.State.EnvironTag().String()}, 798 {"environ-adb650da-b77b-4ee8-9cbb-d57a9a592847"}, 799 {"machine-1"}, 800 {"machine-42"}}, 801 } 802 result, err := s.api.WatchFilesystems(args) 803 c.Assert(err, jc.ErrorIsNil) 804 sort.Strings(result.Results[1].Changes) 805 c.Assert(result, jc.DeepEquals, params.StringsWatchResults{ 806 Results: []params.StringsWatchResult{ 807 { 808 StringsWatcherId: "1", 809 Changes: []string{"0/0"}, 810 }, 811 { 812 StringsWatcherId: "2", 813 Changes: []string{"1", "2", "3"}, 814 }, 815 {Error: apiservertesting.ErrUnauthorized}, 816 {Error: apiservertesting.ErrUnauthorized}, 817 {Error: apiservertesting.ErrUnauthorized}, 818 }, 819 }) 820 821 // Verify the resources were registered and stop them when done. 822 c.Assert(s.resources.Count(), gc.Equals, 2) 823 v0Watcher := s.resources.Get("1") 824 defer statetesting.AssertStop(c, v0Watcher) 825 v1Watcher := s.resources.Get("2") 826 defer statetesting.AssertStop(c, v1Watcher) 827 828 // Check that the Watch has consumed the initial events ("returned" in 829 // the Watch call) 830 wc := statetesting.NewStringsWatcherC(c, s.State, v0Watcher.(state.StringsWatcher)) 831 wc.AssertNoChange() 832 wc = statetesting.NewStringsWatcherC(c, s.State, v1Watcher.(state.StringsWatcher)) 833 wc.AssertNoChange() 834 } 835 836 func (s *provisionerSuite) TestWatchFilesystemAttachments(c *gc.C) { 837 s.setupFilesystems(c) 838 c.Assert(s.resources.Count(), gc.Equals, 0) 839 840 args := params.Entities{Entities: []params.Entity{ 841 {"machine-0"}, 842 {s.State.EnvironTag().String()}, 843 {"environ-adb650da-b77b-4ee8-9cbb-d57a9a592847"}, 844 {"machine-1"}, 845 {"machine-42"}}, 846 } 847 result, err := s.api.WatchFilesystemAttachments(args) 848 c.Assert(err, jc.ErrorIsNil) 849 sort.Sort(byMachineAndEntity(result.Results[0].Changes)) 850 sort.Sort(byMachineAndEntity(result.Results[1].Changes)) 851 c.Assert(result, jc.DeepEquals, params.MachineStorageIdsWatchResults{ 852 Results: []params.MachineStorageIdsWatchResult{ 853 { 854 MachineStorageIdsWatcherId: "1", 855 Changes: []params.MachineStorageId{{ 856 MachineTag: "machine-0", 857 AttachmentTag: "filesystem-0-0", 858 }, { 859 MachineTag: "machine-0", 860 AttachmentTag: "filesystem-1", 861 }, { 862 MachineTag: "machine-0", 863 AttachmentTag: "filesystem-2", 864 }}, 865 }, 866 { 867 MachineStorageIdsWatcherId: "2", 868 Changes: []params.MachineStorageId{{ 869 MachineTag: "machine-0", 870 AttachmentTag: "filesystem-1", 871 }, { 872 MachineTag: "machine-0", 873 AttachmentTag: "filesystem-2", 874 }, { 875 MachineTag: "machine-2", 876 AttachmentTag: "filesystem-3", 877 }}, 878 }, 879 {Error: apiservertesting.ErrUnauthorized}, 880 {Error: apiservertesting.ErrUnauthorized}, 881 {Error: apiservertesting.ErrUnauthorized}, 882 }, 883 }) 884 885 // Verify the resources were registered and stop them when done. 886 c.Assert(s.resources.Count(), gc.Equals, 2) 887 v0Watcher := s.resources.Get("1") 888 defer statetesting.AssertStop(c, v0Watcher) 889 v1Watcher := s.resources.Get("2") 890 defer statetesting.AssertStop(c, v1Watcher) 891 892 // Check that the Watch has consumed the initial events ("returned" in 893 // the Watch call) 894 wc := statetesting.NewStringsWatcherC(c, s.State, v0Watcher.(state.StringsWatcher)) 895 wc.AssertNoChange() 896 wc = statetesting.NewStringsWatcherC(c, s.State, v1Watcher.(state.StringsWatcher)) 897 wc.AssertNoChange() 898 } 899 900 func (s *provisionerSuite) TestWatchBlockDevices(c *gc.C) { 901 s.factory.MakeMachine(c, nil) 902 c.Assert(s.resources.Count(), gc.Equals, 0) 903 904 args := params.Entities{Entities: []params.Entity{ 905 {"machine-0"}, 906 {"service-mysql"}, 907 {"machine-1"}, 908 {"machine-42"}}, 909 } 910 results, err := s.api.WatchBlockDevices(args) 911 c.Assert(err, jc.ErrorIsNil) 912 c.Assert(results, jc.DeepEquals, params.NotifyWatchResults{ 913 Results: []params.NotifyWatchResult{ 914 {NotifyWatcherId: "1"}, 915 {Error: ¶ms.Error{Message: `"service-mysql" is not a valid machine tag`}}, 916 {Error: apiservertesting.ErrUnauthorized}, 917 {Error: apiservertesting.ErrUnauthorized}, 918 }, 919 }) 920 921 // Verify the resources were registered and stop them when done. 922 c.Assert(s.resources.Count(), gc.Equals, 1) 923 watcher := s.resources.Get("1") 924 defer statetesting.AssertStop(c, watcher) 925 926 // Check that the Watch has consumed the initial event. 927 wc := statetesting.NewNotifyWatcherC(c, s.State, watcher.(state.NotifyWatcher)) 928 wc.AssertNoChange() 929 930 m, err := s.State.Machine("0") 931 c.Assert(err, jc.ErrorIsNil) 932 err = m.SetMachineBlockDevices(state.BlockDeviceInfo{ 933 DeviceName: "sda", 934 Size: 123, 935 }) 936 c.Assert(err, jc.ErrorIsNil) 937 wc.AssertOneChange() 938 } 939 940 func (s *provisionerSuite) TestVolumeBlockDevices(c *gc.C) { 941 s.setupVolumes(c) 942 s.factory.MakeMachine(c, nil) 943 944 err := s.State.SetVolumeAttachmentInfo( 945 names.NewMachineTag("0"), 946 names.NewVolumeTag("0/0"), 947 state.VolumeAttachmentInfo{}, 948 ) 949 c.Assert(err, jc.ErrorIsNil) 950 951 machine0, err := s.State.Machine("0") 952 c.Assert(err, jc.ErrorIsNil) 953 err = machine0.SetMachineBlockDevices(state.BlockDeviceInfo{ 954 DeviceName: "sda", 955 Size: 123, 956 HardwareId: "123", // matches volume-0/0 957 }) 958 c.Assert(err, jc.ErrorIsNil) 959 960 args := params.MachineStorageIds{Ids: []params.MachineStorageId{ 961 {MachineTag: "machine-0", AttachmentTag: "volume-0-0"}, 962 {MachineTag: "machine-0", AttachmentTag: "volume-0-1"}, 963 {MachineTag: "machine-0", AttachmentTag: "volume-0-2"}, 964 {MachineTag: "machine-1", AttachmentTag: "volume-1"}, 965 {MachineTag: "machine-42", AttachmentTag: "volume-42"}, 966 {MachineTag: "service-mysql", AttachmentTag: "volume-1"}, 967 }} 968 results, err := s.api.VolumeBlockDevices(args) 969 c.Assert(err, jc.ErrorIsNil) 970 c.Assert(results, jc.DeepEquals, params.BlockDeviceResults{ 971 Results: []params.BlockDeviceResult{ 972 {Result: storage.BlockDevice{ 973 DeviceName: "sda", 974 Size: 123, 975 HardwareId: "123", 976 }}, 977 {Error: apiservertesting.ErrUnauthorized}, 978 {Error: apiservertesting.ErrUnauthorized}, 979 {Error: apiservertesting.ErrUnauthorized}, 980 {Error: apiservertesting.ErrUnauthorized}, 981 {Error: ¶ms.Error{Message: `"service-mysql" is not a valid machine tag`}}, 982 }, 983 }) 984 } 985 986 func (s *provisionerSuite) TestLife(c *gc.C) { 987 s.setupVolumes(c) 988 args := params.Entities{Entities: []params.Entity{{"volume-0-0"}, {"volume-1"}, {"volume-42"}}} 989 result, err := s.api.Life(args) 990 c.Assert(err, jc.ErrorIsNil) 991 c.Assert(result, gc.DeepEquals, params.LifeResults{ 992 Results: []params.LifeResult{ 993 {Life: params.Alive}, 994 {Life: params.Alive}, 995 {Error: common.ServerError(errors.NotFoundf(`volume "42"`))}, 996 }, 997 }) 998 } 999 1000 func (s *provisionerSuite) TestAttachmentLife(c *gc.C) { 1001 s.setupVolumes(c) 1002 1003 // TODO(axw) test filesystem attachment life 1004 // TODO(axw) test Dying 1005 1006 results, err := s.api.AttachmentLife(params.MachineStorageIds{ 1007 Ids: []params.MachineStorageId{{ 1008 MachineTag: "machine-0", 1009 AttachmentTag: "volume-0-0", 1010 }, { 1011 MachineTag: "machine-0", 1012 AttachmentTag: "volume-1", 1013 }, { 1014 MachineTag: "machine-2", 1015 AttachmentTag: "volume-4", 1016 }, { 1017 MachineTag: "machine-0", 1018 AttachmentTag: "volume-42", 1019 }}, 1020 }) 1021 c.Assert(err, jc.ErrorIsNil) 1022 c.Assert(results, jc.DeepEquals, params.LifeResults{ 1023 Results: []params.LifeResult{ 1024 {Life: params.Alive}, 1025 {Life: params.Alive}, 1026 {Life: params.Alive}, 1027 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1028 }, 1029 }) 1030 } 1031 1032 func (s *provisionerSuite) TestEnsureDead(c *gc.C) { 1033 s.setupVolumes(c) 1034 args := params.Entities{Entities: []params.Entity{{"volume-0-0"}, {"volume-1"}, {"volume-42"}}} 1035 result, err := s.api.EnsureDead(args) 1036 c.Assert(err, jc.ErrorIsNil) 1037 // TODO(wallyworld) - this test will be updated when EnsureDead is supported 1038 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1039 Results: []params.ErrorResult{ 1040 {Error: common.ServerError(common.NotSupportedError(names.NewVolumeTag("0/0"), "ensuring death"))}, 1041 {Error: common.ServerError(common.NotSupportedError(names.NewVolumeTag("1"), "ensuring death"))}, 1042 {Error: common.ServerError(errors.NotFoundf(`volume "42"`))}, 1043 }, 1044 }) 1045 } 1046 1047 func (s *provisionerSuite) TestWatchForEnvironConfigChanges(c *gc.C) { 1048 result, err := s.api.WatchForEnvironConfigChanges() 1049 c.Assert(err, jc.ErrorIsNil) 1050 c.Assert(result.NotifyWatcherId, gc.Equals, "1") 1051 1052 // Verify the resource was registered and stop it when done. 1053 c.Assert(s.resources.Count(), gc.Equals, 1) 1054 watcher := s.resources.Get("1") 1055 defer statetesting.AssertStop(c, watcher) 1056 1057 // Check that the Watch has consumed the initial events ("returned" in 1058 // the Watch call) 1059 wc := statetesting.NewNotifyWatcherC(c, s.State, watcher.(state.NotifyWatcher)) 1060 wc.AssertNoChange() 1061 1062 // Updating config should trigger the watcher. 1063 err = s.State.UpdateEnvironConfig(map[string]interface{}{"what": "ever"}, nil, nil) 1064 c.Assert(err, jc.ErrorIsNil) 1065 wc.AssertOneChange() 1066 } 1067 1068 func (s *provisionerSuite) TestEnvironConfig(c *gc.C) { 1069 stateEnvironConfig, err := s.State.EnvironConfig() 1070 c.Assert(err, jc.ErrorIsNil) 1071 1072 result, err := s.api.EnvironConfig() 1073 c.Assert(err, jc.ErrorIsNil) 1074 c.Assert(result.Config, jc.DeepEquals, params.EnvironConfig(stateEnvironConfig.AllAttrs())) 1075 } 1076 1077 func (s *provisionerSuite) TestRemoveVolumesEnvironManager(c *gc.C) { 1078 s.setupVolumes(c) 1079 args := params.Entities{Entities: []params.Entity{ 1080 {"volume-1-0"}, {"volume-1"}, {"volume-2"}, {"volume-42"}, 1081 {"volume-invalid"}, {"machine-0"}, 1082 }} 1083 1084 err := s.State.DetachVolume(names.NewMachineTag("0"), names.NewVolumeTag("1")) 1085 c.Assert(err, jc.ErrorIsNil) 1086 err = s.State.RemoveVolumeAttachment(names.NewMachineTag("0"), names.NewVolumeTag("1")) 1087 c.Assert(err, jc.ErrorIsNil) 1088 err = s.State.DestroyVolume(names.NewVolumeTag("1")) 1089 c.Assert(err, jc.ErrorIsNil) 1090 1091 result, err := s.api.Remove(args) 1092 c.Assert(err, jc.ErrorIsNil) 1093 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1094 Results: []params.ErrorResult{ 1095 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1096 {Error: nil}, 1097 {Error: ¶ms.Error{Message: "removing volume 2: volume is not dead"}}, 1098 {Error: nil}, 1099 {Error: ¶ms.Error{Message: `"volume-invalid" is not a valid volume tag`}}, 1100 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1101 }, 1102 }) 1103 } 1104 1105 func (s *provisionerSuite) TestRemoveFilesystemsEnvironManager(c *gc.C) { 1106 s.setupFilesystems(c) 1107 args := params.Entities{Entities: []params.Entity{ 1108 {"filesystem-1-0"}, {"filesystem-1"}, {"filesystem-2"}, {"filesystem-42"}, 1109 {"filesystem-invalid"}, {"machine-0"}, 1110 }} 1111 1112 err := s.State.DetachFilesystem(names.NewMachineTag("0"), names.NewFilesystemTag("1")) 1113 c.Assert(err, jc.ErrorIsNil) 1114 err = s.State.RemoveFilesystemAttachment(names.NewMachineTag("0"), names.NewFilesystemTag("1")) 1115 c.Assert(err, jc.ErrorIsNil) 1116 err = s.State.DestroyFilesystem(names.NewFilesystemTag("1")) 1117 c.Assert(err, jc.ErrorIsNil) 1118 1119 result, err := s.api.Remove(args) 1120 c.Assert(err, jc.ErrorIsNil) 1121 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1122 Results: []params.ErrorResult{ 1123 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1124 {Error: nil}, 1125 {Error: ¶ms.Error{Message: "removing filesystem 2: filesystem is not dead"}}, 1126 {Error: nil}, 1127 {Error: ¶ms.Error{Message: `"filesystem-invalid" is not a valid filesystem tag`}}, 1128 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1129 }, 1130 }) 1131 } 1132 1133 func (s *provisionerSuite) TestRemoveVolumesMachineAgent(c *gc.C) { 1134 s.setupVolumes(c) 1135 s.authorizer.EnvironManager = false 1136 args := params.Entities{Entities: []params.Entity{ 1137 {"volume-0-0"}, {"volume-0-42"}, {"volume-42"}, 1138 {"volume-invalid"}, {"machine-0"}, 1139 }} 1140 1141 err := s.State.DetachVolume(names.NewMachineTag("0"), names.NewVolumeTag("0/0")) 1142 c.Assert(err, jc.ErrorIsNil) 1143 err = s.State.RemoveVolumeAttachment(names.NewMachineTag("0"), names.NewVolumeTag("0/0")) 1144 c.Assert(err, jc.ErrorIsNil) 1145 err = s.State.DestroyVolume(names.NewVolumeTag("0/0")) 1146 c.Assert(err, jc.ErrorIsNil) 1147 1148 result, err := s.api.Remove(args) 1149 c.Assert(err, jc.ErrorIsNil) 1150 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1151 Results: []params.ErrorResult{ 1152 {Error: nil}, 1153 {Error: nil}, 1154 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1155 {Error: ¶ms.Error{Message: `"volume-invalid" is not a valid volume tag`}}, 1156 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1157 }, 1158 }) 1159 } 1160 1161 func (s *provisionerSuite) TestRemoveFilesystemsMachineAgent(c *gc.C) { 1162 s.setupFilesystems(c) 1163 s.authorizer.EnvironManager = false 1164 args := params.Entities{Entities: []params.Entity{ 1165 {"filesystem-0-0"}, {"filesystem-0-42"}, {"filesystem-42"}, 1166 {"filesystem-invalid"}, {"machine-0"}, 1167 }} 1168 1169 err := s.State.DetachFilesystem(names.NewMachineTag("0"), names.NewFilesystemTag("0/0")) 1170 c.Assert(err, jc.ErrorIsNil) 1171 err = s.State.RemoveFilesystemAttachment(names.NewMachineTag("0"), names.NewFilesystemTag("0/0")) 1172 c.Assert(err, jc.ErrorIsNil) 1173 err = s.State.DestroyFilesystem(names.NewFilesystemTag("0/0")) 1174 c.Assert(err, jc.ErrorIsNil) 1175 1176 result, err := s.api.Remove(args) 1177 c.Assert(err, jc.ErrorIsNil) 1178 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1179 Results: []params.ErrorResult{ 1180 {Error: nil}, 1181 {Error: nil}, 1182 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1183 {Error: ¶ms.Error{Message: `"filesystem-invalid" is not a valid filesystem tag`}}, 1184 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1185 }, 1186 }) 1187 } 1188 1189 func (s *provisionerSuite) TestRemoveVolumeAttachments(c *gc.C) { 1190 s.setupVolumes(c) 1191 s.authorizer.EnvironManager = false 1192 1193 err := s.State.DetachVolume(names.NewMachineTag("0"), names.NewVolumeTag("1")) 1194 c.Assert(err, jc.ErrorIsNil) 1195 1196 results, err := s.api.RemoveAttachment(params.MachineStorageIds{ 1197 Ids: []params.MachineStorageId{{ 1198 MachineTag: "machine-0", 1199 AttachmentTag: "volume-0-0", 1200 }, { 1201 MachineTag: "machine-0", 1202 AttachmentTag: "volume-1", 1203 }, { 1204 MachineTag: "machine-2", 1205 AttachmentTag: "volume-4", 1206 }, { 1207 MachineTag: "machine-0", 1208 AttachmentTag: "volume-42", 1209 }}, 1210 }) 1211 c.Assert(err, jc.ErrorIsNil) 1212 c.Assert(results, jc.DeepEquals, params.ErrorResults{ 1213 Results: []params.ErrorResult{ 1214 {Error: ¶ms.Error{Message: "removing attachment of volume 0/0 from machine 0: volume attachment is not dying"}}, 1215 {Error: nil}, 1216 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1217 {Error: ¶ms.Error{`removing attachment of volume 42 from machine 0: volume "42" on machine "0" not found`, "not found"}}, 1218 }, 1219 }) 1220 } 1221 1222 func (s *provisionerSuite) TestRemoveFilesystemAttachments(c *gc.C) { 1223 s.setupFilesystems(c) 1224 s.authorizer.EnvironManager = false 1225 1226 err := s.State.DetachFilesystem(names.NewMachineTag("0"), names.NewFilesystemTag("1")) 1227 c.Assert(err, jc.ErrorIsNil) 1228 1229 results, err := s.api.RemoveAttachment(params.MachineStorageIds{ 1230 Ids: []params.MachineStorageId{{ 1231 MachineTag: "machine-0", 1232 AttachmentTag: "filesystem-0-0", 1233 }, { 1234 MachineTag: "machine-0", 1235 AttachmentTag: "filesystem-1", 1236 }, { 1237 MachineTag: "machine-2", 1238 AttachmentTag: "filesystem-4", 1239 }, { 1240 MachineTag: "machine-0", 1241 AttachmentTag: "filesystem-42", 1242 }}, 1243 }) 1244 c.Assert(err, jc.ErrorIsNil) 1245 c.Assert(results, jc.DeepEquals, params.ErrorResults{ 1246 Results: []params.ErrorResult{ 1247 {Error: ¶ms.Error{Message: "removing attachment of filesystem 0/0 from machine 0: filesystem attachment is not dying"}}, 1248 {Error: nil}, 1249 {Error: ¶ms.Error{"permission denied", "unauthorized access"}}, 1250 {Error: ¶ms.Error{`removing attachment of filesystem 42 from machine 0: filesystem "42" on machine "0" not found`, "not found"}}, 1251 }, 1252 }) 1253 } 1254 1255 type byMachineAndEntity []params.MachineStorageId 1256 1257 func (b byMachineAndEntity) Len() int { 1258 return len(b) 1259 } 1260 1261 func (b byMachineAndEntity) Less(i, j int) bool { 1262 if b[i].MachineTag == b[j].MachineTag { 1263 return b[i].AttachmentTag < b[j].AttachmentTag 1264 } 1265 return b[i].MachineTag < b[j].MachineTag 1266 } 1267 1268 func (b byMachineAndEntity) Swap(i, j int) { 1269 b[i], b[j] = b[j], b[i] 1270 }