github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/facades/controller/caasunitprovisioner/mock_test.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package caasunitprovisioner_test 5 6 import ( 7 "strings" 8 "time" 9 10 "github.com/juju/charm/v12" 11 "github.com/juju/errors" 12 "github.com/juju/names/v5" 13 "github.com/juju/testing" 14 15 charmscommon "github.com/juju/juju/apiserver/common/charms" 16 "github.com/juju/juju/apiserver/facades/controller/caasunitprovisioner" 17 k8sconstants "github.com/juju/juju/caas/kubernetes/provider/constants" 18 "github.com/juju/juju/controller" 19 coreconfig "github.com/juju/juju/core/config" 20 "github.com/juju/juju/core/constraints" 21 "github.com/juju/juju/core/network" 22 "github.com/juju/juju/core/status" 23 "github.com/juju/juju/environs/config" 24 "github.com/juju/juju/state" 25 statetesting "github.com/juju/juju/state/testing" 26 "github.com/juju/juju/storage" 27 "github.com/juju/juju/storage/poolmanager" 28 coretesting "github.com/juju/juju/testing" 29 jujuversion "github.com/juju/juju/version" 30 ) 31 32 type mockState struct { 33 testing.Stub 34 application mockApplication 35 applicationsWatcher *statetesting.MockStringsWatcher 36 model mockModel 37 unit mockUnit 38 } 39 40 func (st *mockState) WatchApplications() state.StringsWatcher { 41 st.MethodCall(st, "WatchApplications") 42 return st.applicationsWatcher 43 } 44 45 func (st *mockState) Application(name string) (caasunitprovisioner.Application, error) { 46 st.MethodCall(st, "Application", name) 47 if name != st.application.tag.Id() { 48 return nil, errors.NotFoundf("application %v", name) 49 } 50 return &st.application, st.NextErr() 51 } 52 53 func (st *mockState) FindEntity(tag names.Tag) (state.Entity, error) { 54 st.MethodCall(st, "FindEntity", tag) 55 if err := st.NextErr(); err != nil { 56 return nil, err 57 } 58 switch tag.(type) { 59 case names.ApplicationTag: 60 return &st.application, nil 61 case names.UnitTag: 62 return &st.unit, nil 63 default: 64 return nil, errors.NotFoundf("%s", names.ReadableString(tag)) 65 } 66 } 67 68 func (st *mockState) ControllerConfig() (controller.Config, error) { 69 st.MethodCall(st, "ControllerConfig") 70 return coretesting.FakeControllerConfig(), nil 71 } 72 73 func (st *mockState) Model() (caasunitprovisioner.Model, error) { 74 st.MethodCall(st, "Model") 75 if err := st.NextErr(); err != nil { 76 return nil, err 77 } 78 return &st.model, nil 79 } 80 81 func (st *mockState) ResolveConstraints(cons constraints.Value) (constraints.Value, error) { 82 st.MethodCall(st, "ResolveConstraints", cons) 83 if err := st.NextErr(); err != nil { 84 return constraints.Value{}, err 85 } 86 return cons, nil 87 } 88 89 func (m *mockState) AllSpaceInfos() (network.SpaceInfos, error) { 90 m.MethodCall(m, "AllSpaceInfos") 91 return network.SpaceInfos{}, nil 92 } 93 94 type mockModel struct { 95 testing.Stub 96 podSpecWatcher *statetesting.MockNotifyWatcher 97 containers []state.CloudContainer 98 isRawK8sSpec *bool 99 } 100 101 func (m *mockModel) ModelConfig() (*config.Config, error) { 102 m.MethodCall(m, "ModelConfig") 103 attrs := coretesting.FakeConfig() 104 attrs["workload-storage"] = "k8s-storage" 105 ver := jujuversion.Current 106 ver.Build = 666 107 attrs["agent-version"] = ver.String() 108 return config.New(config.UseDefaults, attrs) 109 } 110 111 func (m *mockModel) PodSpec(tag names.ApplicationTag) (string, error) { 112 m.MethodCall(m, "PodSpec", tag) 113 if err := m.NextErr(); err != nil { 114 return "", err 115 } 116 if *m.isRawK8sSpec { 117 return "", nil 118 } 119 return "spec(" + tag.Id() + ")", nil 120 } 121 122 func (m *mockModel) RawK8sSpec(tag names.ApplicationTag) (string, error) { 123 m.MethodCall(m, "RawK8sSpec", tag) 124 if err := m.NextErr(); err != nil { 125 return "", err 126 } 127 if *m.isRawK8sSpec { 128 return "raw spec(" + tag.Id() + ")", nil 129 } 130 return "", nil 131 } 132 133 func (m *mockModel) WatchPodSpec(tag names.ApplicationTag) (state.NotifyWatcher, error) { 134 m.MethodCall(m, "WatchPodSpec", tag) 135 if err := m.NextErr(); err != nil { 136 return nil, err 137 } 138 return m.podSpecWatcher, nil 139 } 140 141 func (m *mockModel) Containers(providerIds ...string) ([]state.CloudContainer, error) { 142 m.MethodCall(m, "Containers", providerIds) 143 return m.containers, nil 144 } 145 146 type mockApplication struct { 147 testing.Stub 148 life state.Life 149 scaleWatcher *statetesting.MockNotifyWatcher 150 settingsWatcher *statetesting.MockStringsWatcher 151 152 tag names.Tag 153 scale int 154 units []caasunitprovisioner.Unit 155 ops *state.UpdateUnitsOperation 156 providerId string 157 addresses []network.SpaceAddress 158 charm *mockCharm 159 } 160 161 func (a *mockApplication) Tag() names.Tag { 162 return a.tag 163 } 164 165 func (a *mockApplication) Name() string { 166 a.MethodCall(a, "Name") 167 return a.tag.Id() 168 } 169 170 func (a *mockApplication) Life() state.Life { 171 a.MethodCall(a, "Life") 172 return a.life 173 } 174 175 func (a *mockApplication) WatchScale() state.NotifyWatcher { 176 a.MethodCall(a, "WatchScale") 177 return a.scaleWatcher 178 } 179 180 func (a *mockApplication) GetScale() int { 181 a.MethodCall(a, "GetScale") 182 return a.scale 183 } 184 185 func (a *mockApplication) SetScale(scale int, generation int64, force bool) error { 186 a.MethodCall(a, "SetScale", scale) 187 a.scale = scale 188 return nil 189 } 190 191 func (a *mockApplication) WatchConfigSettingsHash() state.StringsWatcher { 192 a.MethodCall(a, "WatchConfigSettingsHash") 193 return a.settingsWatcher 194 } 195 196 func (a *mockApplication) ClearResources() error { 197 a.MethodCall(a, "ClearResources") 198 return nil 199 } 200 201 func (a *mockApplication) CharmModifiedVersion() int { 202 a.MethodCall(a, "CharmModifiedVersion") 203 return 888 204 } 205 206 func (a *mockApplication) StorageConstraints() (map[string]state.StorageConstraints, error) { 207 return map[string]state.StorageConstraints{ 208 "data": { 209 Size: 100, 210 Count: 1, 211 }, 212 "logs": { 213 Size: 200, 214 Pool: "rootfs", 215 Count: 1, 216 }, 217 }, nil 218 } 219 220 type mockCharm struct { 221 charmscommon.Charm 222 meta charm.Meta 223 } 224 225 func (m *mockCharm) Meta() *charm.Meta { 226 return &m.meta 227 } 228 229 func (a *mockApplication) Charm() (charmscommon.Charm, bool, error) { 230 a.MethodCall(a, "Charm") 231 return a.charm, false, nil 232 } 233 234 func (a *mockApplication) GetPlacement() string { 235 a.MethodCall(a, "GetPlacement") 236 return "placement" 237 } 238 239 func (a *mockApplication) ApplicationConfig() (coreconfig.ConfigAttributes, error) { 240 a.MethodCall(a, "ApplicationConfig") 241 return coreconfig.ConfigAttributes{"foo": "bar"}, a.NextErr() 242 } 243 244 func (m *mockApplication) AllUnits() (units []caasunitprovisioner.Unit, err error) { 245 return m.units, nil 246 } 247 248 func (m *mockApplication) UpdateUnits(ops *state.UpdateUnitsOperation) error { 249 m.ops = ops 250 return nil 251 } 252 253 func (m *mockApplication) DeviceConstraints() (map[string]state.DeviceConstraints, error) { 254 return map[string]state.DeviceConstraints{ 255 "bitcoinminer": {Type: "nvidia.com/gpu", 256 Count: 3, 257 Attributes: map[string]string{"gpu": "nvidia-tesla-p100"}, 258 }, 259 }, nil 260 } 261 262 func (m *mockApplication) Constraints() (constraints.Value, error) { 263 return constraints.MustParse("mem=64G"), nil 264 } 265 266 func (m *mockApplication) UpdateCloudService(providerId string, addresses []network.SpaceAddress) error { 267 m.providerId = providerId 268 m.addresses = addresses 269 return nil 270 } 271 272 var addOp = &state.AddUnitOperation{} 273 274 func (m *mockApplication) AddOperation(props state.UnitUpdateProperties) *state.AddUnitOperation { 275 m.MethodCall(m, "AddOperation", props) 276 return addOp 277 } 278 279 func (m *mockApplication) SetOperatorStatus(sInfo status.StatusInfo) error { 280 m.MethodCall(m, "SetOperatorStatus", sInfo) 281 return nil 282 } 283 284 func (m *mockApplication) SetStatus(sInfo status.StatusInfo) error { 285 m.MethodCall(m, "SetStatus", sInfo) 286 return nil 287 } 288 289 type mockContainerInfo struct { 290 state.CloudContainer 291 providerId string 292 unitName string 293 } 294 295 func (m *mockContainerInfo) ProviderId() string { 296 return m.providerId 297 } 298 299 func (m *mockContainerInfo) Unit() string { 300 return m.unitName 301 } 302 303 type mockUnit struct { 304 testing.Stub 305 name string 306 life state.Life 307 containerInfo *mockContainerInfo 308 } 309 310 func (*mockUnit) Tag() names.Tag { 311 panic("should not be called") 312 } 313 314 func (u *mockUnit) UnitTag() names.UnitTag { 315 return names.NewUnitTag(u.name) 316 } 317 318 func (u *mockUnit) Life() state.Life { 319 u.MethodCall(u, "Life") 320 return u.life 321 } 322 323 func (m *mockUnit) Name() string { 324 return m.name 325 } 326 327 func (m *mockUnit) ContainerInfo() (state.CloudContainer, error) { 328 if m.containerInfo == nil { 329 return nil, errors.NotFoundf("container info") 330 } 331 return m.containerInfo, nil 332 } 333 334 func (m *mockUnit) AgentStatus() (status.StatusInfo, error) { 335 return status.StatusInfo{Status: status.Allocating}, nil 336 } 337 338 var updateOp = &state.UpdateUnitOperation{} 339 340 func (m *mockUnit) UpdateOperation(props state.UnitUpdateProperties) *state.UpdateUnitOperation { 341 m.MethodCall(m, "UpdateOperation", props) 342 return updateOp 343 } 344 345 var destroyOp = &state.DestroyUnitOperation{} 346 347 func (m *mockUnit) DestroyOperation() *state.DestroyUnitOperation { 348 m.MethodCall(m, "DestroyOperation") 349 return destroyOp 350 } 351 352 type mockStorage struct { 353 testing.Stub 354 storageFilesystems map[names.StorageTag]names.FilesystemTag 355 storageVolumes map[names.StorageTag]names.VolumeTag 356 storageAttachments map[names.UnitTag]names.StorageTag 357 backingVolume names.VolumeTag 358 } 359 360 func (m *mockStorage) StorageInstance(tag names.StorageTag) (state.StorageInstance, error) { 361 m.MethodCall(m, "StorageInstance", tag) 362 return &mockStorageInstance{ 363 tag: tag, 364 owner: names.NewUserTag("fred"), 365 }, nil 366 } 367 368 func (m *mockStorage) AllFilesystems() ([]state.Filesystem, error) { 369 m.MethodCall(m, "AllFilesystems") 370 var result []state.Filesystem 371 for _, fsTag := range m.storageFilesystems { 372 result = append(result, &mockFilesystem{Stub: &m.Stub, tag: fsTag, volTag: m.backingVolume}) 373 } 374 return result, nil 375 } 376 377 func (m *mockStorage) DestroyStorageInstance(tag names.StorageTag, destroyAttachments bool, force bool, maxWait time.Duration) (err error) { 378 m.MethodCall(m, "DestroyStorageInstance", tag, destroyAttachments, force) 379 return nil 380 } 381 382 func (m *mockStorage) DestroyFilesystem(tag names.FilesystemTag, force bool) (err error) { 383 m.MethodCall(m, "DestroyFilesystem", tag) 384 return nil 385 } 386 387 func (m *mockStorage) DestroyVolume(tag names.VolumeTag) (err error) { 388 m.MethodCall(m, "DestroyVolume", tag) 389 return nil 390 } 391 392 func (m *mockStorage) Filesystem(fsTag names.FilesystemTag) (state.Filesystem, error) { 393 m.MethodCall(m, "Filesystem", fsTag) 394 return &mockFilesystem{Stub: &m.Stub, tag: fsTag, volTag: m.backingVolume}, nil 395 } 396 397 func (m *mockStorage) StorageInstanceFilesystem(tag names.StorageTag) (state.Filesystem, error) { 398 return &mockFilesystem{Stub: &m.Stub, tag: m.storageFilesystems[tag], volTag: m.backingVolume}, nil 399 } 400 401 func (m *mockStorage) UnitStorageAttachments(unit names.UnitTag) ([]state.StorageAttachment, error) { 402 m.MethodCall(m, "UnitStorageAttachments", unit) 403 return []state.StorageAttachment{ 404 &mockStorageAttachment{ 405 unit: unit, 406 storage: m.storageAttachments[unit], 407 }, 408 }, nil 409 } 410 411 func (m *mockStorage) SetFilesystemInfo(fsTag names.FilesystemTag, fsInfo state.FilesystemInfo) error { 412 m.MethodCall(m, "SetFilesystemInfo", fsTag, fsInfo) 413 return nil 414 } 415 416 func (m *mockStorage) SetFilesystemAttachmentInfo(host names.Tag, fsTag names.FilesystemTag, info state.FilesystemAttachmentInfo) error { 417 m.MethodCall(m, "SetFilesystemAttachmentInfo", host, fsTag, info) 418 return nil 419 } 420 421 func (m *mockStorage) Volume(volTag names.VolumeTag) (state.Volume, error) { 422 m.MethodCall(m, "Volume", volTag) 423 return &mockVolume{Stub: &m.Stub, tag: volTag}, nil 424 } 425 426 func (m *mockStorage) StorageInstanceVolume(tag names.StorageTag) (state.Volume, error) { 427 return &mockVolume{Stub: &m.Stub, tag: m.storageVolumes[tag]}, nil 428 } 429 430 func (m *mockStorage) SetVolumeInfo(volTag names.VolumeTag, volInfo state.VolumeInfo) error { 431 m.MethodCall(m, "SetVolumeInfo", volTag, volInfo) 432 return nil 433 } 434 435 func (m *mockStorage) SetVolumeAttachmentInfo(host names.Tag, volTag names.VolumeTag, info state.VolumeAttachmentInfo) error { 436 m.MethodCall(m, "SetVolumeAttachmentInfo", host, volTag, info) 437 return nil 438 } 439 440 type mockDeviceBackend struct { 441 testing.Stub 442 } 443 444 func (d *mockDeviceBackend) DeviceConstraints(id string) (map[string]state.DeviceConstraints, error) { 445 d.MethodCall(d, "DeviceConstraints", id) 446 return map[string]state.DeviceConstraints{ 447 "bitcoinminer": {Type: "nvidia.com/gpu", 448 Count: 3, 449 Attributes: map[string]string{"gpu": "nvidia-tesla-p100"}, 450 }}, nil 451 } 452 453 type mockStorageInstance struct { 454 state.StorageInstance 455 tag names.StorageTag 456 owner names.Tag 457 } 458 459 func (a *mockStorageInstance) Kind() state.StorageKind { 460 return state.StorageKindFilesystem 461 } 462 463 func (a *mockStorageInstance) Tag() names.Tag { 464 return a.tag 465 } 466 467 func (a *mockStorageInstance) StorageName() string { 468 id := a.tag.Id() 469 return strings.Split(id, "/")[0] 470 } 471 472 type mockStorageAttachment struct { 473 state.StorageAttachment 474 testing.Stub 475 unit names.UnitTag 476 storage names.StorageTag 477 } 478 479 func (a *mockStorageAttachment) StorageInstance() names.StorageTag { 480 return a.storage 481 } 482 483 type mockFilesystem struct { 484 *testing.Stub 485 state.Filesystem 486 tag names.FilesystemTag 487 volTag names.VolumeTag 488 } 489 490 func (f *mockFilesystem) Tag() names.Tag { 491 return f.FilesystemTag() 492 } 493 494 func (f *mockFilesystem) FilesystemTag() names.FilesystemTag { 495 return f.tag 496 } 497 498 func (f *mockFilesystem) Volume() (names.VolumeTag, error) { 499 if f.volTag.Id() == "" { 500 return f.volTag, state.ErrNoBackingVolume 501 } 502 return f.volTag, nil 503 } 504 505 func (f *mockFilesystem) SetStatus(statusInfo status.StatusInfo) error { 506 f.MethodCall(f, "SetStatus", statusInfo) 507 return nil 508 } 509 510 func (f *mockFilesystem) Info() (state.FilesystemInfo, error) { 511 return state.FilesystemInfo{}, errors.NotProvisionedf("filesystem") 512 } 513 514 type mockVolume struct { 515 *testing.Stub 516 state.Volume 517 tag names.VolumeTag 518 } 519 520 func (v *mockVolume) Tag() names.Tag { 521 return v.VolumeTag() 522 } 523 524 func (v *mockVolume) VolumeTag() names.VolumeTag { 525 return v.tag 526 } 527 528 func (v *mockVolume) SetStatus(statusInfo status.StatusInfo) error { 529 v.MethodCall(v, "SetStatus", statusInfo) 530 return nil 531 } 532 533 func (v *mockVolume) Info() (state.VolumeInfo, error) { 534 return state.VolumeInfo{}, errors.NotProvisionedf("volume") 535 } 536 537 type mockStoragePoolManager struct { 538 testing.Stub 539 poolmanager.PoolManager 540 } 541 542 func (m *mockStoragePoolManager) Get(name string) (*storage.Config, error) { 543 m.MethodCall(m, "Get", name) 544 if name == "rootfs" { 545 return nil, errors.NotFoundf("pool %q", name) 546 } 547 return storage.NewConfig(name, k8sconstants.StorageProviderType, map[string]interface{}{"foo": "bar"}) 548 } 549 550 type mockStorageRegistry struct { 551 testing.Stub 552 storage.ProviderRegistry 553 } 554 555 type mockProvider struct { 556 storage.Provider 557 } 558 559 func (m *mockProvider) Supports(kind storage.StorageKind) bool { 560 return kind == storage.StorageKindFilesystem 561 } 562 563 func (m *mockStorageRegistry) StorageProvider(p storage.ProviderType) (storage.Provider, error) { 564 if p != "rootfs" { 565 return nil, errors.NotFoundf("provider %q", p) 566 } 567 return &mockProvider{}, nil 568 }