diff --git a/apiserver/facades/client/action/run_test.go b/apiserver/facades/client/action/run_test.go index 5365b9126bc..a912b47afc8 100644 --- a/apiserver/facades/client/action/run_test.go +++ b/apiserver/facades/client/action/run_test.go @@ -95,6 +95,7 @@ func (s *runSuite) TestRunMachineAndApplication(c *gc.C) { state.AddApplicationArgs{ Name: "magic", Charm: charm, + CharmURL: charm.URL(), CharmOrigin: &state.CharmOrigin{Platform: &state.Platform{OS: "ubuntu", Channel: "20.04/stable"}}, }, jujutesting.NewObjectStore(c, s.ControllerModelUUID()), @@ -159,6 +160,7 @@ func (s *runSuite) TestRunApplicationWorkload(c *gc.C) { state.AddApplicationArgs{ Name: "magic", Charm: charm, + CharmURL: charm.URL(), CharmOrigin: &state.CharmOrigin{Platform: &state.Platform{OS: "ubuntu", Channel: "20.04/stable"}}, }, jujutesting.NewObjectStore(c, s.ControllerModelUUID()), diff --git a/apiserver/facades/client/application/application_test.go b/apiserver/facades/client/application/application_test.go index b27b5c0de4e..a786520f5bc 100644 --- a/apiserver/facades/client/application/application_test.go +++ b/apiserver/facades/client/application/application_test.go @@ -382,7 +382,7 @@ func (s *applicationSuite) TestDeploy(c *gc.C) { s.setupAPI(c) s.expectCharm(c, "foo") s.expectCharmConfig(c, 2) - s.expectCharmMeta("foo", 6) + s.expectCharmMeta("foo", 7) s.expectReadSequence("foo", 1) s.expectAddApplication() s.expectCreateApplication("foo") diff --git a/apiserver/facades/client/application/deploy.go b/apiserver/facades/client/application/deploy.go index f49a93e612a..882150fac51 100644 --- a/apiserver/facades/client/application/deploy.go +++ b/apiserver/facades/client/application/deploy.go @@ -125,6 +125,7 @@ func DeployApplication( asa := state.AddApplicationArgs{ Name: args.ApplicationName, Charm: args.Charm, + CharmURL: args.Charm.URL(), CharmOrigin: origin, Storage: stateStorageDirectives(args.Storage), Devices: stateDeviceConstraints(args.Devices), diff --git a/apiserver/facades/client/application/deployrepository.go b/apiserver/facades/client/application/deployrepository.go index 762feccad03..79825906e13 100644 --- a/apiserver/facades/client/application/deployrepository.go +++ b/apiserver/facades/client/application/deployrepository.go @@ -146,6 +146,7 @@ func (api *DeployFromRepositoryAPI) DeployFromRepository(ctx context.Context, ar ApplicationConfig: dt.applicationConfig, AttachStorage: dt.attachStorage, Charm: ch, + CharmURL: ch.URL(), CharmConfig: dt.charmSettings, CharmOrigin: stOrigin, Constraints: dt.constraints, diff --git a/apiserver/facades/client/client/status_test.go b/apiserver/facades/client/client/status_test.go index 4bdc9f79165..05132bfcb74 100644 --- a/apiserver/facades/client/client/status_test.go +++ b/apiserver/facades/client/client/status_test.go @@ -950,8 +950,9 @@ func (s *statusUpgradeUnitSuite) AddApplication(c *gc.C, charmName, applicationN st := s.ControllerModel(c).State() _, err := st.AddApplication(state.AddApplicationArgs{ - Name: applicationName, - Charm: ch, + Name: applicationName, + Charm: ch, + CharmURL: ch.URL(), CharmOrigin: &state.CharmOrigin{ ID: "mycharmhubid", Hash: "mycharmhash", diff --git a/apiserver/facades/controller/charmdownloader/charmdownloader.go b/apiserver/facades/controller/charmdownloader/charmdownloader.go index 0c91462f40b..5999984cad0 100644 --- a/apiserver/facades/controller/charmdownloader/charmdownloader.go +++ b/apiserver/facades/controller/charmdownloader/charmdownloader.go @@ -141,7 +141,7 @@ func (a *CharmDownloaderAPI) downloadApplicationCharm(ctx context.Context, appTa } a.logger.Infof("downloading charm %q", pendingCharmURL) - downloadedOrigin, err := downloader.DownloadAndStore(ctx, pendingCharmURL, *resolvedOrigin, force) + downloadedOrigin, _, err := downloader.DownloadAndStore(ctx, pendingCharmURL, *resolvedOrigin, force) if err != nil { return errors.Annotatef(err, "cannot download and store charm %q", pendingCharmURL) } diff --git a/apiserver/facades/controller/charmdownloader/charmdownloader_test.go b/apiserver/facades/controller/charmdownloader/charmdownloader_test.go index 09bf0ae83c7..b4391df577c 100644 --- a/apiserver/facades/controller/charmdownloader/charmdownloader_test.go +++ b/apiserver/facades/controller/charmdownloader/charmdownloader_test.go @@ -103,7 +103,7 @@ func (s *charmDownloaderSuite) TestDownloadApplicationCharmsDeploy(c *gc.C) { s.authChecker.EXPECT().AuthController().Return(true) s.stateBackend.EXPECT().Application("ufo").Return(app, nil) - s.downloader.EXPECT().DownloadAndStore(gomock.Any(), charmURL, resolvedOrigin, false).Return(downloadedOrigin, nil) + s.downloader.EXPECT().DownloadAndStore(gomock.Any(), charmURL, resolvedOrigin, false).Return(downloadedOrigin, nil, nil) got, err := s.api.DownloadApplicationCharms(context.Background(), params.Entities{ Entities: []params.Entity{ @@ -150,7 +150,7 @@ func (s *charmDownloaderSuite) TestDownloadApplicationCharmsDeployMultiAppOneCha s.authChecker.EXPECT().AuthController().Return(true) s.stateBackend.EXPECT().Application("ufo").Return(appOne, nil) s.stateBackend.EXPECT().Application("another-ufo").Return(appTwo, nil) - s.downloader.EXPECT().DownloadAndStore(gomock.Any(), charmURL, resolvedOrigin, false).Return(downloadedOrigin, nil).AnyTimes() + s.downloader.EXPECT().DownloadAndStore(gomock.Any(), charmURL, resolvedOrigin, false).Return(downloadedOrigin, nil, nil).AnyTimes() got, err := s.api.DownloadApplicationCharms(context.Background(), params.Entities{ Entities: []params.Entity{ @@ -193,7 +193,7 @@ func (s *charmDownloaderSuite) TestDownloadApplicationCharmsRefresh(c *gc.C) { s.authChecker.EXPECT().AuthController().Return(true) s.stateBackend.EXPECT().Application("ufo").Return(app, nil) - s.downloader.EXPECT().DownloadAndStore(gomock.Any(), charmURL, resolvedOrigin, false).Return(downloadedOrigin, nil) + s.downloader.EXPECT().DownloadAndStore(gomock.Any(), charmURL, resolvedOrigin, false).Return(downloadedOrigin, nil, nil) got, err := s.api.DownloadApplicationCharms(context.Background(), params.Entities{ Entities: []params.Entity{ @@ -228,7 +228,7 @@ func (s *charmDownloaderSuite) TestDownloadApplicationCharmsSetStatusIfDownloadF s.authChecker.EXPECT().AuthController().Return(true) s.stateBackend.EXPECT().Application("ufo").Return(app, nil) - s.downloader.EXPECT().DownloadAndStore(gomock.Any(), charmURL, resolvedOrigin, false).Return(corecharm.Origin{}, errors.NotFoundf("charm")) + s.downloader.EXPECT().DownloadAndStore(gomock.Any(), charmURL, resolvedOrigin, false).Return(corecharm.Origin{}, nil, errors.NotFoundf("charm")) got, err := s.api.DownloadApplicationCharms(context.Background(), params.Entities{ Entities: []params.Entity{ diff --git a/apiserver/facades/controller/charmdownloader/interfaces.go b/apiserver/facades/controller/charmdownloader/interfaces.go index b2788991889..f5a8f8177de 100644 --- a/apiserver/facades/controller/charmdownloader/interfaces.go +++ b/apiserver/facades/controller/charmdownloader/interfaces.go @@ -40,7 +40,7 @@ type Charm interface { // Downloader defines an API for downloading and storing charms. type Downloader interface { - DownloadAndStore(ctx context.Context, charmURL *charm.URL, requestedOrigin corecharm.Origin, force bool) (corecharm.Origin, error) + DownloadAndStore(ctx context.Context, charmURL *charm.URL, requestedOrigin corecharm.Origin, force bool) (corecharm.Origin, charm.Charm, error) } // AuthChecker provides an API for checking if the API client is a controller. diff --git a/apiserver/facades/controller/charmdownloader/mocks/mocks.go b/apiserver/facades/controller/charmdownloader/mocks/mocks.go index badb8b918ce..7dee3ef0659 100644 --- a/apiserver/facades/controller/charmdownloader/mocks/mocks.go +++ b/apiserver/facades/controller/charmdownloader/mocks/mocks.go @@ -539,12 +539,13 @@ func (m *MockDownloader) EXPECT() *MockDownloaderMockRecorder { } // DownloadAndStore mocks base method. -func (m *MockDownloader) DownloadAndStore(arg0 context.Context, arg1 *charm0.URL, arg2 charm.Origin, arg3 bool) (charm.Origin, error) { +func (m *MockDownloader) DownloadAndStore(arg0 context.Context, arg1 *charm0.URL, arg2 charm.Origin, arg3 bool) (charm.Origin, charm0.Charm, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "DownloadAndStore", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(charm.Origin) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret1, _ := ret[1].(charm0.Charm) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 } // DownloadAndStore indicates an expected call of DownloadAndStore. @@ -560,19 +561,19 @@ type MockDownloaderDownloadAndStoreCall struct { } // Return rewrite *gomock.Call.Return -func (c *MockDownloaderDownloadAndStoreCall) Return(arg0 charm.Origin, arg1 error) *MockDownloaderDownloadAndStoreCall { - c.Call = c.Call.Return(arg0, arg1) +func (c *MockDownloaderDownloadAndStoreCall) Return(arg0 charm.Origin, arg1 charm0.Charm, arg2 error) *MockDownloaderDownloadAndStoreCall { + c.Call = c.Call.Return(arg0, arg1, arg2) return c } // Do rewrite *gomock.Call.Do -func (c *MockDownloaderDownloadAndStoreCall) Do(f func(context.Context, *charm0.URL, charm.Origin, bool) (charm.Origin, error)) *MockDownloaderDownloadAndStoreCall { +func (c *MockDownloaderDownloadAndStoreCall) Do(f func(context.Context, *charm0.URL, charm.Origin, bool) (charm.Origin, charm0.Charm, error)) *MockDownloaderDownloadAndStoreCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockDownloaderDownloadAndStoreCall) DoAndReturn(f func(context.Context, *charm0.URL, charm.Origin, bool) (charm.Origin, error)) *MockDownloaderDownloadAndStoreCall { +func (c *MockDownloaderDownloadAndStoreCall) DoAndReturn(f func(context.Context, *charm0.URL, charm.Origin, bool) (charm.Origin, charm0.Charm, error)) *MockDownloaderDownloadAndStoreCall { c.Call = c.Call.DoAndReturn(f) return c } diff --git a/internal/bootstrap/bootstrap_mock_test.go b/internal/bootstrap/bootstrap_mock_test.go index 86fbf798acc..d461c7b7673 100644 --- a/internal/bootstrap/bootstrap_mock_test.go +++ b/internal/bootstrap/bootstrap_mock_test.go @@ -1,9 +1,9 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/juju/juju/internal/bootstrap (interfaces: AgentBinaryStorage,ControllerCharmDeployer,HTTPClient,CloudService,CloudServiceGetter,OperationApplier,Machine,MachineGetter,StateBackend,Application,Charm,Unit,CharmUploader,ApplicationService,ModelConfigService) +// Source: github.com/juju/juju/internal/bootstrap (interfaces: AgentBinaryStorage,ControllerCharmDeployer,HTTPClient,CloudService,CloudServiceGetter,OperationApplier,Machine,MachineGetter,StateBackend,Application,Charm,Unit,CharmUploader,ApplicationService,ModelConfigService,Downloader) // // Generated by this command: // -// mockgen -typed -package bootstrap -destination bootstrap_mock_test.go github.com/juju/juju/internal/bootstrap AgentBinaryStorage,ControllerCharmDeployer,HTTPClient,CloudService,CloudServiceGetter,OperationApplier,Machine,MachineGetter,StateBackend,Application,Charm,Unit,CharmUploader,ApplicationService,ModelConfigService +// mockgen -typed -package bootstrap -destination bootstrap_mock_test.go github.com/juju/juju/internal/bootstrap AgentBinaryStorage,ControllerCharmDeployer,HTTPClient,CloudService,CloudServiceGetter,OperationApplier,Machine,MachineGetter,StateBackend,Application,Charm,Unit,CharmUploader,ApplicationService,ModelConfigService,Downloader // // Package bootstrap is a generated GoMock package. @@ -117,18 +117,18 @@ func (m *MockControllerCharmDeployer) EXPECT() *MockControllerCharmDeployerMockR } // AddControllerApplication mocks base method. -func (m *MockControllerCharmDeployer) AddControllerApplication(arg0 context.Context, arg1 string, arg2 charm.Origin, arg3 string) (Unit, error) { +func (m *MockControllerCharmDeployer) AddControllerApplication(arg0 context.Context, arg1 string, arg2 charm.Origin, arg3 charm0.Charm, arg4 string) (Unit, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddControllerApplication", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "AddControllerApplication", arg0, arg1, arg2, arg3, arg4) ret0, _ := ret[0].(Unit) ret1, _ := ret[1].(error) return ret0, ret1 } // AddControllerApplication indicates an expected call of AddControllerApplication. -func (mr *MockControllerCharmDeployerMockRecorder) AddControllerApplication(arg0, arg1, arg2, arg3 any) *MockControllerCharmDeployerAddControllerApplicationCall { +func (mr *MockControllerCharmDeployerMockRecorder) AddControllerApplication(arg0, arg1, arg2, arg3, arg4 any) *MockControllerCharmDeployerAddControllerApplicationCall { mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddControllerApplication", reflect.TypeOf((*MockControllerCharmDeployer)(nil).AddControllerApplication), arg0, arg1, arg2, arg3) + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddControllerApplication", reflect.TypeOf((*MockControllerCharmDeployer)(nil).AddControllerApplication), arg0, arg1, arg2, arg3, arg4) return &MockControllerCharmDeployerAddControllerApplicationCall{Call: call} } @@ -144,13 +144,13 @@ func (c *MockControllerCharmDeployerAddControllerApplicationCall) Return(arg0 Un } // Do rewrite *gomock.Call.Do -func (c *MockControllerCharmDeployerAddControllerApplicationCall) Do(f func(context.Context, string, charm.Origin, string) (Unit, error)) *MockControllerCharmDeployerAddControllerApplicationCall { +func (c *MockControllerCharmDeployerAddControllerApplicationCall) Do(f func(context.Context, string, charm.Origin, charm0.Charm, string) (Unit, error)) *MockControllerCharmDeployerAddControllerApplicationCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockControllerCharmDeployerAddControllerApplicationCall) DoAndReturn(f func(context.Context, string, charm.Origin, string) (Unit, error)) *MockControllerCharmDeployerAddControllerApplicationCall { +func (c *MockControllerCharmDeployerAddControllerApplicationCall) DoAndReturn(f func(context.Context, string, charm.Origin, charm0.Charm, string) (Unit, error)) *MockControllerCharmDeployerAddControllerApplicationCall { c.Call = c.Call.DoAndReturn(f) return c } @@ -310,13 +310,14 @@ func (c *MockControllerCharmDeployerControllerCharmBaseCall) DoAndReturn(f func( } // DeployCharmhubCharm mocks base method. -func (m *MockControllerCharmDeployer) DeployCharmhubCharm(arg0 context.Context, arg1 string, arg2 base.Base) (string, *charm.Origin, error) { +func (m *MockControllerCharmDeployer) DeployCharmhubCharm(arg0 context.Context, arg1 string, arg2 base.Base) (string, *charm.Origin, charm0.Charm, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "DeployCharmhubCharm", arg0, arg1, arg2) ret0, _ := ret[0].(string) ret1, _ := ret[1].(*charm.Origin) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 + ret2, _ := ret[2].(charm0.Charm) + ret3, _ := ret[3].(error) + return ret0, ret1, ret2, ret3 } // DeployCharmhubCharm indicates an expected call of DeployCharmhubCharm. @@ -332,31 +333,32 @@ type MockControllerCharmDeployerDeployCharmhubCharmCall struct { } // Return rewrite *gomock.Call.Return -func (c *MockControllerCharmDeployerDeployCharmhubCharmCall) Return(arg0 string, arg1 *charm.Origin, arg2 error) *MockControllerCharmDeployerDeployCharmhubCharmCall { - c.Call = c.Call.Return(arg0, arg1, arg2) +func (c *MockControllerCharmDeployerDeployCharmhubCharmCall) Return(arg0 string, arg1 *charm.Origin, arg2 charm0.Charm, arg3 error) *MockControllerCharmDeployerDeployCharmhubCharmCall { + c.Call = c.Call.Return(arg0, arg1, arg2, arg3) return c } // Do rewrite *gomock.Call.Do -func (c *MockControllerCharmDeployerDeployCharmhubCharmCall) Do(f func(context.Context, string, base.Base) (string, *charm.Origin, error)) *MockControllerCharmDeployerDeployCharmhubCharmCall { +func (c *MockControllerCharmDeployerDeployCharmhubCharmCall) Do(f func(context.Context, string, base.Base) (string, *charm.Origin, charm0.Charm, error)) *MockControllerCharmDeployerDeployCharmhubCharmCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockControllerCharmDeployerDeployCharmhubCharmCall) DoAndReturn(f func(context.Context, string, base.Base) (string, *charm.Origin, error)) *MockControllerCharmDeployerDeployCharmhubCharmCall { +func (c *MockControllerCharmDeployerDeployCharmhubCharmCall) DoAndReturn(f func(context.Context, string, base.Base) (string, *charm.Origin, charm0.Charm, error)) *MockControllerCharmDeployerDeployCharmhubCharmCall { c.Call = c.Call.DoAndReturn(f) return c } // DeployLocalCharm mocks base method. -func (m *MockControllerCharmDeployer) DeployLocalCharm(arg0 context.Context, arg1 string, arg2 base.Base) (string, *charm.Origin, error) { +func (m *MockControllerCharmDeployer) DeployLocalCharm(arg0 context.Context, arg1 string, arg2 base.Base) (string, *charm.Origin, charm0.Charm, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "DeployLocalCharm", arg0, arg1, arg2) ret0, _ := ret[0].(string) ret1, _ := ret[1].(*charm.Origin) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 + ret2, _ := ret[2].(charm0.Charm) + ret3, _ := ret[3].(error) + return ret0, ret1, ret2, ret3 } // DeployLocalCharm indicates an expected call of DeployLocalCharm. @@ -372,19 +374,19 @@ type MockControllerCharmDeployerDeployLocalCharmCall struct { } // Return rewrite *gomock.Call.Return -func (c *MockControllerCharmDeployerDeployLocalCharmCall) Return(arg0 string, arg1 *charm.Origin, arg2 error) *MockControllerCharmDeployerDeployLocalCharmCall { - c.Call = c.Call.Return(arg0, arg1, arg2) +func (c *MockControllerCharmDeployerDeployLocalCharmCall) Return(arg0 string, arg1 *charm.Origin, arg2 charm0.Charm, arg3 error) *MockControllerCharmDeployerDeployLocalCharmCall { + c.Call = c.Call.Return(arg0, arg1, arg2, arg3) return c } // Do rewrite *gomock.Call.Do -func (c *MockControllerCharmDeployerDeployLocalCharmCall) Do(f func(context.Context, string, base.Base) (string, *charm.Origin, error)) *MockControllerCharmDeployerDeployLocalCharmCall { +func (c *MockControllerCharmDeployerDeployLocalCharmCall) Do(f func(context.Context, string, base.Base) (string, *charm.Origin, charm0.Charm, error)) *MockControllerCharmDeployerDeployLocalCharmCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockControllerCharmDeployerDeployLocalCharmCall) DoAndReturn(f func(context.Context, string, base.Base) (string, *charm.Origin, error)) *MockControllerCharmDeployerDeployLocalCharmCall { +func (c *MockControllerCharmDeployerDeployLocalCharmCall) DoAndReturn(f func(context.Context, string, base.Base) (string, *charm.Origin, charm0.Charm, error)) *MockControllerCharmDeployerDeployLocalCharmCall { c.Call = c.Call.DoAndReturn(f) return c } @@ -1199,45 +1201,6 @@ func (c *MockStateBackendAddApplicationCall) DoAndReturn(f func(state.AddApplica return c } -// Charm mocks base method. -func (m *MockStateBackend) Charm(arg0 string) (Charm, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Charm", arg0) - ret0, _ := ret[0].(Charm) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Charm indicates an expected call of Charm. -func (mr *MockStateBackendMockRecorder) Charm(arg0 any) *MockStateBackendCharmCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Charm", reflect.TypeOf((*MockStateBackend)(nil).Charm), arg0) - return &MockStateBackendCharmCall{Call: call} -} - -// MockStateBackendCharmCall wrap *gomock.Call -type MockStateBackendCharmCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockStateBackendCharmCall) Return(arg0 Charm, arg1 error) *MockStateBackendCharmCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockStateBackendCharmCall) Do(f func(string) (Charm, error)) *MockStateBackendCharmCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockStateBackendCharmCall) DoAndReturn(f func(string) (Charm, error)) *MockStateBackendCharmCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - // Unit mocks base method. func (m *MockStateBackend) Unit(arg0 string) (Unit, error) { m.ctrl.T.Helper() @@ -2146,3 +2109,66 @@ func (c *MockModelConfigServiceModelConfigCall) DoAndReturn(f func(context.Conte c.Call = c.Call.DoAndReturn(f) return c } + +// MockDownloader is a mock of Downloader interface. +type MockDownloader struct { + ctrl *gomock.Controller + recorder *MockDownloaderMockRecorder +} + +// MockDownloaderMockRecorder is the mock recorder for MockDownloader. +type MockDownloaderMockRecorder struct { + mock *MockDownloader +} + +// NewMockDownloader creates a new mock instance. +func NewMockDownloader(ctrl *gomock.Controller) *MockDownloader { + mock := &MockDownloader{ctrl: ctrl} + mock.recorder = &MockDownloaderMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDownloader) EXPECT() *MockDownloaderMockRecorder { + return m.recorder +} + +// DownloadAndStore mocks base method. +func (m *MockDownloader) DownloadAndStore(arg0 context.Context, arg1 *charm0.URL, arg2 charm.Origin, arg3 bool) (charm.Origin, charm0.Charm, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DownloadAndStore", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(charm.Origin) + ret1, _ := ret[1].(charm0.Charm) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// DownloadAndStore indicates an expected call of DownloadAndStore. +func (mr *MockDownloaderMockRecorder) DownloadAndStore(arg0, arg1, arg2, arg3 any) *MockDownloaderDownloadAndStoreCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DownloadAndStore", reflect.TypeOf((*MockDownloader)(nil).DownloadAndStore), arg0, arg1, arg2, arg3) + return &MockDownloaderDownloadAndStoreCall{Call: call} +} + +// MockDownloaderDownloadAndStoreCall wrap *gomock.Call +type MockDownloaderDownloadAndStoreCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockDownloaderDownloadAndStoreCall) Return(arg0 charm.Origin, arg1 charm0.Charm, arg2 error) *MockDownloaderDownloadAndStoreCall { + c.Call = c.Call.Return(arg0, arg1, arg2) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockDownloaderDownloadAndStoreCall) Do(f func(context.Context, *charm0.URL, charm.Origin, bool) (charm.Origin, charm0.Charm, error)) *MockDownloaderDownloadAndStoreCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockDownloaderDownloadAndStoreCall) DoAndReturn(f func(context.Context, *charm0.URL, charm.Origin, bool) (charm.Origin, charm0.Charm, error)) *MockDownloaderDownloadAndStoreCall { + c.Call = c.Call.DoAndReturn(f) + return c +} diff --git a/internal/bootstrap/controller.go b/internal/bootstrap/controller.go index 68b57e6bb47..e0ac95f97be 100644 --- a/internal/bootstrap/controller.go +++ b/internal/bootstrap/controller.go @@ -36,14 +36,14 @@ func PopulateControllerCharm(ctx context.Context, deployer ControllerCharmDeploy // When deploying a local charm, it is expected that the charm is located // in a certain location. If the charm is not located there, we'll get an // error indicating that the charm is not found. - curl, origin, err := deployer.DeployLocalCharm(ctx, arch, base) + curl, origin, ch, err := deployer.DeployLocalCharm(ctx, arch, base) if err != nil && !errors.Is(err, errors.NotFound) { return errors.Annotatef(err, "deploying local controller charm") } // If the errors is not found locally, we'll try to download it from // charm hub. if errors.Is(err, errors.NotFound) { - curl, origin, err = deployer.DeployCharmhubCharm(ctx, arch, base) + curl, origin, ch, err = deployer.DeployCharmhubCharm(ctx, arch, base) if err != nil { return errors.Annotatef(err, "deploying charmhub controller charm") } @@ -53,7 +53,7 @@ func PopulateControllerCharm(ctx context.Context, deployer ControllerCharmDeploy } // Once the charm is added, set up the controller application. - controllerUnit, err := deployer.AddControllerApplication(ctx, curl, *origin, controllerAddress) + controllerUnit, err := deployer.AddControllerApplication(ctx, curl, *origin, ch, controllerAddress) if err != nil && !errors.Is(err, applicationerrors.ApplicationAlreadyExists) { return errors.Annotatef(err, "adding controller application") } diff --git a/internal/bootstrap/controller_test.go b/internal/bootstrap/controller_test.go index 54a81d71548..306654863df 100644 --- a/internal/bootstrap/controller_test.go +++ b/internal/bootstrap/controller_test.go @@ -87,7 +87,7 @@ func (s *ControllerSuite) TestPopulateControllerAlreadyExists(c *gc.C) { s.expectCharmInfo() s.expectLocalCharmNotFound() s.expectCharmhubDeployment(origin) - s.deployer.EXPECT().AddControllerApplication(gomock.Any(), "juju-controller", origin, "10.0.0.1").Return(s.unit, applicationerrors.ApplicationAlreadyExists) + s.deployer.EXPECT().AddControllerApplication(gomock.Any(), "juju-controller", origin, s.charm, "10.0.0.1").Return(s.unit, applicationerrors.ApplicationAlreadyExists) s.expectCompletion() err := PopulateControllerCharm(context.Background(), s.deployer) @@ -104,23 +104,23 @@ func (s *ControllerSuite) expectCharmInfo() { } func (s *ControllerSuite) expectLocalDeployment(origin charm.Origin) { - s.deployer.EXPECT().DeployLocalCharm(gomock.Any(), arch.DefaultArchitecture, defaultBase).Return("juju-controller", &origin, nil) + s.deployer.EXPECT().DeployLocalCharm(gomock.Any(), arch.DefaultArchitecture, defaultBase).Return("juju-controller", &origin, s.charm, nil) } func (s *ControllerSuite) expectLocalCharmNotFound() { - s.deployer.EXPECT().DeployLocalCharm(gomock.Any(), arch.DefaultArchitecture, defaultBase).Return("", nil, errors.NotFoundf("not found")) + s.deployer.EXPECT().DeployLocalCharm(gomock.Any(), arch.DefaultArchitecture, defaultBase).Return("", nil, s.charm, errors.NotFoundf("not found")) } func (s *ControllerSuite) expectLocalCharmError() { - s.deployer.EXPECT().DeployLocalCharm(gomock.Any(), arch.DefaultArchitecture, defaultBase).Return("", nil, errors.Errorf("boom")) + s.deployer.EXPECT().DeployLocalCharm(gomock.Any(), arch.DefaultArchitecture, defaultBase).Return("", nil, s.charm, errors.Errorf("boom")) } func (s *ControllerSuite) expectCharmhubDeployment(origin charm.Origin) { - s.deployer.EXPECT().DeployCharmhubCharm(gomock.Any(), arch.DefaultArchitecture, defaultBase).Return("juju-controller", &origin, nil) + s.deployer.EXPECT().DeployCharmhubCharm(gomock.Any(), arch.DefaultArchitecture, defaultBase).Return("juju-controller", &origin, s.charm, nil) } func (s *ControllerSuite) expectAddApplication(origin charm.Origin) { - s.deployer.EXPECT().AddControllerApplication(gomock.Any(), "juju-controller", origin, "10.0.0.1").Return(s.unit, nil) + s.deployer.EXPECT().AddControllerApplication(gomock.Any(), "juju-controller", origin, s.charm, "10.0.0.1").Return(s.unit, nil) } func (s *ControllerSuite) expectCompletion() { diff --git a/internal/bootstrap/deployer.go b/internal/bootstrap/deployer.go index ec0048e636b..6914546a11c 100644 --- a/internal/bootstrap/deployer.go +++ b/internal/bootstrap/deployer.go @@ -41,13 +41,13 @@ import ( type ControllerCharmDeployer interface { // DeployLocalCharm deploys the controller charm from the local charm // store. - DeployLocalCharm(context.Context, string, corebase.Base) (string, *corecharm.Origin, error) + DeployLocalCharm(context.Context, string, corebase.Base) (string, *corecharm.Origin, charm.Charm, error) // DeployCharmhubCharm deploys the controller charm from charm hub. - DeployCharmhubCharm(context.Context, string, corebase.Base) (string, *corecharm.Origin, error) + DeployCharmhubCharm(context.Context, string, corebase.Base) (string, *corecharm.Origin, charm.Charm, error) // AddControllerApplication adds the controller application. - AddControllerApplication(context.Context, string, corecharm.Origin, string) (Unit, error) + AddControllerApplication(context.Context, string, corecharm.Origin, charm.Charm, string) (Unit, error) // ControllerAddress returns the address of the controller that should be // used. @@ -105,7 +105,7 @@ type CharmRepoFunc func(services.CharmRepoFactoryConfig) (corecharm.Repository, // Downloader defines an API for downloading and storing charms. type Downloader interface { - DownloadAndStore(ctx context.Context, charmURL *charm.URL, requestedOrigin corecharm.Origin, force bool) (corecharm.Origin, error) + DownloadAndStore(ctx context.Context, charmURL *charm.URL, requestedOrigin corecharm.Origin, force bool) (corecharm.Origin, charm.Charm, error) } // CharmDownloaderFunc is the function that is used to create a charm @@ -145,7 +145,6 @@ type Unit interface { // state. type StateBackend interface { AddApplication(state.AddApplicationArgs, objectstore.ObjectStore) (Application, error) - Charm(string) (Charm, error) Unit(string) (Unit, error) } @@ -253,19 +252,19 @@ func (b *baseDeployer) ControllerCharmArch() string { // DeployLocalCharm deploys the controller charm from the local charm // store. -func (b *baseDeployer) DeployLocalCharm(ctx context.Context, arch string, base corebase.Base) (string, *corecharm.Origin, error) { +func (b *baseDeployer) DeployLocalCharm(ctx context.Context, arch string, base corebase.Base) (string, *corecharm.Origin, charm.Charm, error) { controllerCharmPath := filepath.Join(b.dataDir, "charms", bootstrap.ControllerCharmArchive) _, err := os.Stat(controllerCharmPath) if os.IsNotExist(err) { - return "", nil, errors.NotFoundf(controllerCharmPath) + return "", nil, nil, errors.NotFoundf(controllerCharmPath) } if err != nil { - return "", nil, errors.Trace(err) + return "", nil, nil, errors.Trace(err) } - curl, err := addLocalControllerCharm(ctx, b.objectStore, b.charmUploader, controllerCharmPath) + curl, ch, err := addLocalControllerCharm(ctx, b.objectStore, b.charmUploader, controllerCharmPath) if err != nil { - return "", nil, errors.Annotatef(err, "cannot store controller charm at %q", controllerCharmPath) + return "", nil, nil, errors.Annotatef(err, "cannot store controller charm at %q", controllerCharmPath) } b.logger.Debugf("Successfully deployed local Juju controller charm") origin := corecharm.Origin{ @@ -277,18 +276,18 @@ func (b *baseDeployer) DeployLocalCharm(ctx context.Context, arch string, base c Channel: base.Channel.String(), }, } - return curl.String(), &origin, nil + return curl.String(), &origin, ch, nil } // DeployCharmhubCharm deploys the controller charm from charm hub. -func (b *baseDeployer) DeployCharmhubCharm(ctx context.Context, arch string, base corebase.Base) (string, *corecharm.Origin, error) { +func (b *baseDeployer) DeployCharmhubCharm(ctx context.Context, arch string, base corebase.Base) (string, *corecharm.Origin, charm.Charm, error) { charmRepo, err := b.newCharmRepo(services.CharmRepoFactoryConfig{ Logger: b.logger, CharmhubHTTPClient: b.charmhubHTTPClient, ModelConfigService: b.modelConfigService, }) if err != nil { - return "", nil, errors.Trace(err) + return "", nil, nil, errors.Trace(err) } var curl *charm.URL @@ -297,9 +296,6 @@ func (b *baseDeployer) DeployCharmhubCharm(ctx context.Context, arch string, bas } else { curl = charm.MustParseURL(b.controllerCharmName) } - if err != nil { - return "", nil, errors.Trace(err) - } origin := corecharm.Origin{ Source: corecharm.CharmHub, Type: "charm", @@ -323,7 +319,7 @@ func (b *baseDeployer) DeployCharmhubCharm(ctx context.Context, arch string, bas // The controller charm doesn't have any base specific code. curl, origin, _, err = charmRepo.ResolveWithPreferredChannel(ctx, curl.Name, origin) if err != nil { - return "", nil, errors.Annotatef(err, "resolving %q", controllerCharmURL) + return "", nil, nil, errors.Annotatef(err, "resolving %q", controllerCharmURL) } charmDownloader, err := b.newCharmDownloader(services.CharmDownloaderConfig{ @@ -334,24 +330,20 @@ func (b *baseDeployer) DeployCharmhubCharm(ctx context.Context, arch string, bas ModelConfigService: b.modelConfigService, }) if err != nil { - return "", nil, errors.Trace(err) + return "", nil, nil, errors.Trace(err) } - resOrigin, err := charmDownloader.DownloadAndStore(ctx, curl, origin, false) + resOrigin, ch, err := charmDownloader.DownloadAndStore(ctx, curl, origin, false) if err != nil { - return "", nil, errors.Trace(err) + return "", nil, nil, errors.Trace(err) } b.logger.Debugf("Successfully deployed charmhub Juju controller charm") - return curl.String(), &resOrigin, nil + return curl.String(), &resOrigin, ch, nil } // AddControllerApplication adds the controller application. -func (b *baseDeployer) AddControllerApplication(ctx context.Context, curl string, origin corecharm.Origin, controllerAddress string) (Unit, error) { - ch, err := b.stateBackend.Charm(curl) - if err != nil { - return nil, errors.Trace(err) - } +func (b *baseDeployer) AddControllerApplication(ctx context.Context, curl string, origin corecharm.Origin, ch charm.Charm, controllerAddress string) (Unit, error) { cfg := charm.Settings{ "is-juju": true, } @@ -381,6 +373,7 @@ func (b *baseDeployer) AddControllerApplication(ctx context.Context, curl string app, err := b.stateBackend.AddApplication(state.AddApplicationArgs{ Name: bootstrap.ControllerApplicationName, Charm: ch, + CharmURL: curl, CharmOrigin: stateOrigin, CharmConfig: cfg, Constraints: b.constraints, @@ -409,15 +402,15 @@ func (b *baseDeployer) AddControllerApplication(ctx context.Context, curl string } // addLocalControllerCharm adds the specified local charm to the controller. -func addLocalControllerCharm(ctx context.Context, objectStore services.Storage, uploader CharmUploader, charmFileName string) (*charm.URL, error) { +func addLocalControllerCharm(ctx context.Context, objectStore services.Storage, uploader CharmUploader, charmFileName string) (*charm.URL, charm.Charm, error) { archive, err := charm.ReadCharmArchive(charmFileName) if err != nil { - return nil, errors.Errorf("invalid charm archive: %v", err) + return nil, nil, errors.Errorf("invalid charm archive: %v", err) } name := archive.Meta().Name if name != bootstrap.ControllerCharmName { - return nil, errors.Errorf("unexpected controller charm name %q", name) + return nil, nil, errors.Errorf("unexpected controller charm name %q", name) } // Reserve a charm URL for it in state. @@ -428,16 +421,16 @@ func addLocalControllerCharm(ctx context.Context, objectStore services.Storage, } curl, err = uploader.PrepareLocalCharmUpload(curl.String()) if err != nil { - return nil, errors.Trace(err) + return nil, nil, errors.Trace(err) } // Now we need to repackage it with the reserved URL, upload it to // provider storage and update the state. _, _, _, _, err = apiserver.RepackageAndUploadCharm(ctx, objectStore, uploader, archive, curl.String(), archive.Revision()) if err != nil { - return nil, errors.Trace(err) + return nil, nil, errors.Trace(err) } - return curl, nil + return curl, archive, nil } // ConfigSchema is used to force the trust config option to be true for all diff --git a/internal/bootstrap/deployer_test.go b/internal/bootstrap/deployer_test.go index b17c2088b0d..dbd196bda4d 100644 --- a/internal/bootstrap/deployer_test.go +++ b/internal/bootstrap/deployer_test.go @@ -124,7 +124,7 @@ func (s *deployerSuite) TestDeployLocalCharmThatDoesNotExist(c *gc.C) { cfg := s.newConfig(c) deployer := makeBaseDeployer(cfg) - _, _, err := deployer.DeployLocalCharm(context.Background(), arch.DefaultArchitecture, base.MakeDefaultBase("ubuntu", "22.04")) + _, _, _, err := deployer.DeployLocalCharm(context.Background(), arch.DefaultArchitecture, base.MakeDefaultBase("ubuntu", "22.04")) c.Assert(err, jc.ErrorIs, errors.NotFound) } @@ -142,7 +142,7 @@ func (s *deployerSuite) TestDeployLocalCharm(c *gc.C) { deployer := s.newBaseDeployer(c, cfg) - url, origin, err := deployer.DeployLocalCharm(context.Background(), "arm64", base.MakeDefaultBase("ubuntu", "22.04")) + url, origin, ch, err := deployer.DeployLocalCharm(context.Background(), "arm64", base.MakeDefaultBase("ubuntu", "22.04")) c.Assert(err, jc.ErrorIsNil) c.Assert(url, gc.Equals, "local:arm64/juju-controller-0") c.Assert(origin, gc.DeepEquals, &corecharm.Origin{ @@ -154,6 +154,7 @@ func (s *deployerSuite) TestDeployLocalCharm(c *gc.C) { Channel: "22.04/stable", }, }) + c.Assert(ch, gc.NotNil) } func (s *deployerSuite) TestDeployCharmhubCharm(c *gc.C) { @@ -168,7 +169,7 @@ func (s *deployerSuite) TestDeployCharmhubCharm(c *gc.C) { deployer := s.newBaseDeployer(c, cfg) - url, origin, err := deployer.DeployCharmhubCharm(context.Background(), "arm64", base.MakeDefaultBase("ubuntu", "22.04")) + url, origin, ch, err := deployer.DeployCharmhubCharm(context.Background(), "arm64", base.MakeDefaultBase("ubuntu", "22.04")) c.Assert(err, jc.ErrorIsNil) c.Assert(url, gc.Equals, "ch:arm64/juju-controller-0") c.Assert(origin, gc.DeepEquals, &corecharm.Origin{ @@ -181,6 +182,7 @@ func (s *deployerSuite) TestDeployCharmhubCharm(c *gc.C) { Channel: "22.04", }, }) + c.Assert(ch, gc.NotNil) } func (s *deployerSuite) TestDeployCharmhubCharmWithCustomName(c *gc.C) { @@ -195,7 +197,7 @@ func (s *deployerSuite) TestDeployCharmhubCharmWithCustomName(c *gc.C) { deployer := s.newBaseDeployer(c, cfg) - url, origin, err := deployer.DeployCharmhubCharm(context.Background(), "arm64", base.MakeDefaultBase("ubuntu", "22.04")) + url, origin, ch, err := deployer.DeployCharmhubCharm(context.Background(), "arm64", base.MakeDefaultBase("ubuntu", "22.04")) c.Assert(err, jc.ErrorIsNil) c.Assert(url, gc.Equals, "ch:arm64/inferi-0") c.Assert(origin, gc.DeepEquals, &corecharm.Origin{ @@ -208,6 +210,7 @@ func (s *deployerSuite) TestDeployCharmhubCharmWithCustomName(c *gc.C) { Channel: "22.04", }, }) + c.Assert(ch, gc.NotNil) } func (s *deployerSuite) TestAddControllerApplication(c *gc.C) { @@ -219,9 +222,8 @@ func (s *deployerSuite) TestAddControllerApplication(c *gc.C) { cfg := s.newConfig(c) - charmName := "obscura" + curl := "ch:juju-controller-0" - s.stateBackend.EXPECT().Charm(charmName).Return(s.charm, nil) s.stateBackend.EXPECT().AddApplication(gomock.Any(), s.objectStore).DoAndReturn(func(args state.AddApplicationArgs, store objectstore.ObjectStore) (Application, error) { appCfg, err := coreconfig.NewConfig(nil, configSchema, schema.Defaults{ coreapplication.TrustConfigOptionName: true, @@ -233,8 +235,9 @@ func (s *deployerSuite) TestAddControllerApplication(c *gc.C) { // better to not persist anything at all. In that way we can be sure // that we didn't accidentally persist something that we shouldn't have. c.Check(args, gc.DeepEquals, state.AddApplicationArgs{ - Name: bootstrap.ControllerApplicationName, - Charm: s.charm, + Name: bootstrap.ControllerApplicationName, + Charm: s.charm, + CharmURL: "ch:juju-controller-0", CharmOrigin: &state.CharmOrigin{ Source: "charm-hub", Type: "charm", @@ -296,7 +299,7 @@ func (s *deployerSuite) TestAddControllerApplication(c *gc.C) { }, } address := "10.0.0.1" - unit, err := deployer.AddControllerApplication(context.Background(), charmName, origin, address) + unit, err := deployer.AddControllerApplication(context.Background(), curl, origin, s.charm, address) c.Assert(err, jc.ErrorIsNil) c.Assert(unit, gc.NotNil) } @@ -378,5 +381,5 @@ func (s *deployerSuite) expectCharmhubCharmUpload(c *gc.C, name string) { } s.charmRepo.EXPECT().ResolveWithPreferredChannel(gomock.Any(), name, origin).Return(curl, origin, nil, nil) - s.charmDownloader.EXPECT().DownloadAndStore(gomock.Any(), curl, origin, false).Return(origin, nil) + s.charmDownloader.EXPECT().DownloadAndStore(gomock.Any(), curl, origin, false).Return(origin, s.charm, nil) } diff --git a/internal/bootstrap/downloader_mock_test.go b/internal/bootstrap/downloader_mock_test.go deleted file mode 100644 index 5082235d2d8..00000000000 --- a/internal/bootstrap/downloader_mock_test.go +++ /dev/null @@ -1,81 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/juju/juju/apiserver/facades/client/charms/interfaces (interfaces: Downloader) -// -// Generated by this command: -// -// mockgen -typed -package bootstrap -destination downloader_mock_test.go github.com/juju/juju/apiserver/facades/client/charms/interfaces Downloader -// - -// Package bootstrap is a generated GoMock package. -package bootstrap - -import ( - context "context" - reflect "reflect" - - charm "github.com/juju/juju/core/charm" - charm0 "github.com/juju/juju/internal/charm" - gomock "go.uber.org/mock/gomock" -) - -// MockDownloader is a mock of Downloader interface. -type MockDownloader struct { - ctrl *gomock.Controller - recorder *MockDownloaderMockRecorder -} - -// MockDownloaderMockRecorder is the mock recorder for MockDownloader. -type MockDownloaderMockRecorder struct { - mock *MockDownloader -} - -// NewMockDownloader creates a new mock instance. -func NewMockDownloader(ctrl *gomock.Controller) *MockDownloader { - mock := &MockDownloader{ctrl: ctrl} - mock.recorder = &MockDownloaderMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockDownloader) EXPECT() *MockDownloaderMockRecorder { - return m.recorder -} - -// DownloadAndStore mocks base method. -func (m *MockDownloader) DownloadAndStore(arg0 context.Context, arg1 *charm0.URL, arg2 charm.Origin, arg3 bool) (charm.Origin, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DownloadAndStore", arg0, arg1, arg2, arg3) - ret0, _ := ret[0].(charm.Origin) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DownloadAndStore indicates an expected call of DownloadAndStore. -func (mr *MockDownloaderMockRecorder) DownloadAndStore(arg0, arg1, arg2, arg3 any) *MockDownloaderDownloadAndStoreCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DownloadAndStore", reflect.TypeOf((*MockDownloader)(nil).DownloadAndStore), arg0, arg1, arg2, arg3) - return &MockDownloaderDownloadAndStoreCall{Call: call} -} - -// MockDownloaderDownloadAndStoreCall wrap *gomock.Call -type MockDownloaderDownloadAndStoreCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockDownloaderDownloadAndStoreCall) Return(arg0 charm.Origin, arg1 error) *MockDownloaderDownloadAndStoreCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockDownloaderDownloadAndStoreCall) Do(f func(context.Context, *charm0.URL, charm.Origin, bool) (charm.Origin, error)) *MockDownloaderDownloadAndStoreCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockDownloaderDownloadAndStoreCall) DoAndReturn(f func(context.Context, *charm0.URL, charm.Origin, bool) (charm.Origin, error)) *MockDownloaderDownloadAndStoreCall { - c.Call = c.Call.DoAndReturn(f) - return c -} diff --git a/internal/bootstrap/package_test.go b/internal/bootstrap/package_test.go index 44812678358..e5faa236f60 100644 --- a/internal/bootstrap/package_test.go +++ b/internal/bootstrap/package_test.go @@ -20,10 +20,9 @@ import ( "github.com/juju/juju/internal/uuid" ) -//go:generate go run go.uber.org/mock/mockgen -typed -package bootstrap -destination bootstrap_mock_test.go github.com/juju/juju/internal/bootstrap AgentBinaryStorage,ControllerCharmDeployer,HTTPClient,CloudService,CloudServiceGetter,OperationApplier,Machine,MachineGetter,StateBackend,Application,Charm,Unit,CharmUploader,ApplicationService,ModelConfigService +//go:generate go run go.uber.org/mock/mockgen -typed -package bootstrap -destination bootstrap_mock_test.go github.com/juju/juju/internal/bootstrap AgentBinaryStorage,ControllerCharmDeployer,HTTPClient,CloudService,CloudServiceGetter,OperationApplier,Machine,MachineGetter,StateBackend,Application,Charm,Unit,CharmUploader,ApplicationService,ModelConfigService,Downloader //go:generate go run go.uber.org/mock/mockgen -typed -package bootstrap -destination objectstore_mock_test.go github.com/juju/juju/core/objectstore ObjectStore //go:generate go run go.uber.org/mock/mockgen -typed -package bootstrap -destination charm_mock_test.go github.com/juju/juju/core/charm Repository -//go:generate go run go.uber.org/mock/mockgen -typed -package bootstrap -destination downloader_mock_test.go github.com/juju/juju/apiserver/facades/client/charms/interfaces Downloader func Test(t *testing.T) { gc.TestingT(t) diff --git a/internal/charm/downloader/downloader.go b/internal/charm/downloader/downloader.go index ab75a6a30e7..3c6fd15e525 100644 --- a/internal/charm/downloader/downloader.go +++ b/internal/charm/downloader/downloader.go @@ -106,14 +106,14 @@ func NewDownloader(logger logger.Logger, storage Storage, repoGetter RepositoryG // API so it can be persisted. // // The method ensures that all temporary resources are cleaned up before returning. -func (d *Downloader) DownloadAndStore(ctx context.Context, charmURL *charm.URL, requestedOrigin corecharm.Origin, force bool) (corecharm.Origin, error) { +func (d *Downloader) DownloadAndStore(ctx context.Context, charmURL *charm.URL, requestedOrigin corecharm.Origin, force bool) (corecharm.Origin, charm.Charm, error) { var ( err error channelOrigin = requestedOrigin ) channelOrigin.Platform, err = d.normalizePlatform(charmURL.Name, requestedOrigin.Platform) if err != nil { - return corecharm.Origin{}, errors.Trace(err) + return corecharm.Origin{}, nil, errors.Trace(err) } // Notify the storage layer that we are preparing to upload a charm. @@ -126,19 +126,19 @@ func (d *Downloader) DownloadAndStore(ctx context.Context, charmURL *charm.URL, repo, err := d.getRepo(ctx, requestedOrigin.Source) if err != nil { - return corecharm.Origin{}, errors.Trace(err) + return corecharm.Origin{}, nil, errors.Trace(err) } _, resolvedOrigin, err := repo.GetDownloadURL(ctx, charmURL.Name, requestedOrigin) - return resolvedOrigin, errors.Trace(err) + return resolvedOrigin, nil, errors.Trace(err) } - return corecharm.Origin{}, errors.Trace(err) + return corecharm.Origin{}, nil, errors.Trace(err) } // Download charm blob to a temp file tmpFile, err := os.CreateTemp("", charmURL.Name) if err != nil { - return corecharm.Origin{}, errors.Trace(err) + return corecharm.Origin{}, nil, errors.Trace(err) } defer func() { _ = tmpFile.Close() @@ -149,25 +149,25 @@ func (d *Downloader) DownloadAndStore(ctx context.Context, charmURL *charm.URL, repo, err := d.getRepo(ctx, requestedOrigin.Source) if err != nil { - return corecharm.Origin{}, errors.Trace(err) + return corecharm.Origin{}, nil, errors.Trace(err) } downloadedCharm, actualOrigin, err := d.downloadAndHash(ctx, charmURL.Name, channelOrigin, repo, tmpFile.Name()) if err != nil { - return corecharm.Origin{}, errors.Annotatef(err, "downloading charm %q from origin %v", charmURL.Name, requestedOrigin) + return corecharm.Origin{}, nil, errors.Annotatef(err, "downloading charm %q from origin %v", charmURL.Name, requestedOrigin) } // Validate charm if err := downloadedCharm.verify(actualOrigin, force); err != nil { - return corecharm.Origin{}, errors.Annotatef(err, "verifying downloaded charm %q from origin %v", charmURL.Name, requestedOrigin) + return corecharm.Origin{}, nil, errors.Annotatef(err, "verifying downloaded charm %q from origin %v", charmURL.Name, requestedOrigin) } // Store Charm if err := d.storeCharm(ctx, charmURL.String(), downloadedCharm, tmpFile.Name()); err != nil { - return corecharm.Origin{}, errors.Annotatef(err, "storing charm %q from origin %v", charmURL, requestedOrigin) + return corecharm.Origin{}, nil, errors.Annotatef(err, "storing charm %q from origin %v", charmURL, requestedOrigin) } - return actualOrigin, nil + return actualOrigin, downloadedCharm.Charm, nil } func (d *Downloader) downloadAndHash(ctx context.Context, charmName string, requestedOrigin corecharm.Origin, repo CharmRepository, dstPath string) (DownloadedCharm, corecharm.Origin, error) { diff --git a/internal/charm/downloader/downloader_test.go b/internal/charm/downloader/downloader_test.go index 144579f9ceb..b0b27ee00b0 100644 --- a/internal/charm/downloader/downloader_test.go +++ b/internal/charm/downloader/downloader_test.go @@ -160,9 +160,10 @@ func (s downloaderSuite) TestCharmAlreadyStored(c *gc.C) { s.repo.EXPECT().GetDownloadURL(gomock.Any(), curl.Name, requestedOrigin).Return(retURL, knownOrigin, nil) dl := s.newDownloader(c) - gotOrigin, err := dl.DownloadAndStore(context.Background(), curl, requestedOrigin, false) + gotOrigin, ch, err := dl.DownloadAndStore(context.Background(), curl, requestedOrigin, false) c.Assert(gotOrigin, gc.DeepEquals, knownOrigin, gc.Commentf("expected to get back the known origin for the existing charm")) c.Assert(err, jc.ErrorIsNil) + c.Assert(ch, gc.IsNil) } func (s downloaderSuite) TestPrepareToStoreCharmError(c *gc.C) { @@ -176,7 +177,7 @@ func (s downloaderSuite) TestPrepareToStoreCharmError(c *gc.C) { ) dl := s.newDownloader(c) - gotOrigin, err := dl.DownloadAndStore(context.Background(), curl, requestedOrigin, false) + gotOrigin, _, err := dl.DownloadAndStore(context.Background(), curl, requestedOrigin, false) c.Assert(gotOrigin, gc.DeepEquals, corecharm.Origin{}, gc.Commentf("expected a blank origin when encountering errors")) c.Assert(err, gc.ErrorMatches, "something went wrong") } @@ -251,9 +252,10 @@ func (s downloaderSuite) TestDownloadAndStore(c *gc.C) { s.charmArchive.EXPECT().LXDProfile().Return(nil) dl := s.newDownloader(c) - gotOrigin, err := dl.DownloadAndStore(context.Background(), curl, requestedOrigin, false) + gotOrigin, ch, err := dl.DownloadAndStore(context.Background(), curl, requestedOrigin, false) c.Assert(gotOrigin, gc.DeepEquals, resolvedOrigin, gc.Commentf("expected to get back the resolved origin")) c.Assert(err, jc.ErrorIsNil) + c.Assert(ch, gc.Equals, s.charmArchive) } func (s *downloaderSuite) setupMocks(c *gc.C) *gomock.Controller { diff --git a/internal/testing/factory/factory.go b/internal/testing/factory/factory.go index a58e0ddc209..f0259bb3a3c 100644 --- a/internal/testing/factory/factory.go +++ b/internal/testing/factory/factory.go @@ -100,6 +100,7 @@ type MachineParams struct { type ApplicationParams struct { Name string Charm *state.Charm + CharmURL string CharmOrigin *state.CharmOrigin Status *status.StatusInfo ApplicationConfig map[string]interface{} @@ -424,6 +425,9 @@ func (factory *Factory) MakeApplicationReturningPassword(c *gc.C, params *Applic Channel: "12.10", }} } + if params.CharmURL == "" { + params.CharmURL = params.Charm.URL() + } objectStore := NewObjectStore(c, factory.st.ModelUUID(), @@ -448,6 +452,7 @@ func (factory *Factory) MakeApplicationReturningPassword(c *gc.C, params *Applic state.AddApplicationArgs{ Name: params.Name, Charm: params.Charm, + CharmURL: params.CharmURL, CharmOrigin: params.CharmOrigin, CharmConfig: params.CharmConfig, ApplicationConfig: appConfig, diff --git a/state/state.go b/state/state.go index 0b1e024886a..495a968f168 100644 --- a/state/state.go +++ b/state/state.go @@ -895,7 +895,6 @@ func (st *State) CloudService(id string) (*CloudService, error) { type CharmRef interface { Meta() *charm.Meta Manifest() *charm.Manifest - URL() string } // CharmRefFull is actually almost a full charm with addition information. This @@ -908,12 +907,14 @@ type CharmRefFull interface { Actions() *charm.Actions Config() *charm.Config Revision() int + URL() string } // AddApplicationArgs defines the arguments for AddApplication method. type AddApplicationArgs struct { Name string Charm CharmRef + CharmURL string CharmOrigin *CharmOrigin Storage map[string]StorageConstraints Devices map[string]DeviceConstraints @@ -940,9 +941,6 @@ func (st *State) AddApplication( if !names.IsValidApplication(args.Name) { return nil, errors.Errorf("invalid name") } - if args.Charm == nil { - return nil, errors.Errorf("charm is nil") - } if args.CharmOrigin == nil { return nil, errors.Errorf("charm origin is nil") } @@ -1080,7 +1078,7 @@ func (st *State) AddApplication( // The doc defaults to CharmModifiedVersion = 0, which is correct, since it // has, by definition, at its initial state. - cURL := args.Charm.URL() + cURL := args.CharmURL appDoc := &applicationDoc{ DocID: applicationID, Name: args.Name,