github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/worker/storageprovisioner/mock_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 "strconv" 8 "sync" 9 "time" 10 11 "github.com/juju/errors" 12 "github.com/juju/names" 13 gitjujutesting "github.com/juju/testing" 14 gc "gopkg.in/check.v1" 15 16 apiwatcher "github.com/juju/juju/api/watcher" 17 "github.com/juju/juju/apiserver/common" 18 "github.com/juju/juju/apiserver/params" 19 "github.com/juju/juju/environs/config" 20 "github.com/juju/juju/instance" 21 "github.com/juju/juju/storage" 22 "github.com/juju/juju/testing" 23 ) 24 25 const attachedVolumeId = "1" 26 const needsInstanceVolumeId = "23" 27 28 var dyingVolumeAttachmentId = params.MachineStorageId{ 29 MachineTag: "machine-0", 30 AttachmentTag: "volume-0", 31 } 32 33 var dyingFilesystemAttachmentId = params.MachineStorageId{ 34 MachineTag: "machine-0", 35 AttachmentTag: "filesystem-0", 36 } 37 38 var missingVolumeAttachmentId = params.MachineStorageId{ 39 MachineTag: "machine-3", 40 AttachmentTag: "volume-1", 41 } 42 43 type mockNotifyWatcher struct { 44 changes chan struct{} 45 } 46 47 func (*mockNotifyWatcher) Stop() error { 48 return nil 49 } 50 51 func (*mockNotifyWatcher) Err() error { 52 return nil 53 } 54 55 func (w *mockNotifyWatcher) Changes() <-chan struct{} { 56 return w.changes 57 } 58 59 type mockStringsWatcher struct { 60 changes chan []string 61 } 62 63 func (*mockStringsWatcher) Stop() error { 64 return nil 65 } 66 67 func (*mockStringsWatcher) Err() error { 68 return nil 69 } 70 71 func (w *mockStringsWatcher) Changes() <-chan []string { 72 return w.changes 73 } 74 75 type mockAttachmentsWatcher struct { 76 changes chan []params.MachineStorageId 77 } 78 79 func (*mockAttachmentsWatcher) Stop() error { 80 return nil 81 } 82 83 func (*mockAttachmentsWatcher) Err() error { 84 return nil 85 } 86 87 func (w *mockAttachmentsWatcher) Changes() <-chan []params.MachineStorageId { 88 return w.changes 89 } 90 91 type mockEnvironAccessor struct { 92 watcher *mockNotifyWatcher 93 mu sync.Mutex 94 cfg *config.Config 95 } 96 97 func (e *mockEnvironAccessor) WatchForEnvironConfigChanges() (apiwatcher.NotifyWatcher, error) { 98 return e.watcher, nil 99 } 100 101 func (e *mockEnvironAccessor) EnvironConfig() (*config.Config, error) { 102 e.mu.Lock() 103 cfg := e.cfg 104 e.mu.Unlock() 105 return cfg, nil 106 } 107 108 func (e *mockEnvironAccessor) setConfig(cfg *config.Config) { 109 e.mu.Lock() 110 e.cfg = cfg 111 e.mu.Unlock() 112 } 113 114 func newMockEnvironAccessor(c *gc.C) *mockEnvironAccessor { 115 return &mockEnvironAccessor{ 116 watcher: &mockNotifyWatcher{make(chan struct{}, 1)}, 117 cfg: testing.EnvironConfig(c), 118 } 119 } 120 121 type mockVolumeAccessor struct { 122 volumesWatcher *mockStringsWatcher 123 attachmentsWatcher *mockAttachmentsWatcher 124 blockDevicesWatcher *mockNotifyWatcher 125 provisionedMachines map[string]instance.Id 126 provisionedVolumes map[string]params.Volume 127 provisionedAttachments map[params.MachineStorageId]params.VolumeAttachment 128 blockDevices map[params.MachineStorageId]storage.BlockDevice 129 130 setVolumeInfo func([]params.Volume) ([]params.ErrorResult, error) 131 setVolumeAttachmentInfo func([]params.VolumeAttachment) ([]params.ErrorResult, error) 132 } 133 134 func (m *mockVolumeAccessor) provisionVolume(tag names.VolumeTag) params.Volume { 135 v := params.Volume{ 136 VolumeTag: tag.String(), 137 Info: params.VolumeInfo{ 138 VolumeId: "vol-" + tag.Id(), 139 }, 140 } 141 m.provisionedVolumes[tag.String()] = v 142 return v 143 } 144 145 func (w *mockVolumeAccessor) WatchVolumes() (apiwatcher.StringsWatcher, error) { 146 return w.volumesWatcher, nil 147 } 148 149 func (w *mockVolumeAccessor) WatchVolumeAttachments() (apiwatcher.MachineStorageIdsWatcher, error) { 150 return w.attachmentsWatcher, nil 151 } 152 153 func (w *mockVolumeAccessor) WatchBlockDevices(tag names.MachineTag) (apiwatcher.NotifyWatcher, error) { 154 return w.blockDevicesWatcher, nil 155 } 156 157 func (v *mockVolumeAccessor) Volumes(volumes []names.VolumeTag) ([]params.VolumeResult, error) { 158 var result []params.VolumeResult 159 for _, tag := range volumes { 160 if vol, ok := v.provisionedVolumes[tag.String()]; ok { 161 result = append(result, params.VolumeResult{Result: vol}) 162 } else { 163 result = append(result, params.VolumeResult{ 164 Error: common.ServerError(errors.NotProvisionedf("volume %q", tag.Id())), 165 }) 166 } 167 } 168 return result, nil 169 } 170 171 func (v *mockVolumeAccessor) VolumeAttachments(ids []params.MachineStorageId) ([]params.VolumeAttachmentResult, error) { 172 var result []params.VolumeAttachmentResult 173 for _, id := range ids { 174 if att, ok := v.provisionedAttachments[id]; ok { 175 result = append(result, params.VolumeAttachmentResult{Result: att}) 176 } else { 177 result = append(result, params.VolumeAttachmentResult{ 178 Error: common.ServerError(errors.NotProvisionedf("volume attachment %v", id)), 179 }) 180 } 181 } 182 return result, nil 183 } 184 185 func (v *mockVolumeAccessor) VolumeBlockDevices(ids []params.MachineStorageId) ([]params.BlockDeviceResult, error) { 186 var result []params.BlockDeviceResult 187 for _, id := range ids { 188 if dev, ok := v.blockDevices[id]; ok { 189 result = append(result, params.BlockDeviceResult{Result: dev}) 190 } else { 191 result = append(result, params.BlockDeviceResult{ 192 Error: common.ServerError(errors.NotFoundf("block device for volume attachment %v", id)), 193 }) 194 } 195 } 196 return result, nil 197 } 198 199 func (v *mockVolumeAccessor) VolumeParams(volumes []names.VolumeTag) ([]params.VolumeParamsResult, error) { 200 var result []params.VolumeParamsResult 201 for _, tag := range volumes { 202 // Parameters are returned regardless of whether the volume 203 // exists; this is to support destruction. 204 volumeParams := params.VolumeParams{ 205 VolumeTag: tag.String(), 206 Size: 1024, 207 Provider: "dummy", 208 Attributes: map[string]interface{}{ 209 "persistent": tag.String() == "volume-1", 210 }, 211 Tags: map[string]string{ 212 "very": "fancy", 213 }, 214 } 215 volumeParams.Attachment = ¶ms.VolumeAttachmentParams{ 216 VolumeTag: tag.String(), 217 MachineTag: "machine-1", 218 InstanceId: string(v.provisionedMachines["machine-1"]), 219 Provider: "dummy", 220 ReadOnly: tag.String() == "volume-1", 221 } 222 result = append(result, params.VolumeParamsResult{Result: volumeParams}) 223 } 224 return result, nil 225 } 226 227 func (v *mockVolumeAccessor) VolumeAttachmentParams(ids []params.MachineStorageId) ([]params.VolumeAttachmentParamsResult, error) { 228 var result []params.VolumeAttachmentParamsResult 229 for _, id := range ids { 230 // Parameters are returned regardless of whether the attachment 231 // exists; this is to support reattachment. 232 instanceId, _ := v.provisionedMachines[id.MachineTag] 233 result = append(result, params.VolumeAttachmentParamsResult{Result: params.VolumeAttachmentParams{ 234 MachineTag: id.MachineTag, 235 VolumeTag: id.AttachmentTag, 236 InstanceId: string(instanceId), 237 Provider: "dummy", 238 ReadOnly: id.AttachmentTag == "volume-1", 239 }}) 240 } 241 return result, nil 242 } 243 244 func (v *mockVolumeAccessor) SetVolumeInfo(volumes []params.Volume) ([]params.ErrorResult, error) { 245 if v.setVolumeInfo != nil { 246 return v.setVolumeInfo(volumes) 247 } 248 return make([]params.ErrorResult, len(volumes)), nil 249 } 250 251 func (v *mockVolumeAccessor) SetVolumeAttachmentInfo(volumeAttachments []params.VolumeAttachment) ([]params.ErrorResult, error) { 252 if v.setVolumeAttachmentInfo != nil { 253 return v.setVolumeAttachmentInfo(volumeAttachments) 254 } 255 return make([]params.ErrorResult, len(volumeAttachments)), nil 256 } 257 258 func newMockVolumeAccessor() *mockVolumeAccessor { 259 return &mockVolumeAccessor{ 260 volumesWatcher: &mockStringsWatcher{make(chan []string, 1)}, 261 attachmentsWatcher: &mockAttachmentsWatcher{make(chan []params.MachineStorageId, 1)}, 262 blockDevicesWatcher: &mockNotifyWatcher{make(chan struct{}, 1)}, 263 provisionedMachines: make(map[string]instance.Id), 264 provisionedVolumes: make(map[string]params.Volume), 265 provisionedAttachments: make(map[params.MachineStorageId]params.VolumeAttachment), 266 blockDevices: make(map[params.MachineStorageId]storage.BlockDevice), 267 } 268 } 269 270 type mockFilesystemAccessor struct { 271 filesystemsWatcher *mockStringsWatcher 272 attachmentsWatcher *mockAttachmentsWatcher 273 provisionedMachines map[string]instance.Id 274 provisionedFilesystems map[string]params.Filesystem 275 provisionedAttachments map[params.MachineStorageId]params.FilesystemAttachment 276 277 setFilesystemInfo func([]params.Filesystem) ([]params.ErrorResult, error) 278 setFilesystemAttachmentInfo func([]params.FilesystemAttachment) ([]params.ErrorResult, error) 279 } 280 281 func (m *mockFilesystemAccessor) provisionFilesystem(tag names.FilesystemTag) params.Filesystem { 282 f := params.Filesystem{ 283 FilesystemTag: tag.String(), 284 Info: params.FilesystemInfo{ 285 FilesystemId: "vol-" + tag.Id(), 286 }, 287 } 288 m.provisionedFilesystems[tag.String()] = f 289 return f 290 } 291 292 func (w *mockFilesystemAccessor) WatchFilesystems() (apiwatcher.StringsWatcher, error) { 293 return w.filesystemsWatcher, nil 294 } 295 296 func (w *mockFilesystemAccessor) WatchFilesystemAttachments() (apiwatcher.MachineStorageIdsWatcher, error) { 297 return w.attachmentsWatcher, nil 298 } 299 300 func (v *mockFilesystemAccessor) Filesystems(filesystems []names.FilesystemTag) ([]params.FilesystemResult, error) { 301 var result []params.FilesystemResult 302 for _, tag := range filesystems { 303 if vol, ok := v.provisionedFilesystems[tag.String()]; ok { 304 result = append(result, params.FilesystemResult{Result: vol}) 305 } else { 306 result = append(result, params.FilesystemResult{ 307 Error: common.ServerError(errors.NotProvisionedf("filesystem %q", tag.Id())), 308 }) 309 } 310 } 311 return result, nil 312 } 313 314 func (v *mockFilesystemAccessor) FilesystemAttachments(ids []params.MachineStorageId) ([]params.FilesystemAttachmentResult, error) { 315 var result []params.FilesystemAttachmentResult 316 for _, id := range ids { 317 if att, ok := v.provisionedAttachments[id]; ok { 318 result = append(result, params.FilesystemAttachmentResult{Result: att}) 319 } else { 320 result = append(result, params.FilesystemAttachmentResult{ 321 Error: common.ServerError(errors.NotProvisionedf("filesystem attachment %v", id)), 322 }) 323 } 324 } 325 return result, nil 326 } 327 328 func (v *mockFilesystemAccessor) FilesystemParams(filesystems []names.FilesystemTag) ([]params.FilesystemParamsResult, error) { 329 var result []params.FilesystemParamsResult 330 for _, tag := range filesystems { 331 if _, ok := v.provisionedFilesystems[tag.String()]; ok { 332 result = append(result, params.FilesystemParamsResult{ 333 Error: ¶ms.Error{Message: "already provisioned"}, 334 }) 335 } else { 336 filesystemParams := params.FilesystemParams{ 337 FilesystemTag: tag.String(), 338 Size: 1024, 339 Provider: "dummy", 340 Tags: map[string]string{ 341 "very": "fancy", 342 }, 343 } 344 if _, ok := names.FilesystemMachine(tag); ok { 345 // place all volume-backed filesystems on machine-scoped 346 // volumes with the same ID as the filesystem. 347 filesystemParams.VolumeTag = names.NewVolumeTag(tag.Id()).String() 348 } 349 result = append(result, params.FilesystemParamsResult{Result: filesystemParams}) 350 } 351 } 352 return result, nil 353 } 354 355 func (f *mockFilesystemAccessor) FilesystemAttachmentParams(ids []params.MachineStorageId) ([]params.FilesystemAttachmentParamsResult, error) { 356 var result []params.FilesystemAttachmentParamsResult 357 for _, id := range ids { 358 // Parameters are returned regardless of whether the attachment 359 // exists; this is to support reattachment. 360 instanceId := f.provisionedMachines[id.MachineTag] 361 result = append(result, params.FilesystemAttachmentParamsResult{Result: params.FilesystemAttachmentParams{ 362 MachineTag: id.MachineTag, 363 FilesystemTag: id.AttachmentTag, 364 InstanceId: string(instanceId), 365 Provider: "dummy", 366 ReadOnly: true, 367 }}) 368 } 369 return result, nil 370 } 371 372 func (f *mockFilesystemAccessor) SetFilesystemInfo(filesystems []params.Filesystem) ([]params.ErrorResult, error) { 373 return f.setFilesystemInfo(filesystems) 374 } 375 376 func (f *mockFilesystemAccessor) SetFilesystemAttachmentInfo(filesystemAttachments []params.FilesystemAttachment) ([]params.ErrorResult, error) { 377 if f.setFilesystemAttachmentInfo != nil { 378 return f.setFilesystemAttachmentInfo(filesystemAttachments) 379 } 380 return nil, nil 381 } 382 383 func newMockFilesystemAccessor() *mockFilesystemAccessor { 384 return &mockFilesystemAccessor{ 385 filesystemsWatcher: &mockStringsWatcher{make(chan []string, 1)}, 386 attachmentsWatcher: &mockAttachmentsWatcher{make(chan []params.MachineStorageId, 1)}, 387 provisionedMachines: make(map[string]instance.Id), 388 provisionedFilesystems: make(map[string]params.Filesystem), 389 provisionedAttachments: make(map[params.MachineStorageId]params.FilesystemAttachment), 390 } 391 } 392 393 type mockLifecycleManager struct { 394 life func([]names.Tag) ([]params.LifeResult, error) 395 attachmentLife func(ids []params.MachineStorageId) ([]params.LifeResult, error) 396 removeAttachments func([]params.MachineStorageId) ([]params.ErrorResult, error) 397 remove func([]names.Tag) ([]params.ErrorResult, error) 398 } 399 400 func (m *mockLifecycleManager) Life(tags []names.Tag) ([]params.LifeResult, error) { 401 if m.life != nil { 402 return m.life(tags) 403 } 404 var result []params.LifeResult 405 for _, tag := range tags { 406 id, _ := strconv.Atoi(tag.Id()) 407 if id <= 100 { 408 result = append(result, params.LifeResult{Life: params.Alive}) 409 } else { 410 result = append(result, params.LifeResult{Life: params.Dying}) 411 } 412 } 413 return result, nil 414 } 415 416 func (m *mockLifecycleManager) AttachmentLife(ids []params.MachineStorageId) ([]params.LifeResult, error) { 417 if m.attachmentLife != nil { 418 return m.attachmentLife(ids) 419 } 420 var result []params.LifeResult 421 for _, id := range ids { 422 switch id { 423 case dyingVolumeAttachmentId, dyingFilesystemAttachmentId: 424 result = append(result, params.LifeResult{Life: params.Dying}) 425 case missingVolumeAttachmentId: 426 result = append(result, params.LifeResult{ 427 Error: common.ServerError(errors.NotFoundf("attachment %v", id)), 428 }) 429 default: 430 result = append(result, params.LifeResult{Life: params.Alive}) 431 } 432 } 433 return result, nil 434 } 435 436 func (m *mockLifecycleManager) Remove(tags []names.Tag) ([]params.ErrorResult, error) { 437 if m.remove != nil { 438 return m.remove(tags) 439 } 440 return make([]params.ErrorResult, len(tags)), nil 441 } 442 443 func (m *mockLifecycleManager) RemoveAttachments(ids []params.MachineStorageId) ([]params.ErrorResult, error) { 444 if m.removeAttachments != nil { 445 return m.removeAttachments(ids) 446 } 447 return make([]params.ErrorResult, len(ids)), nil 448 } 449 450 // Set up a dummy storage provider so we can stub out volume creation. 451 type dummyProvider struct { 452 storage.Provider 453 dynamic bool 454 455 volumeSourceFunc func(*config.Config, *storage.Config) (storage.VolumeSource, error) 456 filesystemSourceFunc func(*config.Config, *storage.Config) (storage.FilesystemSource, error) 457 createVolumesFunc func([]storage.VolumeParams) ([]storage.CreateVolumesResult, error) 458 attachVolumesFunc func([]storage.VolumeAttachmentParams) ([]storage.AttachVolumesResult, error) 459 detachVolumesFunc func([]storage.VolumeAttachmentParams) ([]error, error) 460 detachFilesystemsFunc func([]storage.FilesystemAttachmentParams) ([]error, error) 461 destroyVolumesFunc func([]string) ([]error, error) 462 } 463 464 type dummyVolumeSource struct { 465 storage.VolumeSource 466 provider *dummyProvider 467 createVolumesArgs [][]storage.VolumeParams 468 } 469 470 type dummyFilesystemSource struct { 471 storage.FilesystemSource 472 provider *dummyProvider 473 createFilesystemsArgs [][]storage.FilesystemParams 474 } 475 476 func (p *dummyProvider) VolumeSource(environConfig *config.Config, providerConfig *storage.Config) (storage.VolumeSource, error) { 477 if p.volumeSourceFunc != nil { 478 return p.volumeSourceFunc(environConfig, providerConfig) 479 } 480 return &dummyVolumeSource{provider: p}, nil 481 } 482 483 func (p *dummyProvider) FilesystemSource(environConfig *config.Config, providerConfig *storage.Config) (storage.FilesystemSource, error) { 484 if p.filesystemSourceFunc != nil { 485 return p.filesystemSourceFunc(environConfig, providerConfig) 486 } 487 return &dummyFilesystemSource{provider: p}, nil 488 } 489 490 func (p *dummyProvider) Dynamic() bool { 491 return p.dynamic 492 } 493 494 func (*dummyVolumeSource) ValidateVolumeParams(params storage.VolumeParams) error { 495 return nil 496 } 497 498 // CreateVolumes makes some volumes that we can check later to ensure things went as expected. 499 func (s *dummyVolumeSource) CreateVolumes(params []storage.VolumeParams) ([]storage.CreateVolumesResult, error) { 500 if s.provider != nil && s.provider.createVolumesFunc != nil { 501 return s.provider.createVolumesFunc(params) 502 } 503 504 paramsCopy := make([]storage.VolumeParams, len(params)) 505 copy(paramsCopy, params) 506 s.createVolumesArgs = append(s.createVolumesArgs, paramsCopy) 507 508 results := make([]storage.CreateVolumesResult, len(params)) 509 for i, p := range params { 510 persistent, _ := p.Attributes["persistent"].(bool) 511 results[i].Volume = &storage.Volume{ 512 p.Tag, 513 storage.VolumeInfo{ 514 Size: p.Size, 515 HardwareId: "serial-" + p.Tag.Id(), 516 VolumeId: "id-" + p.Tag.Id(), 517 Persistent: persistent, 518 }, 519 } 520 } 521 return results, nil 522 } 523 524 // DestroyVolumes destroys volumes. 525 func (s *dummyVolumeSource) DestroyVolumes(volumeIds []string) ([]error, error) { 526 if s.provider.destroyVolumesFunc != nil { 527 return s.provider.destroyVolumesFunc(volumeIds) 528 } 529 return make([]error, len(volumeIds)), nil 530 } 531 532 // AttachVolumes attaches volumes to machines. 533 func (s *dummyVolumeSource) AttachVolumes(params []storage.VolumeAttachmentParams) ([]storage.AttachVolumesResult, error) { 534 if s.provider != nil && s.provider.attachVolumesFunc != nil { 535 return s.provider.attachVolumesFunc(params) 536 } 537 538 results := make([]storage.AttachVolumesResult, len(params)) 539 for i, p := range params { 540 if p.VolumeId == "" { 541 panic("AttachVolumes called with unprovisioned volume") 542 } 543 if p.InstanceId == "" { 544 panic("AttachVolumes called with unprovisioned machine") 545 } 546 results[i].VolumeAttachment = &storage.VolumeAttachment{ 547 p.Volume, 548 p.Machine, 549 storage.VolumeAttachmentInfo{ 550 DeviceName: "/dev/sda" + p.Volume.Id(), 551 ReadOnly: p.ReadOnly, 552 }, 553 } 554 } 555 return results, nil 556 } 557 558 // DetachVolumes detaches volumes from machines. 559 func (s *dummyVolumeSource) DetachVolumes(params []storage.VolumeAttachmentParams) ([]error, error) { 560 if s.provider.detachVolumesFunc != nil { 561 return s.provider.detachVolumesFunc(params) 562 } 563 return make([]error, len(params)), nil 564 } 565 566 func (*dummyFilesystemSource) ValidateFilesystemParams(params storage.FilesystemParams) error { 567 return nil 568 } 569 570 // CreateFilesystems makes some filesystems that we can check later to ensure things went as expected. 571 func (s *dummyFilesystemSource) CreateFilesystems(params []storage.FilesystemParams) ([]storage.CreateFilesystemsResult, error) { 572 paramsCopy := make([]storage.FilesystemParams, len(params)) 573 copy(paramsCopy, params) 574 s.createFilesystemsArgs = append(s.createFilesystemsArgs, paramsCopy) 575 576 results := make([]storage.CreateFilesystemsResult, len(params)) 577 for i, p := range params { 578 results[i].Filesystem = &storage.Filesystem{ 579 Tag: p.Tag, 580 FilesystemInfo: storage.FilesystemInfo{ 581 Size: p.Size, 582 FilesystemId: "id-" + p.Tag.Id(), 583 }, 584 } 585 } 586 return results, nil 587 } 588 589 // AttachFilesystems attaches filesystems to machines. 590 func (*dummyFilesystemSource) AttachFilesystems(params []storage.FilesystemAttachmentParams) ([]storage.AttachFilesystemsResult, error) { 591 results := make([]storage.AttachFilesystemsResult, len(params)) 592 for i, p := range params { 593 if p.FilesystemId == "" { 594 panic("AttachFilesystems called with unprovisioned filesystem") 595 } 596 if p.InstanceId == "" { 597 panic("AttachFilesystems called with unprovisioned machine") 598 } 599 results[i].FilesystemAttachment = &storage.FilesystemAttachment{ 600 p.Filesystem, 601 p.Machine, 602 storage.FilesystemAttachmentInfo{ 603 Path: "/srv/" + p.FilesystemId, 604 }, 605 } 606 } 607 return results, nil 608 } 609 610 // DetachFilesystems detaches filesystems from machines. 611 func (s *dummyFilesystemSource) DetachFilesystems(params []storage.FilesystemAttachmentParams) ([]error, error) { 612 if s.provider.detachFilesystemsFunc != nil { 613 return s.provider.detachFilesystemsFunc(params) 614 } 615 return make([]error, len(params)), nil 616 } 617 618 type mockManagedFilesystemSource struct { 619 blockDevices map[names.VolumeTag]storage.BlockDevice 620 filesystems map[names.FilesystemTag]storage.Filesystem 621 } 622 623 func (s *mockManagedFilesystemSource) ValidateFilesystemParams(params storage.FilesystemParams) error { 624 return nil 625 } 626 627 func (s *mockManagedFilesystemSource) CreateFilesystems(args []storage.FilesystemParams) ([]storage.CreateFilesystemsResult, error) { 628 results := make([]storage.CreateFilesystemsResult, len(args)) 629 for i, arg := range args { 630 blockDevice, ok := s.blockDevices[arg.Volume] 631 if !ok { 632 results[i].Error = errors.Errorf("filesystem %v's backing-volume is not attached", arg.Tag.Id()) 633 continue 634 } 635 results[i].Filesystem = &storage.Filesystem{ 636 Tag: arg.Tag, 637 FilesystemInfo: storage.FilesystemInfo{ 638 Size: blockDevice.Size, 639 FilesystemId: blockDevice.DeviceName, 640 }, 641 } 642 } 643 return results, nil 644 } 645 646 func (s *mockManagedFilesystemSource) DestroyFilesystems(filesystemIds []string) ([]error, error) { 647 return make([]error, len(filesystemIds)), nil 648 } 649 650 func (s *mockManagedFilesystemSource) AttachFilesystems(args []storage.FilesystemAttachmentParams) ([]storage.AttachFilesystemsResult, error) { 651 results := make([]storage.AttachFilesystemsResult, len(args)) 652 for i, arg := range args { 653 if arg.FilesystemId == "" { 654 panic("AttachFilesystems called with unprovisioned filesystem") 655 } 656 if arg.InstanceId == "" { 657 panic("AttachFilesystems called with unprovisioned machine") 658 } 659 filesystem, ok := s.filesystems[arg.Filesystem] 660 if !ok { 661 results[i].Error = errors.Errorf("filesystem %v has not been created", arg.Filesystem.Id()) 662 continue 663 } 664 blockDevice, ok := s.blockDevices[filesystem.Volume] 665 if !ok { 666 results[i].Error = errors.Errorf("filesystem %v's backing-volume is not attached", filesystem.Tag.Id()) 667 continue 668 } 669 results[i].FilesystemAttachment = &storage.FilesystemAttachment{ 670 arg.Filesystem, 671 arg.Machine, 672 storage.FilesystemAttachmentInfo{ 673 Path: "/mnt/" + blockDevice.DeviceName, 674 ReadOnly: arg.ReadOnly, 675 }, 676 } 677 } 678 return results, nil 679 } 680 681 func (s *mockManagedFilesystemSource) DetachFilesystems(params []storage.FilesystemAttachmentParams) ([]error, error) { 682 return nil, errors.NotImplementedf("DetachFilesystems") 683 } 684 685 type mockMachineAccessor struct { 686 instanceIds map[names.MachineTag]instance.Id 687 watcher *mockNotifyWatcher 688 } 689 690 func (a *mockMachineAccessor) WatchMachine(names.MachineTag) (apiwatcher.NotifyWatcher, error) { 691 return a.watcher, nil 692 } 693 694 func (a *mockMachineAccessor) InstanceIds(tags []names.MachineTag) ([]params.StringResult, error) { 695 results := make([]params.StringResult, len(tags)) 696 for i, tag := range tags { 697 instanceId, ok := a.instanceIds[tag] 698 if !ok { 699 results[i].Error = ¶ms.Error{Code: params.CodeNotFound} 700 } else if instanceId == "" { 701 results[i].Error = ¶ms.Error{Code: params.CodeNotProvisioned} 702 } else { 703 results[i].Result = string(instanceId) 704 } 705 } 706 return results, nil 707 } 708 709 func newMockMachineAccessor(c *gc.C) *mockMachineAccessor { 710 return &mockMachineAccessor{ 711 instanceIds: make(map[names.MachineTag]instance.Id), 712 watcher: &mockNotifyWatcher{make(chan struct{}, 1)}, 713 } 714 } 715 716 type mockClock struct { 717 gitjujutesting.Stub 718 now time.Time 719 nowFunc func() time.Time 720 afterFunc func(time.Duration) <-chan time.Time 721 } 722 723 func (c *mockClock) Now() time.Time { 724 c.MethodCall(c, "Now") 725 if c.nowFunc != nil { 726 return c.nowFunc() 727 } 728 return c.now 729 } 730 731 func (c *mockClock) After(d time.Duration) <-chan time.Time { 732 c.MethodCall(c, "After", d) 733 if c.afterFunc != nil { 734 return c.afterFunc(d) 735 } 736 if d > 0 { 737 c.now = c.now.Add(d) 738 } 739 ch := make(chan time.Time, 1) 740 ch <- c.now 741 return ch 742 } 743 744 type mockStatusSetter struct { 745 args []params.EntityStatusArgs 746 setStatus func([]params.EntityStatusArgs) error 747 } 748 749 func (m *mockStatusSetter) SetStatus(args []params.EntityStatusArgs) error { 750 if m.setStatus != nil { 751 return m.setStatus(args) 752 } 753 m.args = append(m.args, args...) 754 return nil 755 }