diff --git a/cmd/jujud-controller/agent/model/manifolds.go b/cmd/jujud-controller/agent/model/manifolds.go index dd3a85c014e..6bfdfb51937 100644 --- a/cmd/jujud-controller/agent/model/manifolds.go +++ b/cmd/jujud-controller/agent/model/manifolds.go @@ -30,7 +30,6 @@ import ( "github.com/juju/juju/internal/worker/apiconfigwatcher" "github.com/juju/juju/internal/worker/applicationscaler" "github.com/juju/juju/internal/worker/caasapplicationprovisioner" - "github.com/juju/juju/internal/worker/caasbroker" "github.com/juju/juju/internal/worker/caasenvironupgrader" "github.com/juju/juju/internal/worker/caasfirewaller" "github.com/juju/juju/internal/worker/caasmodelconfigmanager" @@ -351,12 +350,14 @@ func IAASManifolds(config ManifoldsConfig) dependency.Manifolds { controllerTag := agentConfig.Controller() modelTag := agentConfig.Model() manifolds := dependency.Manifolds{ - providerTrackerName: ifCredentialValid(ifResponsible(providertracker.Manifold(providertracker.ManifoldConfig{ + providerTrackerName: ifCredentialValid(ifResponsible(providertracker.Manifold(providertracker.ManifoldConfig[environs.Environ]{ ProviderServiceFactoryName: providerServiceFactoryName, - NewEnviron: config.NewEnvironFunc, - NewWorker: providertracker.NewWorker, + NewWorker: providertracker.NewWorker[environs.Environ], GetProviderServiceFactory: providertracker.GetProviderServiceFactory, Logger: config.LoggingContext.GetLogger("juju.worker.providertracker"), + GetProvider: providertracker.IAASGetProvider(func(ctx context.Context, args environs.OpenParams) (environs.Environ, error) { + return config.NewEnvironFunc(ctx, args) + }), }))), // Everything else should be wrapped in ifResponsible, @@ -489,6 +490,16 @@ func CAASManifolds(config ManifoldsConfig) dependency.Manifolds { agentConfig := config.Agent.CurrentConfig() modelTag := agentConfig.Model() manifolds := dependency.Manifolds{ + providerTrackerName: ifResponsible(providertracker.Manifold(providertracker.ManifoldConfig[caas.Broker]{ + ProviderServiceFactoryName: providerServiceFactoryName, + NewWorker: providertracker.NewWorker[caas.Broker], + GetProviderServiceFactory: providertracker.GetProviderServiceFactory, + Logger: config.LoggingContext.GetLogger("juju.worker.providertracker"), + GetProvider: providertracker.CAASGetProvider(func(ctx context.Context, args environs.OpenParams) (caas.Broker, error) { + return config.NewContainerBrokerFunc(ctx, args) + }), + })), + // The undertaker is currently the only ifNotAlive worker. undertakerName: ifNotAlive(undertaker.Manifold(undertaker.ManifoldConfig{ APICallerName: apiCallerName, @@ -502,16 +513,10 @@ func CAASManifolds(config ManifoldsConfig) dependency.Manifolds { }, })), - caasBrokerTrackerName: ifResponsible(caasbroker.Manifold(caasbroker.ManifoldConfig{ - APICallerName: apiCallerName, - NewContainerBrokerFunc: config.NewContainerBrokerFunc, - Logger: config.LoggingContext.GetLogger("juju.worker.caas"), - })), - caasFirewallerName: ifNotMigrating(caasfirewaller.Manifold( caasfirewaller.ManifoldConfig{ APICallerName: apiCallerName, - BrokerName: caasBrokerTrackerName, + BrokerName: providerTrackerName, ControllerUUID: agentConfig.Controller().Id(), ModelUUID: agentConfig.Model().Id(), NewClient: func(caller base.APICaller) caasfirewaller.Client { @@ -525,14 +530,14 @@ func CAASManifolds(config ManifoldsConfig) dependency.Manifolds { caasModelOperatorName: ifResponsible(caasmodeloperator.Manifold(caasmodeloperator.ManifoldConfig{ AgentName: agentName, APICallerName: apiCallerName, - BrokerName: caasBrokerTrackerName, + BrokerName: providerTrackerName, Logger: config.LoggingContext.GetLogger("juju.worker.caasmodeloperator"), ModelUUID: agentConfig.Model().Id(), })), caasmodelconfigmanagerName: ifResponsible(caasmodelconfigmanager.Manifold(caasmodelconfigmanager.ManifoldConfig{ APICallerName: apiCallerName, - BrokerName: caasBrokerTrackerName, + BrokerName: providerTrackerName, Logger: config.LoggingContext.GetLogger("juju.worker.caasmodelconfigmanager"), NewWorker: caasmodelconfigmanager.NewWorker, NewFacade: caasmodelconfigmanager.NewFacade, @@ -542,7 +547,7 @@ func CAASManifolds(config ManifoldsConfig) dependency.Manifolds { caasApplicationProvisionerName: ifNotMigrating(caasapplicationprovisioner.Manifold( caasapplicationprovisioner.ManifoldConfig{ APICallerName: apiCallerName, - BrokerName: caasBrokerTrackerName, + BrokerName: providerTrackerName, ClockName: clockName, NewWorker: caasapplicationprovisioner.NewProvisionerWorker, Logger: config.LoggingContext.GetLogger("juju.worker.caasapplicationprovisioner"), @@ -561,7 +566,7 @@ func CAASManifolds(config ManifoldsConfig) dependency.Manifolds { APICallerName: apiCallerName, Clock: config.Clock, Logger: config.LoggingContext.GetLogger("juju.worker.storageprovisioner"), - StorageRegistryName: caasBrokerTrackerName, + StorageRegistryName: providerTrackerName, Model: modelTag, NewCredentialValidatorFacade: common.NewCredentialInvalidatorFacade, NewWorker: storageprovisioner.NewCaasWorker, @@ -698,7 +703,6 @@ const ( caasmodelconfigmanagerName = "caas-model-config-manager" caasApplicationProvisionerName = "caas-application-provisioner" caasStorageProvisionerName = "caas-storage-provisioner" - caasBrokerTrackerName = "caas-broker-tracker" secretsPrunerName = "secrets-pruner" userSecretsDrainWorker = "user-secrets-drain-worker" diff --git a/cmd/jujud-controller/agent/model/manifolds_test.go b/cmd/jujud-controller/agent/model/manifolds_test.go index 92cd316f216..ab13346a022 100644 --- a/cmd/jujud-controller/agent/model/manifolds_test.go +++ b/cmd/jujud-controller/agent/model/manifolds_test.go @@ -90,7 +90,6 @@ func (s *ManifoldsSuite) TestCAASNames(c *gc.C) { "api-caller", "api-config-watcher", "caas-application-provisioner", - "caas-broker-tracker", "caas-firewaller", "caas-model-config-manager", "caas-model-operator", @@ -106,6 +105,7 @@ func (s *ManifoldsSuite) TestCAASNames(c *gc.C) { "not-alive-flag", "not-dead-flag", "provider-service-factory", + "provider-tracker", "provider-upgrade-gate", "provider-upgraded-flag", "provider-upgrader", @@ -214,30 +214,31 @@ var expectedCAASModelManifoldsWithDependencies = map[string][]string{ "is-responsible-flag", "migration-fortress", "migration-inactive-flag", + "not-dead-flag", "provider-upgrade-gate", "provider-upgraded-flag", - "not-dead-flag"}, + }, "secrets-pruner": { "agent", "api-caller", - "provider-upgrade-gate", - "provider-upgraded-flag", "is-responsible-flag", "migration-fortress", "migration-inactive-flag", "not-dead-flag", + "provider-upgrade-gate", + "provider-upgraded-flag", }, "user-secrets-drain-worker": { "agent", "api-caller", - "provider-upgrade-gate", - "provider-upgraded-flag", "is-responsible-flag", "migration-fortress", "migration-inactive-flag", "not-dead-flag", + "provider-upgrade-gate", + "provider-upgraded-flag", }, "agent": {}, @@ -246,51 +247,69 @@ var expectedCAASModelManifoldsWithDependencies = map[string][]string{ "api-config-watcher": {"agent"}, - "caas-broker-tracker": {"agent", "api-caller", "is-responsible-flag"}, + "provider-tracker": { + "agent", + "api-caller", + "is-responsible-flag", + "provider-service-factory", + }, - "caas-model-config-manager": {"agent", "api-caller", "caas-broker-tracker", "is-responsible-flag"}, + "caas-model-config-manager": { + "agent", + "api-caller", + "is-responsible-flag", + "provider-service-factory", + "provider-tracker", + }, "caas-firewaller": { "agent", "api-caller", - "caas-broker-tracker", "is-responsible-flag", "migration-fortress", "migration-inactive-flag", + "not-dead-flag", + "provider-service-factory", + "provider-tracker", "provider-upgrade-gate", "provider-upgraded-flag", - "not-dead-flag"}, + }, "caas-model-operator": { "agent", "api-caller", - "caas-broker-tracker", + "provider-service-factory", + "provider-tracker", "is-responsible-flag", }, "caas-application-provisioner": { "agent", "api-caller", - "caas-broker-tracker", "clock", "is-responsible-flag", "migration-fortress", "migration-inactive-flag", + "not-dead-flag", + "provider-service-factory", + "provider-tracker", "provider-upgrade-gate", "provider-upgraded-flag", - "not-dead-flag"}, + }, "caas-storage-provisioner": { "agent", "api-caller", - "caas-broker-tracker", "is-responsible-flag", "migration-fortress", "migration-inactive-flag", + "not-dead-flag", + "provider-service-factory", + "provider-tracker", "provider-upgrade-gate", "provider-upgraded-flag", - "not-dead-flag", - "valid-credential-flag"}, + "valid-credential-flag", + }, "charm-downloader": { "agent", @@ -298,10 +317,11 @@ var expectedCAASModelManifoldsWithDependencies = map[string][]string{ "is-responsible-flag", "migration-fortress", "migration-inactive-flag", + "not-dead-flag", "provider-upgrade-gate", "provider-upgraded-flag", - "not-dead-flag", - "valid-credential-flag"}, + "valid-credential-flag", + }, "charm-revision-updater": { "agent", @@ -309,9 +329,10 @@ var expectedCAASModelManifoldsWithDependencies = map[string][]string{ "is-responsible-flag", "migration-fortress", "migration-inactive-flag", + "not-dead-flag", "provider-upgrade-gate", "provider-upgraded-flag", - "not-dead-flag"}, + }, "clock": {}, @@ -323,35 +344,38 @@ var expectedCAASModelManifoldsWithDependencies = map[string][]string{ "is-responsible-flag", "migration-fortress", "migration-inactive-flag", + "not-dead-flag", "provider-upgrade-gate", "provider-upgraded-flag", - "not-dead-flag", }, "migration-fortress": { "agent", "api-caller", "is-responsible-flag", + "not-dead-flag", "provider-upgrade-gate", "provider-upgraded-flag", - "not-dead-flag"}, + }, "migration-inactive-flag": { "agent", "api-caller", "is-responsible-flag", + "not-dead-flag", "provider-upgrade-gate", "provider-upgraded-flag", - "not-dead-flag"}, + }, "migration-master": { "agent", "api-caller", "is-responsible-flag", "migration-fortress", + "not-dead-flag", "provider-upgrade-gate", "provider-upgraded-flag", - "not-dead-flag"}, + }, "provider-upgrade-gate": {}, @@ -360,9 +384,9 @@ var expectedCAASModelManifoldsWithDependencies = map[string][]string{ "provider-upgrader": { "agent", "api-caller", - "provider-upgrade-gate", "is-responsible-flag", "not-dead-flag", + "provider-upgrade-gate", "valid-credential-flag", }, @@ -378,9 +402,10 @@ var expectedCAASModelManifoldsWithDependencies = map[string][]string{ "is-responsible-flag", "migration-fortress", "migration-inactive-flag", + "not-dead-flag", "provider-upgrade-gate", "provider-upgraded-flag", - "not-dead-flag"}, + }, "state-cleaner": { "agent", @@ -388,9 +413,10 @@ var expectedCAASModelManifoldsWithDependencies = map[string][]string{ "is-responsible-flag", "migration-fortress", "migration-inactive-flag", + "not-dead-flag", "provider-upgrade-gate", "provider-upgraded-flag", - "not-dead-flag"}, + }, "status-history-pruner": { "agent", @@ -398,9 +424,10 @@ var expectedCAASModelManifoldsWithDependencies = map[string][]string{ "is-responsible-flag", "migration-fortress", "migration-inactive-flag", + "not-dead-flag", "provider-upgrade-gate", "provider-upgraded-flag", - "not-dead-flag"}, + }, "undertaker": { "agent", diff --git a/domain/model/modelmigration/import.go b/domain/model/modelmigration/import.go index 938bda48cba..2eb93a0169f 100644 --- a/domain/model/modelmigration/import.go +++ b/domain/model/modelmigration/import.go @@ -15,9 +15,9 @@ import ( coremodel "github.com/juju/juju/core/model" "github.com/juju/juju/core/modelmigration" coreuser "github.com/juju/juju/core/user" - usererrors "github.com/juju/juju/domain/access/errors" - userservice "github.com/juju/juju/domain/access/service" - userstate "github.com/juju/juju/domain/access/state" + accesserrors "github.com/juju/juju/domain/access/errors" + accessservice "github.com/juju/juju/domain/access/service" + accessstate "github.com/juju/juju/domain/access/state" controllerconfigservice "github.com/juju/juju/domain/controllerconfig/service" controllerconfigstate "github.com/juju/juju/domain/controllerconfig/state" domainmodel "github.com/juju/juju/domain/model" @@ -103,7 +103,7 @@ func (i *importOperation) Setup(scope modelmigration.Scope) error { i.readOnlyModelService = modelservice.NewModelService( modelstate.NewModelState(scope.ModelDB()), ) - i.userService = userservice.NewService(userstate.NewState(scope.ControllerDB(), i.logger)) + i.userService = accessservice.NewService(accessstate.NewState(scope.ControllerDB(), i.logger)) i.controllerConfigService = controllerconfigservice.NewService( controllerconfigstate.NewState(scope.ControllerDB()), ) @@ -116,7 +116,7 @@ func (i *importOperation) Setup(scope modelmigration.Scope) error { // If model name or uuid are undefined or are not strings in the model config an // error satisfying [errors.NotValid] will be returned. // If the user specified for the model cannot be found an error satisfying -// [usererrors.NotFound] will be returned. +// [accesserrors.NotFound] will be returned. func (i importOperation) Execute(ctx context.Context, model description.Model) error { modelName, uuid, err := i.getModelNameAndUUID(model) if err != nil { @@ -124,9 +124,9 @@ func (i importOperation) Execute(ctx context.Context, model description.Model) e } user, err := i.userService.GetUserByName(ctx, model.Owner().Name()) - if errors.Is(err, usererrors.UserNotFound) { + if errors.Is(err, accesserrors.UserNotFound) { return fmt.Errorf("cannot import model %q with uuid %q, %w for name %q", - modelName, uuid, usererrors.UserNotFound, model.Owner().Name(), + modelName, uuid, accesserrors.UserNotFound, model.Owner().Name(), ) } else if err != nil { return fmt.Errorf( diff --git a/internal/worker/bootstrap/worker_test.go b/internal/worker/bootstrap/worker_test.go index 1aa454a1ffc..54e538054c1 100644 --- a/internal/worker/bootstrap/worker_test.go +++ b/internal/worker/bootstrap/worker_test.go @@ -24,7 +24,7 @@ import ( "github.com/juju/juju/core/objectstore" "github.com/juju/juju/core/user" usertesting "github.com/juju/juju/core/user/testing" - userservice "github.com/juju/juju/domain/access/service" + accessservice "github.com/juju/juju/domain/access/service" "github.com/juju/juju/environs" "github.com/juju/juju/environs/config" "github.com/juju/juju/internal/bootstrap" @@ -318,7 +318,7 @@ func (s *workerSuite) expectUser(c *gc.C) { s.userService.EXPECT().GetUserByName(gomock.Any(), "admin").Return(user.User{ UUID: usertesting.GenUserUUID(c), }, nil) - s.userService.EXPECT().AddUser(gomock.Any(), gomock.Any()).DoAndReturn(func(_ context.Context, u userservice.AddUserArg) (user.UUID, []byte, error) { + s.userService.EXPECT().AddUser(gomock.Any(), gomock.Any()).DoAndReturn(func(_ context.Context, u accessservice.AddUserArg) (user.UUID, []byte, error) { c.Check(u.Name, gc.Equals, "juju-metrics") return usertesting.GenUserUUID(c), nil, nil }) diff --git a/internal/worker/caasadmission/manifold.go b/internal/worker/caasadmission/manifold.go index adec60acf44..c8f94e0a6b4 100644 --- a/internal/worker/caasadmission/manifold.go +++ b/internal/worker/caasadmission/manifold.go @@ -13,6 +13,7 @@ import ( "github.com/juju/juju/agent" "github.com/juju/juju/apiserver/apiserverhttp" + "github.com/juju/juju/caas" "github.com/juju/juju/internal/pki" "github.com/juju/juju/internal/worker/caasrbacmapper" "github.com/juju/juju/internal/worker/muxhttpserver" @@ -100,10 +101,14 @@ func (c ManifoldConfig) Start(context context.Context, getter dependency.Getter) return nil, errors.Trace(err) } - var broker K8sBroker + var broker caas.Broker if err := getter.Get(c.BrokerName, &broker); err != nil { return nil, errors.Trace(err) } + k8sBroker, ok := broker.(K8sBroker) + if !ok { + return nil, errors.Errorf("broker does not implement K8sBroker") + } var rbacMapper caasrbacmapper.Mapper if err := getter.Get(c.RBACMapperName, &rbacMapper); err != nil { @@ -129,9 +134,10 @@ func (c ManifoldConfig) Start(context context.Context, getter dependency.Getter) currentConfig := agent.CurrentConfig() admissionPath := AdmissionPathForModel(currentConfig.Model().Id()) admissionCreator, err := NewAdmissionCreator(authority, - broker.GetCurrentNamespace(), broker.CurrentModel(), - broker.IsLegacyLabels(), - broker.EnsureMutatingWebhookConfiguration, + k8sBroker.GetCurrentNamespace(), + k8sBroker.CurrentModel(), + k8sBroker.IsLegacyLabels(), + k8sBroker.EnsureMutatingWebhookConfiguration, &admission.ServiceReference{ Name: c.ServiceName, Namespace: c.ServiceNamespace, @@ -147,7 +153,7 @@ func (c ManifoldConfig) Start(context context.Context, getter dependency.Getter) c.Logger, mux, AdmissionPathForModel(currentConfig.Model().Id()), - broker.IsLegacyLabels(), + k8sBroker.IsLegacyLabels(), admissionCreator, rbacMapper) } diff --git a/internal/worker/caasrbacmapper/manifold.go b/internal/worker/caasrbacmapper/manifold.go index 772166be1e5..6c29570b5af 100644 --- a/internal/worker/caasrbacmapper/manifold.go +++ b/internal/worker/caasrbacmapper/manifold.go @@ -10,6 +10,8 @@ import ( "github.com/juju/worker/v4" "github.com/juju/worker/v4/dependency" "k8s.io/client-go/informers" + + "github.com/juju/juju/caas" ) type K8sBroker interface { @@ -55,12 +57,16 @@ func (c ManifoldConfig) Start(context context.Context, getter dependency.Getter) return nil, errors.Trace(err) } - var broker K8sBroker + var broker caas.Broker if err := getter.Get(c.BrokerName, &broker); err != nil { return nil, errors.Trace(err) } + k8sBroker, ok := broker.(K8sBroker) + if !ok { + return nil, errors.Errorf("broker does not implement K8sBroker") + } - return NewMapper(c.Logger, broker.SharedInformerFactory().Core().V1().ServiceAccounts()) + return NewMapper(c.Logger, k8sBroker.SharedInformerFactory().Core().V1().ServiceAccounts()) } func (c ManifoldConfig) Validate() error { diff --git a/internal/worker/providertracker/caas_mock_test.go b/internal/worker/providertracker/caas_mock_test.go new file mode 100644 index 00000000000..40bdbc14af7 --- /dev/null +++ b/internal/worker/providertracker/caas_mock_test.go @@ -0,0 +1,528 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/juju/juju/caas (interfaces: Broker) +// +// Generated by this command: +// +// mockgen -package providertracker -destination caas_mock_test.go github.com/juju/juju/caas Broker +// + +// Package providertracker is a generated GoMock package. +package providertracker + +import ( + context "context" + reflect "reflect" + + caas "github.com/juju/juju/caas" + constraints "github.com/juju/juju/core/constraints" + secrets "github.com/juju/juju/core/secrets" + environs "github.com/juju/juju/environs" + config "github.com/juju/juju/environs/config" + envcontext "github.com/juju/juju/environs/envcontext" + docker "github.com/juju/juju/internal/docker" + proxy "github.com/juju/juju/internal/proxy" + storage "github.com/juju/juju/internal/storage" + names "github.com/juju/names/v5" + version "github.com/juju/version/v2" + gomock "go.uber.org/mock/gomock" +) + +// MockBroker is a mock of Broker interface. +type MockBroker struct { + ctrl *gomock.Controller + recorder *MockBrokerMockRecorder +} + +// MockBrokerMockRecorder is the mock recorder for MockBroker. +type MockBrokerMockRecorder struct { + mock *MockBroker +} + +// NewMockBroker creates a new mock instance. +func NewMockBroker(ctrl *gomock.Controller) *MockBroker { + mock := &MockBroker{ctrl: ctrl} + mock.recorder = &MockBrokerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockBroker) EXPECT() *MockBrokerMockRecorder { + return m.recorder +} + +// APIVersion mocks base method. +func (m *MockBroker) APIVersion() (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "APIVersion") + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// APIVersion indicates an expected call of APIVersion. +func (mr *MockBrokerMockRecorder) APIVersion() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "APIVersion", reflect.TypeOf((*MockBroker)(nil).APIVersion)) +} + +// AdoptResources mocks base method. +func (m *MockBroker) AdoptResources(arg0 envcontext.ProviderCallContext, arg1 string, arg2 version.Number) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AdoptResources", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// AdoptResources indicates an expected call of AdoptResources. +func (mr *MockBrokerMockRecorder) AdoptResources(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AdoptResources", reflect.TypeOf((*MockBroker)(nil).AdoptResources), arg0, arg1, arg2) +} + +// AnnotateUnit mocks base method. +func (m *MockBroker) AnnotateUnit(arg0 context.Context, arg1, arg2 string, arg3 names.UnitTag) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AnnotateUnit", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(error) + return ret0 +} + +// AnnotateUnit indicates an expected call of AnnotateUnit. +func (mr *MockBrokerMockRecorder) AnnotateUnit(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AnnotateUnit", reflect.TypeOf((*MockBroker)(nil).AnnotateUnit), arg0, arg1, arg2, arg3) +} + +// Application mocks base method. +func (m *MockBroker) Application(arg0 string, arg1 caas.DeploymentType) caas.Application { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Application", arg0, arg1) + ret0, _ := ret[0].(caas.Application) + return ret0 +} + +// Application indicates an expected call of Application. +func (mr *MockBrokerMockRecorder) Application(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Application", reflect.TypeOf((*MockBroker)(nil).Application), arg0, arg1) +} + +// Bootstrap mocks base method. +func (m *MockBroker) Bootstrap(arg0 environs.BootstrapContext, arg1 envcontext.ProviderCallContext, arg2 environs.BootstrapParams) (*environs.BootstrapResult, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Bootstrap", arg0, arg1, arg2) + ret0, _ := ret[0].(*environs.BootstrapResult) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Bootstrap indicates an expected call of Bootstrap. +func (mr *MockBrokerMockRecorder) Bootstrap(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Bootstrap", reflect.TypeOf((*MockBroker)(nil).Bootstrap), arg0, arg1, arg2) +} + +// CheckCloudCredentials mocks base method. +func (m *MockBroker) CheckCloudCredentials(arg0 context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CheckCloudCredentials", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// CheckCloudCredentials indicates an expected call of CheckCloudCredentials. +func (mr *MockBrokerMockRecorder) CheckCloudCredentials(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckCloudCredentials", reflect.TypeOf((*MockBroker)(nil).CheckCloudCredentials), arg0) +} + +// Config mocks base method. +func (m *MockBroker) Config() *config.Config { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Config") + ret0, _ := ret[0].(*config.Config) + return ret0 +} + +// Config indicates an expected call of Config. +func (mr *MockBrokerMockRecorder) Config() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Config", reflect.TypeOf((*MockBroker)(nil).Config)) +} + +// ConstraintsValidator mocks base method. +func (m *MockBroker) ConstraintsValidator(arg0 envcontext.ProviderCallContext) (constraints.Validator, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ConstraintsValidator", arg0) + ret0, _ := ret[0].(constraints.Validator) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ConstraintsValidator indicates an expected call of ConstraintsValidator. +func (mr *MockBrokerMockRecorder) ConstraintsValidator(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConstraintsValidator", reflect.TypeOf((*MockBroker)(nil).ConstraintsValidator), arg0) +} + +// Create mocks base method. +func (m *MockBroker) Create(arg0 envcontext.ProviderCallContext, arg1 environs.CreateParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Create indicates an expected call of Create. +func (mr *MockBrokerMockRecorder) Create(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockBroker)(nil).Create), arg0, arg1) +} + +// DeleteJujuSecret mocks base method. +func (m *MockBroker) DeleteJujuSecret(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteJujuSecret", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteJujuSecret indicates an expected call of DeleteJujuSecret. +func (mr *MockBrokerMockRecorder) DeleteJujuSecret(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteJujuSecret", reflect.TypeOf((*MockBroker)(nil).DeleteJujuSecret), arg0, arg1) +} + +// Destroy mocks base method. +func (m *MockBroker) Destroy(arg0 envcontext.ProviderCallContext) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Destroy", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Destroy indicates an expected call of Destroy. +func (mr *MockBrokerMockRecorder) Destroy(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Destroy", reflect.TypeOf((*MockBroker)(nil).Destroy), arg0) +} + +// DestroyController mocks base method. +func (m *MockBroker) DestroyController(arg0 envcontext.ProviderCallContext, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DestroyController", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DestroyController indicates an expected call of DestroyController. +func (mr *MockBrokerMockRecorder) DestroyController(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DestroyController", reflect.TypeOf((*MockBroker)(nil).DestroyController), arg0, arg1) +} + +// EnsureImageRepoSecret mocks base method. +func (m *MockBroker) EnsureImageRepoSecret(arg0 context.Context, arg1 docker.ImageRepoDetails) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EnsureImageRepoSecret", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// EnsureImageRepoSecret indicates an expected call of EnsureImageRepoSecret. +func (mr *MockBrokerMockRecorder) EnsureImageRepoSecret(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnsureImageRepoSecret", reflect.TypeOf((*MockBroker)(nil).EnsureImageRepoSecret), arg0, arg1) +} + +// EnsureModelOperator mocks base method. +func (m *MockBroker) EnsureModelOperator(arg0 context.Context, arg1, arg2 string, arg3 *caas.ModelOperatorConfig) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EnsureModelOperator", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(error) + return ret0 +} + +// EnsureModelOperator indicates an expected call of EnsureModelOperator. +func (mr *MockBrokerMockRecorder) EnsureModelOperator(arg0, arg1, arg2, arg3 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnsureModelOperator", reflect.TypeOf((*MockBroker)(nil).EnsureModelOperator), arg0, arg1, arg2, arg3) +} + +// EnsureSecretAccessToken mocks base method. +func (m *MockBroker) EnsureSecretAccessToken(arg0 context.Context, arg1 names.Tag, arg2, arg3, arg4 []string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EnsureSecretAccessToken", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EnsureSecretAccessToken indicates an expected call of EnsureSecretAccessToken. +func (mr *MockBrokerMockRecorder) EnsureSecretAccessToken(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnsureSecretAccessToken", reflect.TypeOf((*MockBroker)(nil).EnsureSecretAccessToken), arg0, arg1, arg2, arg3, arg4) +} + +// GetJujuSecret mocks base method. +func (m *MockBroker) GetJujuSecret(arg0 context.Context, arg1 string) (secrets.SecretValue, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetJujuSecret", arg0, arg1) + ret0, _ := ret[0].(secrets.SecretValue) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetJujuSecret indicates an expected call of GetJujuSecret. +func (mr *MockBrokerMockRecorder) GetJujuSecret(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetJujuSecret", reflect.TypeOf((*MockBroker)(nil).GetJujuSecret), arg0, arg1) +} + +// GetSecretToken mocks base method. +func (m *MockBroker) GetSecretToken(arg0 context.Context, arg1 string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSecretToken", arg0, arg1) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetSecretToken indicates an expected call of GetSecretToken. +func (mr *MockBrokerMockRecorder) GetSecretToken(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSecretToken", reflect.TypeOf((*MockBroker)(nil).GetSecretToken), arg0, arg1) +} + +// GetService mocks base method. +func (m *MockBroker) GetService(arg0 context.Context, arg1 string, arg2 bool) (*caas.Service, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetService", arg0, arg1, arg2) + ret0, _ := ret[0].(*caas.Service) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetService indicates an expected call of GetService. +func (mr *MockBrokerMockRecorder) GetService(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetService", reflect.TypeOf((*MockBroker)(nil).GetService), arg0, arg1, arg2) +} + +// ModelOperator mocks base method. +func (m *MockBroker) ModelOperator(arg0 context.Context) (*caas.ModelOperatorConfig, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ModelOperator", arg0) + ret0, _ := ret[0].(*caas.ModelOperatorConfig) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ModelOperator indicates an expected call of ModelOperator. +func (mr *MockBrokerMockRecorder) ModelOperator(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModelOperator", reflect.TypeOf((*MockBroker)(nil).ModelOperator), arg0) +} + +// ModelOperatorExists mocks base method. +func (m *MockBroker) ModelOperatorExists(arg0 context.Context) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ModelOperatorExists", arg0) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ModelOperatorExists indicates an expected call of ModelOperatorExists. +func (mr *MockBrokerMockRecorder) ModelOperatorExists(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModelOperatorExists", reflect.TypeOf((*MockBroker)(nil).ModelOperatorExists), arg0) +} + +// PrecheckInstance mocks base method. +func (m *MockBroker) PrecheckInstance(arg0 envcontext.ProviderCallContext, arg1 environs.PrecheckInstanceParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PrecheckInstance", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// PrecheckInstance indicates an expected call of PrecheckInstance. +func (mr *MockBrokerMockRecorder) PrecheckInstance(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrecheckInstance", reflect.TypeOf((*MockBroker)(nil).PrecheckInstance), arg0, arg1) +} + +// PrepareForBootstrap mocks base method. +func (m *MockBroker) PrepareForBootstrap(arg0 environs.BootstrapContext, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PrepareForBootstrap", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// PrepareForBootstrap indicates an expected call of PrepareForBootstrap. +func (mr *MockBrokerMockRecorder) PrepareForBootstrap(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrepareForBootstrap", reflect.TypeOf((*MockBroker)(nil).PrepareForBootstrap), arg0, arg1) +} + +// Provider mocks base method. +func (m *MockBroker) Provider() caas.ContainerEnvironProvider { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Provider") + ret0, _ := ret[0].(caas.ContainerEnvironProvider) + return ret0 +} + +// Provider indicates an expected call of Provider. +func (mr *MockBrokerMockRecorder) Provider() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Provider", reflect.TypeOf((*MockBroker)(nil).Provider)) +} + +// ProxyToApplication mocks base method. +func (m *MockBroker) ProxyToApplication(arg0 context.Context, arg1, arg2 string) (proxy.Proxier, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ProxyToApplication", arg0, arg1, arg2) + ret0, _ := ret[0].(proxy.Proxier) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ProxyToApplication indicates an expected call of ProxyToApplication. +func (mr *MockBrokerMockRecorder) ProxyToApplication(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProxyToApplication", reflect.TypeOf((*MockBroker)(nil).ProxyToApplication), arg0, arg1, arg2) +} + +// RemoveSecretAccessToken mocks base method. +func (m *MockBroker) RemoveSecretAccessToken(arg0 context.Context, arg1 names.Tag) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveSecretAccessToken", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// RemoveSecretAccessToken indicates an expected call of RemoveSecretAccessToken. +func (mr *MockBrokerMockRecorder) RemoveSecretAccessToken(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveSecretAccessToken", reflect.TypeOf((*MockBroker)(nil).RemoveSecretAccessToken), arg0, arg1) +} + +// SaveJujuSecret mocks base method. +func (m *MockBroker) SaveJujuSecret(arg0 context.Context, arg1 string, arg2 secrets.SecretValue) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SaveJujuSecret", arg0, arg1, arg2) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SaveJujuSecret indicates an expected call of SaveJujuSecret. +func (mr *MockBrokerMockRecorder) SaveJujuSecret(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveJujuSecret", reflect.TypeOf((*MockBroker)(nil).SaveJujuSecret), arg0, arg1, arg2) +} + +// SetConfig mocks base method. +func (m *MockBroker) SetConfig(arg0 *config.Config) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetConfig", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetConfig indicates an expected call of SetConfig. +func (mr *MockBrokerMockRecorder) SetConfig(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetConfig", reflect.TypeOf((*MockBroker)(nil).SetConfig), arg0) +} + +// StorageProvider mocks base method. +func (m *MockBroker) StorageProvider(arg0 storage.ProviderType) (storage.Provider, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StorageProvider", arg0) + ret0, _ := ret[0].(storage.Provider) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// StorageProvider indicates an expected call of StorageProvider. +func (mr *MockBrokerMockRecorder) StorageProvider(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StorageProvider", reflect.TypeOf((*MockBroker)(nil).StorageProvider), arg0) +} + +// StorageProviderTypes mocks base method. +func (m *MockBroker) StorageProviderTypes() ([]storage.ProviderType, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StorageProviderTypes") + ret0, _ := ret[0].([]storage.ProviderType) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// StorageProviderTypes indicates an expected call of StorageProviderTypes. +func (mr *MockBrokerMockRecorder) StorageProviderTypes() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StorageProviderTypes", reflect.TypeOf((*MockBroker)(nil).StorageProviderTypes)) +} + +// Units mocks base method. +func (m *MockBroker) Units(arg0 context.Context, arg1 string) ([]caas.Unit, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Units", arg0, arg1) + ret0, _ := ret[0].([]caas.Unit) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Units indicates an expected call of Units. +func (mr *MockBrokerMockRecorder) Units(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Units", reflect.TypeOf((*MockBroker)(nil).Units), arg0, arg1) +} + +// Upgrade mocks base method. +func (m *MockBroker) Upgrade(arg0 context.Context, arg1 string, arg2 version.Number) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Upgrade", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// Upgrade indicates an expected call of Upgrade. +func (mr *MockBrokerMockRecorder) Upgrade(arg0, arg1, arg2 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Upgrade", reflect.TypeOf((*MockBroker)(nil).Upgrade), arg0, arg1, arg2) +} + +// ValidateStorageClass mocks base method. +func (m *MockBroker) ValidateStorageClass(arg0 context.Context, arg1 map[string]any) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ValidateStorageClass", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// ValidateStorageClass indicates an expected call of ValidateStorageClass. +func (mr *MockBrokerMockRecorder) ValidateStorageClass(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateStorageClass", reflect.TypeOf((*MockBroker)(nil).ValidateStorageClass), arg0, arg1) +} + +// Version mocks base method. +func (m *MockBroker) Version() (*version.Number, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Version") + ret0, _ := ret[0].(*version.Number) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Version indicates an expected call of Version. +func (mr *MockBrokerMockRecorder) Version() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Version", reflect.TypeOf((*MockBroker)(nil).Version)) +} diff --git a/internal/worker/providertracker/manifold.go b/internal/worker/providertracker/manifold.go index 5190273eea4..06f3e6ebd52 100644 --- a/internal/worker/providertracker/manifold.go +++ b/internal/worker/providertracker/manifold.go @@ -10,47 +10,83 @@ import ( "github.com/juju/worker/v4" "github.com/juju/worker/v4/dependency" + "github.com/juju/juju/caas" coredependency "github.com/juju/juju/core/dependency" + coremodel "github.com/juju/juju/core/model" "github.com/juju/juju/environs" + environscloudspec "github.com/juju/juju/environs/cloudspec" "github.com/juju/juju/internal/storage" "github.com/juju/juju/internal/worker/modelworkermanager" ) +// Provider is an interface that represents a provider, this can either be +// a CAAS broker or IAAS provider. +type Provider interface { + environs.Configer +} + +// ProviderConfigGetter is an interface that extends +// environs.EnvironConfigGetter to include the ControllerUUID method. +type ProviderConfigGetter interface { + environs.EnvironConfigGetter + + // ControllerUUID returns the UUID of the controller. + ControllerUUID() coremodel.UUID +} + +// ProviderFunc is a function that returns a provider, this can either be +// a CAAS broker or IAAS provider. +type ProviderFunc[T Provider] func(ctx context.Context, args environs.OpenParams) (T, error) + // Logger defines the methods used by the pruner worker for logging. type Logger interface { Debugf(string, ...interface{}) Warningf(string, ...interface{}) } +// GetProviderFunc is a helper function that gets a provider from the manifold. +type GetProviderFunc[T Provider] func(context.Context, ProviderConfigGetter) (T, environscloudspec.CloudSpec, error) + // GetProviderServiceFactoryFunc is a helper function that gets a service from // the manifold. type GetProviderServiceFactoryFunc func(dependency.Getter, string) (ServiceFactory, error) // NewWorkerFunc is a function that creates a new Worker. -type NewWorkerFunc func(ctx context.Context, cfg Config) (worker.Worker, error) +type NewWorkerFunc[T Provider] func(ctx context.Context, cfg Config[T]) (worker.Worker, error) // ManifoldConfig describes the resources used by a Worker. -type ManifoldConfig struct { +type ManifoldConfig[T Provider] struct { + // ProviderServiceFactoryName is the name of the service factory that + // provides the services required by the provider. ProviderServiceFactoryName string - NewEnviron environs.NewEnvironFunc - NewWorker NewWorkerFunc - Logger Logger - GetProviderServiceFactory GetProviderServiceFactoryFunc + // NewProvider is a function that returns a provider, this can either be + // a CAAS broker or IAAS provider. + NewProvider ProviderFunc[T] + // NewWorker is a function that creates a new Worker. + NewWorker NewWorkerFunc[T] + // GetProvider is a helper function that gets a provider from the manifold. + // This is generalized to allow for different types of providers. + GetProvider GetProviderFunc[T] + // GetProviderServiceFactory is a helper function that gets a service from + // the dependency engine. + GetProviderServiceFactory GetProviderServiceFactoryFunc + // Logger represents the methods used by the worker to log details. + Logger Logger } -func (cfg ManifoldConfig) Validate() error { +func (cfg ManifoldConfig[T]) Validate() error { if cfg.ProviderServiceFactoryName == "" { return errors.NotValidf("empty ProviderServiceFactoryName") } - if cfg.NewEnviron == nil { - return errors.NotValidf("nil NewEnviron") - } if cfg.NewWorker == nil { return errors.NotValidf("nil NewWorker") } if cfg.Logger == nil { return errors.NotValidf("nil Logger") } + if cfg.GetProvider == nil { + return errors.NotValidf("nil GetProvider") + } if cfg.GetProviderServiceFactory == nil { return errors.NotValidf("nil GetProviderServiceFactory") } @@ -59,24 +95,24 @@ func (cfg ManifoldConfig) Validate() error { // Manifold returns a Manifold that encapsulates a *Worker and exposes it as // an environs.Environ resource. -func Manifold(config ManifoldConfig) dependency.Manifold { +func Manifold[T Provider](config ManifoldConfig[T]) dependency.Manifold { return dependency.Manifold{ Inputs: []string{ config.ProviderServiceFactoryName, }, - Output: manifoldOutput, + Output: manifoldOutput[T], Start: func(ctx context.Context, getter dependency.Getter) (worker.Worker, error) { serviceFactory, err := config.GetProviderServiceFactory(getter, config.ProviderServiceFactoryName) if err != nil { return nil, errors.Trace(err) } - w, err := config.NewWorker(ctx, Config{ + w, err := config.NewWorker(ctx, Config[T]{ CloudService: serviceFactory.Cloud(), ConfigService: serviceFactory.Config(), CredentialService: serviceFactory.Credential(), ModelService: serviceFactory.Model(), - NewEnviron: config.NewEnviron, + GetProvider: config.GetProvider, Logger: config.Logger, }) if err != nil { @@ -87,25 +123,6 @@ func Manifold(config ManifoldConfig) dependency.Manifold { } } -// manifoldOutput extracts an environs.Environ resource from a *Worker. -func manifoldOutput(in worker.Worker, out interface{}) error { - w, ok := in.(*trackerWorker) - if !ok { - return errors.Errorf("expected *environ.Tracker, got %T", in) - } - switch result := out.(type) { - case *environs.Environ: - *result = w.Environ() - case *environs.CloudDestroyer: - *result = w.Environ() - case *storage.ProviderRegistry: - *result = w.Environ() - default: - return errors.Errorf("expected *environs.Environ, *storage.ProviderRegistry, or *environs.CloudDestroyer, got %T", out) - } - return nil -} - // ServiceFactory provides access to the services required by the provider. type ServiceFactory interface { // Model returns the model service. @@ -152,3 +169,97 @@ func (f serviceFactory) Config() ConfigService { func (f serviceFactory) Credential() CredentialService { return f.factory.Credential() } + +// IAASGetProvider creates a new provider from the given args. +func IAASGetProvider(newProvider ProviderFunc[environs.Environ]) func(ctx context.Context, getter ProviderConfigGetter) (environs.Environ, environscloudspec.CloudSpec, error) { + return func(ctx context.Context, getter ProviderConfigGetter) (environs.Environ, environscloudspec.CloudSpec, error) { + // We can't use newProvider directly, as type invariance prevents us + // from using it with the environs.GetEnvironAndCloud function. + // Just wrap it in a closure to work around this. + provider, spec, err := environs.GetEnvironAndCloud(ctx, getter, func(ctx context.Context, op environs.OpenParams) (environs.Environ, error) { + return newProvider(ctx, op) + }) + if err != nil { + return nil, environscloudspec.CloudSpec{}, errors.Trace(err) + } + return provider, *spec, nil + } +} + +// CAASGetProvider creates a new provider from the given args. +func CAASGetProvider(newProvider ProviderFunc[caas.Broker]) func(ctx context.Context, getter ProviderConfigGetter) (caas.Broker, environscloudspec.CloudSpec, error) { + return func(ctx context.Context, getter ProviderConfigGetter) (caas.Broker, environscloudspec.CloudSpec, error) { + cloudSpec, err := getter.CloudSpec(ctx) + if err != nil { + return nil, environscloudspec.CloudSpec{}, errors.Annotate(err, "cannot get cloud information") + } + + cfg, err := getter.ModelConfig(ctx) + if err != nil { + return nil, environscloudspec.CloudSpec{}, errors.Trace(err) + } + + broker, err := newProvider(ctx, environs.OpenParams{ + ControllerUUID: getter.ControllerUUID().String(), + Cloud: cloudSpec, + Config: cfg, + }) + if err != nil { + return nil, environscloudspec.CloudSpec{}, errors.Annotate(err, "cannot create caas broker") + } + return broker, cloudSpec, nil + } +} + +func manifoldOutput[T Provider](in worker.Worker, out any) error { + // In order to switch on the type of the provider, we need to use a type + // assertion to get the underlying value. + switch any(new(T)).(type) { + case *environs.Environ: + w, ok := in.(*trackerWorker[environs.Environ]) + if !ok { + return errors.Errorf("expected *trackerWorker, got %T", in) + } + return iaasOutput(w, out) + + case *caas.Broker: + w, ok := in.(*trackerWorker[caas.Broker]) + if !ok { + return errors.Errorf("expected *trackerWorker, got %T", in) + } + return caasOutput(w, out) + + default: + return errors.Errorf("expected *environs.Environ or *caas.Broker, got %T", out) + } +} + +// iaasOutput extracts an environs.Environ resource from a *Worker. +func iaasOutput(in *trackerWorker[environs.Environ], out interface{}) error { + switch result := out.(type) { + case *environs.Environ: + *result = in.Provider() + case *environs.CloudDestroyer: + *result = in.Provider() + case *storage.ProviderRegistry: + *result = in.Provider() + default: + return errors.Errorf("expected *environs.Environ, *storage.ProviderRegistry, or *environs.CloudDestroyer, got %T", out) + } + return nil +} + +// caasOutput extracts a caas.Broker resource from a *Worker. +func caasOutput(in *trackerWorker[caas.Broker], out interface{}) error { + switch result := out.(type) { + case *caas.Broker: + *result = in.Provider() + case *environs.CloudDestroyer: + *result = in.Provider() + case *storage.ProviderRegistry: + *result = in.Provider() + default: + return errors.Errorf("expected *caas.Broker, *storage.ProviderRegistry or *environs.CloudDestroyer, got %T", out) + } + return nil +} diff --git a/internal/worker/providertracker/manifold_test.go b/internal/worker/providertracker/manifold_test.go index 169a08661f1..fb634dd757d 100644 --- a/internal/worker/providertracker/manifold_test.go +++ b/internal/worker/providertracker/manifold_test.go @@ -15,7 +15,9 @@ import ( gc "gopkg.in/check.v1" "gopkg.in/tomb.v2" + "github.com/juju/juju/caas" "github.com/juju/juju/environs" + cloudspec "github.com/juju/juju/environs/cloudspec" "github.com/juju/juju/internal/servicefactory" storage "github.com/juju/juju/internal/storage" ) @@ -37,7 +39,7 @@ func (s *manifoldSuite) TestValidateConfig(c *gc.C) { c.Check(cfg.Validate(), jc.ErrorIs, errors.NotValid) cfg = s.getConfig() - cfg.NewEnviron = nil + cfg.GetProvider = nil c.Check(cfg.Validate(), jc.ErrorIs, errors.NotValid) cfg = s.getConfig() @@ -53,16 +55,16 @@ func (s *manifoldSuite) TestValidateConfig(c *gc.C) { c.Check(cfg.Validate(), jc.ErrorIs, errors.NotValid) } -func (s *manifoldSuite) getConfig() ManifoldConfig { - return ManifoldConfig{ +func (s *manifoldSuite) getConfig() ManifoldConfig[environs.Environ] { + return ManifoldConfig[environs.Environ]{ ProviderServiceFactoryName: "provider-service-factory", Logger: s.logger, - NewEnviron: func(ctx context.Context, op environs.OpenParams) (environs.Environ, error) { - return nil, nil - }, - NewWorker: func(ctx context.Context, cfg Config) (worker.Worker, error) { + NewWorker: func(ctx context.Context, cfg Config[environs.Environ]) (worker.Worker, error) { return newStubWorker(), nil }, + GetProvider: func(ctx context.Context, pcg ProviderConfigGetter) (environs.Environ, cloudspec.CloudSpec, error) { + return s.environ, cloudspec.CloudSpec{}, nil + }, GetProviderServiceFactory: func(getter dependency.Getter, name string) (ServiceFactory, error) { return s.serviceFactory, nil }, @@ -95,30 +97,54 @@ func (s *manifoldSuite) TestStart(c *gc.C) { workertest.CleanKill(c, w) } -func (s *manifoldSuite) TestOutput(c *gc.C) { +func (s *manifoldSuite) TestIAASManifoldOutput(c *gc.C) { defer s.setupMocks(c).Finish() - w := &trackerWorker{ - environ: s.environ, + w := &trackerWorker[environs.Environ]{ + provider: s.environ, } var environ environs.Environ - err := manifoldOutput(w, &environ) + err := manifoldOutput[environs.Environ](w, &environ) c.Check(err, jc.ErrorIsNil) var destroyer environs.CloudDestroyer - err = manifoldOutput(w, &destroyer) + err = manifoldOutput[environs.Environ](w, &destroyer) c.Check(err, jc.ErrorIsNil) var registry storage.ProviderRegistry - err = manifoldOutput(w, ®istry) + err = manifoldOutput[environs.Environ](w, ®istry) c.Check(err, jc.ErrorIsNil) var bob string - err = manifoldOutput(w, &bob) + err = manifoldOutput[environs.Environ](w, &bob) c.Check(err, gc.ErrorMatches, `expected \*environs.Environ, \*storage.ProviderRegistry, or \*environs.CloudDestroyer, got \*string`) } +func (s *manifoldSuite) TestCAASManifoldOutput(c *gc.C) { + defer s.setupMocks(c).Finish() + + w := &trackerWorker[caas.Broker]{ + provider: s.broker, + } + + var broker caas.Broker + err := manifoldOutput[caas.Broker](w, &broker) + c.Check(err, jc.ErrorIsNil) + + var destroyer environs.CloudDestroyer + err = manifoldOutput[caas.Broker](w, &destroyer) + c.Check(err, jc.ErrorIsNil) + + var registry storage.ProviderRegistry + err = manifoldOutput[caas.Broker](w, ®istry) + c.Check(err, jc.ErrorIsNil) + + var bob string + err = manifoldOutput[caas.Broker](w, &bob) + c.Check(err, gc.ErrorMatches, `expected \*caas.Broker, \*storage.ProviderRegistry or \*environs.CloudDestroyer, got \*string`) +} + type stubWorker struct { tomb tomb.Tomb } diff --git a/internal/worker/providertracker/package_test.go b/internal/worker/providertracker/package_test.go index a69e3bb25ce..b2ed1160bd9 100644 --- a/internal/worker/providertracker/package_test.go +++ b/internal/worker/providertracker/package_test.go @@ -16,6 +16,7 @@ import ( //go:generate go run go.uber.org/mock/mockgen -package providertracker -destination providertracker_mock_test.go github.com/juju/juju/internal/worker/providertracker ServiceFactory,ModelService,CloudService,ConfigService,CredentialService //go:generate go run go.uber.org/mock/mockgen -package providertracker -destination environs_mock_test.go github.com/juju/juju/environs Environ,CloudDestroyer,CloudSpecSetter //go:generate go run go.uber.org/mock/mockgen -package providertracker -destination storage_mock_test.go github.com/juju/juju/internal/storage ProviderRegistry +//go:generate go run go.uber.org/mock/mockgen -package providertracker -destination caas_mock_test.go github.com/juju/juju/caas Broker func TestPackage(t *stdtesting.T) { gc.TestingT(t) @@ -31,6 +32,7 @@ type baseSuite struct { credentialService *MockCredentialService environ *MockEnviron + broker *MockBroker cloudDestroyer *MockCloudDestroyer providerRegistry *MockProviderRegistry cloudSpecSetter *MockCloudSpecSetter @@ -48,6 +50,7 @@ func (s *baseSuite) setupMocks(c *gc.C) *gomock.Controller { s.credentialService = NewMockCredentialService(ctrl) s.environ = NewMockEnviron(ctrl) + s.broker = NewMockBroker(ctrl) s.cloudDestroyer = NewMockCloudDestroyer(ctrl) s.providerRegistry = NewMockProviderRegistry(ctrl) s.cloudSpecSetter = NewMockCloudSpecSetter(ctrl) diff --git a/internal/worker/providertracker/worker.go b/internal/worker/providertracker/worker.go index 30c7468799b..d3329c9c778 100644 --- a/internal/worker/providertracker/worker.go +++ b/internal/worker/providertracker/worker.go @@ -29,17 +29,17 @@ const ( // // It's arguable that it should be called WorkerConfig, because of the heavy // use of model config in this package. -type Config struct { +type Config[T Provider] struct { ModelService ModelService CloudService CloudService ConfigService ConfigService CredentialService CredentialService - NewEnviron environs.NewEnvironFunc + GetProvider GetProviderFunc[T] Logger Logger } // Validate returns an error if the config cannot be used to start a Worker. -func (config Config) Validate() error { +func (config Config[T]) Validate() error { if config.CloudService == nil { return errors.NotValidf("nil CloudService") } @@ -49,8 +49,8 @@ func (config Config) Validate() error { if config.CredentialService == nil { return errors.NotValidf("nil CredentialService") } - if config.NewEnviron == nil { - return errors.NotValidf("nil NewEnviron") + if config.GetProvider == nil { + return errors.NotValidf("nil GetProvider") } if config.Logger == nil { return errors.NotValidf("nil Logger") @@ -60,13 +60,13 @@ func (config Config) Validate() error { // trackerWorker loads an environment, makes it available to clients, and updates // the environment in response to config changes until it is killed. -type trackerWorker struct { +type trackerWorker[T Provider] struct { catacomb catacomb.Catacomb internalStates chan string - config Config + config Config[T] model coremodel.ReadOnlyModel - environ environs.Environ + provider T currentCloudSpec environscloudspec.CloudSpec providerGetter providerGetter @@ -75,11 +75,11 @@ type trackerWorker struct { // NewWorker loads a provider from the observer and returns a new Worker, // or an error if anything goes wrong. If a tracker is returned, its Environ() // method is immediately usable. -func NewWorker(ctx context.Context, config Config) (worker.Worker, error) { +func NewWorker[T Provider](ctx context.Context, config Config[T]) (worker.Worker, error) { return newWorker(ctx, config, nil) } -func newWorker(ctx context.Context, config Config, internalStates chan string) (*trackerWorker, error) { +func newWorker[T Provider](ctx context.Context, config Config[T], internalStates chan string) (*trackerWorker[T], error) { if err := config.Validate(); err != nil { return nil, errors.Trace(err) } @@ -95,17 +95,18 @@ func newWorker(ctx context.Context, config Config, internalStates chan string) ( configService: config.ConfigService, credentialService: config.CredentialService, } - environ, spec, err := environs.GetEnvironAndCloud(ctx, getter, config.NewEnviron) + // Given the model, we can now get the provider. + provider, spec, err := config.GetProvider(ctx, getter) if err != nil { return nil, errors.Trace(err) } - t := &trackerWorker{ + t := &trackerWorker[T]{ internalStates: internalStates, config: config, model: model, - environ: environ, - currentCloudSpec: *spec, + provider: provider, + currentCloudSpec: spec, providerGetter: getter, } err = catacomb.Invoke(catacomb.Plan{ @@ -120,22 +121,22 @@ func newWorker(ctx context.Context, config Config, internalStates chan string) ( // Environ returns the encapsulated Environ. It will continue to be updated in // the background for as long as the Worker continues to run. -func (t *trackerWorker) Environ() environs.Environ { - return t.environ +func (t *trackerWorker[T]) Provider() T { + return t.provider } // Kill is part of the worker.Worker interface. -func (t *trackerWorker) Kill() { +func (t *trackerWorker[T]) Kill() { t.catacomb.Kill(nil) } // Wait is part of the worker.Worker interface. -func (t *trackerWorker) Wait() error { +func (t *trackerWorker[T]) Wait() error { return t.catacomb.Wait() } -func (t *trackerWorker) loop() (err error) { - cfg := t.environ.Config() +func (t *trackerWorker[T]) loop() (err error) { + cfg := t.provider.Config() defer errors.DeferredAnnotatef(&err, "model %q (%s)", cfg.Name(), cfg.UUID()) ctx, cancel := t.scopedContext() @@ -158,7 +159,7 @@ func (t *trackerWorker) loop() (err error) { // Not every provider supports updating the cloud spec, we only want // to get the cloud and credential watchers if the provider supports it. - cloudSpecSetter, ok := t.environ.(environs.CloudSpecSetter) + cloudSpecSetter, ok := any(t.provider).(environs.CloudSpecSetter) if ok { cloudChanges, err = t.watchCloudChanges(ctx) if err != nil { @@ -192,7 +193,7 @@ func (t *trackerWorker) loop() (err error) { if err != nil { return errors.Annotate(err, "reading model config") } - if err = t.environ.SetConfig(modelConfig); err != nil { + if err = t.provider.SetConfig(modelConfig); err != nil { return errors.Annotate(err, "updating provider config") } @@ -222,12 +223,12 @@ func (t *trackerWorker) loop() (err error) { // scopedContext returns a context that is in the scope of the worker lifetime. // It returns a cancellable context that is cancelled when the action has // completed. -func (t *trackerWorker) scopedContext() (context.Context, context.CancelFunc) { +func (t *trackerWorker[T]) scopedContext() (context.Context, context.CancelFunc) { ctx, cancel := context.WithCancel(context.Background()) return t.catacomb.Context(ctx), cancel } -func (t *trackerWorker) reportInternalState(state string) { +func (t *trackerWorker[T]) reportInternalState(state string) { select { case <-t.catacomb.Dying(): case t.internalStates <- state: @@ -235,7 +236,7 @@ func (t *trackerWorker) reportInternalState(state string) { } } -func (t *trackerWorker) watchCloudChanges(ctx context.Context) (<-chan struct{}, error) { +func (t *trackerWorker[T]) watchCloudChanges(ctx context.Context) (<-chan struct{}, error) { cloudWatcher, err := t.config.CloudService.WatchCloud(ctx, t.model.Cloud) if err != nil { return nil, errors.Annotate(err, "watching cloud") @@ -246,7 +247,7 @@ func (t *trackerWorker) watchCloudChanges(ctx context.Context) (<-chan struct{}, return cloudWatcher.Changes(), nil } -func (t *trackerWorker) watchCredentialChanges(ctx context.Context) (<-chan struct{}, error) { +func (t *trackerWorker[T]) watchCredentialChanges(ctx context.Context) (<-chan struct{}, error) { credentialName := t.model.CredentialName if credentialName == "" { return nil, nil @@ -266,7 +267,7 @@ func (t *trackerWorker) watchCredentialChanges(ctx context.Context) (<-chan stru return credentialWatcher.Changes(), nil } -func (t *trackerWorker) updateCloudSpec(ctx context.Context, cloudSetter environs.CloudSpecSetter) error { +func (t *trackerWorker[T]) updateCloudSpec(ctx context.Context, cloudSetter environs.CloudSpecSetter) error { spec, err := t.providerGetter.CloudSpec(ctx) if err != nil { return errors.Annotatef(err, "getting cloud spec") @@ -286,7 +287,7 @@ func (t *trackerWorker) updateCloudSpec(ctx context.Context, cloudSetter environ return nil } -func (t *trackerWorker) addNotifyWatcher(ctx context.Context, watcher eventsource.Watcher[struct{}]) error { +func (t *trackerWorker[T]) addNotifyWatcher(ctx context.Context, watcher eventsource.Watcher[struct{}]) error { if err := t.catacomb.Add(watcher); err != nil { return errors.Trace(err) } @@ -301,7 +302,7 @@ func (t *trackerWorker) addNotifyWatcher(ctx context.Context, watcher eventsourc return nil } -func (t *trackerWorker) addStringsWatcher(ctx context.Context, watcher eventsource.Watcher[[]string]) error { +func (t *trackerWorker[T]) addStringsWatcher(ctx context.Context, watcher eventsource.Watcher[[]string]) error { if err := t.catacomb.Add(watcher); err != nil { return errors.Trace(err) } @@ -323,10 +324,17 @@ type providerGetter struct { credentialService CredentialService } +// ControllerUUID returns the controller UUID. +func (g providerGetter) ControllerUUID() coremodel.UUID { + return g.model.ControllerUUID +} + +// ModelUUID returns the model UUID. func (g providerGetter) ModelConfig(ctx context.Context) (*config.Config, error) { return g.configService.ModelConfig(ctx) } +// CloudSpec returns the cloud spec for the model. func (g providerGetter) CloudSpec(ctx context.Context) (environscloudspec.CloudSpec, error) { modelCredentials, err := modelCredentials(ctx, g.credentialService, g.model) if err != nil { diff --git a/internal/worker/providertracker/worker_test.go b/internal/worker/providertracker/worker_test.go index 359ab01fde2..6a84cd13292 100644 --- a/internal/worker/providertracker/worker_test.go +++ b/internal/worker/providertracker/worker_test.go @@ -36,8 +36,8 @@ func (s *workerSuite) TestWorkerStartup(c *gc.C) { // Ensure we can startup with a normal environ. s.expectModel(c) - cfg := s.expectGetEnviron(c) - s.expectEnvironConfig(c, cfg) + cfg := s.newCloudSpec(c) + s.expectCloudSpec(c, cfg) s.expectConfigWatcher(c) // Create the worker. @@ -56,8 +56,8 @@ func (s *workerSuite) TestWorkerStartupWithCloudSpec(c *gc.C) { // Ensure we can startup with the cloud spec setter and environ. s.expectModel(c) - cfg := s.expectGetEnviron(c) - s.expectEnvironConfig(c, cfg) + cfg := s.newCloudSpec(c) + s.expectCloudSpec(c, cfg) s.expectConfigWatcher(c) // Now we've got the cloud spec setter, we need to ensure we watch the @@ -82,8 +82,8 @@ func (s *workerSuite) TestWorkerModelConfigUpdatesEnviron(c *gc.C) { // Ensure we can startup with a normal environ. s.expectModel(c) - cfg := s.expectGetEnviron(c) - s.expectEnvironConfig(c, cfg) + cfg := s.newCloudSpec(c) + s.expectCloudSpec(c, cfg) ch := s.expectConfigWatcher(c) s.expectEnvironSetConfig(c, cfg) @@ -111,8 +111,8 @@ func (s *workerSuite) TestWorkerCloudUpdatesEnviron(c *gc.C) { // Ensure we can startup with a normal environ. s.expectModel(c) - cfg := s.expectGetEnviron(c) - s.expectEnvironConfig(c, cfg) + cfg := s.newCloudSpec(c) + s.expectCloudSpec(c, cfg) s.expectConfigWatcher(c) // Now we've got the cloud spec setter, we need to ensure we watch the @@ -142,51 +142,14 @@ func (s *workerSuite) TestWorkerCloudUpdatesEnviron(c *gc.C) { workertest.CleanKill(c, w) } -func (s *workerSuite) TestWorkerCloudDoesNotUpdateEnviron(c *gc.C) { - defer s.setupMocks(c).Finish() - - // Ensure we can startup with a normal environ. - - s.expectModel(c) - cfg := s.expectGetEnviron(c) - s.expectEnvironConfig(c, cfg) - s.expectConfigWatcher(c) - - // Now we've got the cloud spec setter, we need to ensure we watch the - // cloud and credentials. - - ch := s.expectCloudWatcher(c) - s.expectCredentialWatcher(c) - - // Nothing has changed, so no cloud spec is updated - s.expectEnvironSetSpecNoUpdate(c) - - // Create the worker. - - w, err := s.newWorker(c, s.newCloudSpecEnviron()) - c.Assert(err, jc.ErrorIsNil) - - // Send a notification so that a cloud change is picked up. - - s.ensureStartup(c) - - select { - case ch <- struct{}{}: - case <-time.After(testing.ShortWait): - c.Fatalf("timed out sending config change") - } - - workertest.CleanKill(c, w) -} - func (s *workerSuite) TestWorkerCredentialUpdatesEnviron(c *gc.C) { defer s.setupMocks(c).Finish() // Ensure we can startup with a normal environ. s.expectModel(c) - cfg := s.expectGetEnviron(c) - s.expectEnvironConfig(c, cfg) + cfg := s.newCloudSpec(c) + s.expectCloudSpec(c, cfg) s.expectConfigWatcher(c) // Now we've got the cloud spec setter, we need to ensure we watch the @@ -216,52 +179,15 @@ func (s *workerSuite) TestWorkerCredentialUpdatesEnviron(c *gc.C) { workertest.CleanKill(c, w) } -func (s *workerSuite) TestWorkerCredentialDoesNotUpdateEnviron(c *gc.C) { - defer s.setupMocks(c).Finish() - - // Ensure we can startup with a normal environ. - - s.expectModel(c) - cfg := s.expectGetEnviron(c) - s.expectEnvironConfig(c, cfg) - s.expectConfigWatcher(c) - - // Now we've got the cloud spec setter, we need to ensure we watch the - // cloud and credentials. - - s.expectCloudWatcher(c) - ch := s.expectCredentialWatcher(c) - - // Nothing has changed, so no cloud spec is updated - s.expectEnvironSetSpecNoUpdate(c) - - // Create the worker. - - w, err := s.newWorker(c, s.newCloudSpecEnviron()) - c.Assert(err, jc.ErrorIsNil) - - // Send a notification so that a credential change is picked up. - - s.ensureStartup(c) - - select { - case ch <- struct{}{}: - case <-time.After(testing.ShortWait): - c.Fatalf("timed out sending config change") - } - - workertest.CleanKill(c, w) -} - -func (s *workerSuite) getConfig(environ environs.Environ) Config { - return Config{ +func (s *workerSuite) getConfig(environ environs.Environ) Config[environs.Environ] { + return Config[environs.Environ]{ ModelService: s.modelService, CloudService: s.cloudService, ConfigService: s.configService, CredentialService: s.credentialService, - NewEnviron: func(ctx context.Context, op environs.OpenParams) (environs.Environ, error) { + GetProvider: IAASGetProvider(func(ctx context.Context, args environs.OpenParams) (environs.Environ, error) { return environ, nil - }, + }), Logger: s.logger, } } @@ -281,7 +207,7 @@ func (s *workerSuite) expectModel(c *gc.C) coremodel.UUID { return id } -func (s *workerSuite) expectGetEnviron(c *gc.C) *config.Config { +func (s *workerSuite) newCloudSpec(c *gc.C) *config.Config { cfg, err := config.New(config.NoDefaults, testing.FakeConfig()) c.Assert(err, jc.ErrorIsNil) @@ -296,7 +222,7 @@ func (s *workerSuite) expectGetEnviron(c *gc.C) *config.Config { return cfg } -func (s *workerSuite) expectEnvironConfig(c *gc.C, cfg *config.Config) { +func (s *workerSuite) expectCloudSpec(c *gc.C, cfg *config.Config) { s.environ.EXPECT().Config().Return(cfg) } @@ -317,15 +243,6 @@ func (s *workerSuite) expectEnvironSetSpecUpdate(c *gc.C) { s.cloudSpecSetter.EXPECT().SetCloudSpec(gomock.Any(), gomock.Any()).Return(nil) } -func (s *workerSuite) expectEnvironSetSpecNoUpdate(c *gc.C) { - s.cloudService.EXPECT().Cloud(gomock.Any(), "cloud").Return(&cloud.Cloud{}, nil) - s.credentialService.EXPECT().CloudCredential(gomock.Any(), credential.Key{ - Cloud: "cloud", - Owner: "owner", - Name: "name", - }).Return(cloud.Credential{}, nil) -} - func (s *workerSuite) expectConfigWatcher(c *gc.C) chan []string { ch := make(chan []string) // Seed the initial event. @@ -384,7 +301,7 @@ func (s *workerSuite) expectCredentialWatcher(c *gc.C) chan struct{} { return ch } -func (s *workerSuite) newWorker(c *gc.C, environ environs.Environ) (*trackerWorker, error) { +func (s *workerSuite) newWorker(c *gc.C, environ environs.Environ) (*trackerWorker[environs.Environ], error) { return newWorker(context.Background(), s.getConfig(environ), s.states) }