diff --git a/apiserver/facades/client/application/deployrepository.go b/apiserver/facades/client/application/deployrepository.go index 3956f17f6cd..3a0b8593cb5 100644 --- a/apiserver/facades/client/application/deployrepository.go +++ b/apiserver/facades/client/application/deployrepository.go @@ -9,7 +9,6 @@ import ( "strconv" "sync" - jujuclock "github.com/juju/clock" "github.com/juju/collections/set" "github.com/juju/errors" "github.com/juju/names/v5" @@ -842,17 +841,13 @@ func (v *deployFromRepositoryValidator) resolveCharm(ctx context.Context, curl * if err != nil { return corecharm.ResolvedDataForDeploy{}, errors.Trace(err) } - workloadBases, err := corebase.WorkloadBases(jujuclock.WallClock.Now(), requestedBase, modelCfg.ImageStream()) - if err != nil { - return corecharm.ResolvedDataForDeploy{}, errors.Trace(err) - } bsCfg := corecharm.SelectorConfig{ Config: modelCfg, Force: force, Logger: v.logger, RequestedBase: requestedBase, SupportedCharmBases: supportedBases, - WorkloadBases: workloadBases, + WorkloadBases: corebase.WorkloadBases(), UsingImageID: cons.HasImageID() || modelCons.HasImageID(), } selector, err := corecharm.ConfigureBaseSelector(bsCfg) diff --git a/apiserver/facades/client/machinemanager/machinemanager_test.go b/apiserver/facades/client/machinemanager/machinemanager_test.go index 00d563ba58f..1e402642158 100644 --- a/apiserver/facades/client/machinemanager/machinemanager_test.go +++ b/apiserver/facades/client/machinemanager/machinemanager_test.go @@ -1648,9 +1648,7 @@ type IsBaseLessThanMachineManagerSuite struct{} // but complex enough to warrant being exported from an export test package for // testing. func (s *IsBaseLessThanMachineManagerSuite) TestIsBaseLessThan(c *gc.C) { - workloadVersions, err := corebase.AllWorkloadVersions() - c.Assert(err, jc.ErrorIsNil) - vers := workloadVersions.Values() + vers := transform.Slice(corebase.WorkloadBases(), func(b corebase.Base) string { return b.Channel.Track }) s.assertSeriesLessThan(c, "ubuntu", vers) } diff --git a/apiserver/facades/client/modelupgrader/upgrader_test.go b/apiserver/facades/client/modelupgrader/upgrader_test.go index 8a0b3a97c59..f3c3ae3eca4 100644 --- a/apiserver/facades/client/modelupgrader/upgrader_test.go +++ b/apiserver/facades/client/modelupgrader/upgrader_test.go @@ -5,7 +5,6 @@ package modelupgrader_test import ( stdcontext "context" - "time" "github.com/juju/collections/transform" "github.com/juju/errors" @@ -189,8 +188,8 @@ func (s *modelUpgradeSuite) assertUpgradeModelForControllerModelJuju3(c *gc.C, d }, ) - s.PatchValue(&upgradevalidation.SupportedJujuBases, func(time.Time, base.Base, string) ([]base.Base, error) { - return transform.SliceOrErr([]string{"ubuntu@24.04", "ubuntu@22.04", "ubuntu@20.04"}, base.ParseBaseFromString) + s.PatchValue(&upgradevalidation.SupportedJujuBases, func() []base.Base { + return transform.Slice([]string{"ubuntu@24.04", "ubuntu@22.04", "ubuntu@20.04"}, base.MustParseBaseFromString) }) ctrlModelTag := coretesting.ModelTag @@ -318,8 +317,8 @@ func (s *modelUpgradeSuite) TestUpgradeModelForControllerDyingHostedModelJuju3(c }, ) - s.PatchValue(&upgradevalidation.SupportedJujuBases, func(time.Time, base.Base, string) ([]base.Base, error) { - return transform.SliceOrErr([]string{"ubuntu@24.04", "ubuntu@22.04", "ubuntu@20.04"}, base.ParseBaseFromString) + s.PatchValue(&upgradevalidation.SupportedJujuBases, func() []base.Base { + return transform.Slice([]string{"ubuntu@24.04", "ubuntu@22.04", "ubuntu@20.04"}, base.MustParseBaseFromString) }) ctrlModelTag := coretesting.ModelTag @@ -427,8 +426,8 @@ func (s *modelUpgradeSuite) TestUpgradeModelForControllerModelJuju3Failed(c *gc. }, ) - s.PatchValue(&upgradevalidation.SupportedJujuBases, func(time.Time, base.Base, string) ([]base.Base, error) { - return transform.SliceOrErr([]string{"ubuntu@24.04", "ubuntu@22.04", "ubuntu@20.04"}, base.ParseBaseFromString) + s.PatchValue(&upgradevalidation.SupportedJujuBases, func() []base.Base { + return transform.Slice([]string{"ubuntu@24.04", "ubuntu@22.04", "ubuntu@20.04"}, base.MustParseBaseFromString) }) ctrlModelTag := coretesting.ModelTag @@ -553,6 +552,14 @@ func (s *modelUpgradeSuite) assertUpgradeModelJuju3(c *gc.C, ctrlModelVers strin }, ) + s.PatchValue(&upgradevalidation.SupportedJujuBases, func() []base.Base { + return []base.Base{ + base.MustParseBaseFromString("ubuntu@24.04"), + base.MustParseBaseFromString("ubuntu@22.04"), + base.MustParseBaseFromString("ubuntu@20.04"), + } + }) + modelUUID := coretesting.ModelTag.Id() model := mocks.NewMockModel(ctrl) st := mocks.NewMockState(ctrl) @@ -588,7 +595,7 @@ func (s *modelUpgradeSuite) assertUpgradeModelJuju3(c *gc.C, ctrlModelVers strin // - check no upgrade series in process. st.EXPECT().HasUpgradeSeriesLocks().Return(false, nil) // - check if the model has deprecated ubuntu machines; - st.EXPECT().MachineCountForBase(makeBases("ubuntu", []string{"20.04/stable", "22.04/stable", "24.04/stable"})).Return(nil, nil) + st.EXPECT().MachineCountForBase(makeBases("ubuntu", []string{"24.04/stable", "22.04/stable", "20.04/stable"})).Return(nil, nil) st.EXPECT().AllMachinesCount().Return(0, nil) // - check LXD version. serverFactory.EXPECT().RemoteServer(s.cloudSpec).Return(server, nil) @@ -639,8 +646,8 @@ func (s *modelUpgradeSuite) TestUpgradeModelJuju3Failed(c *gc.C) { }, ) - s.PatchValue(&upgradevalidation.SupportedJujuBases, func(time.Time, base.Base, string) ([]base.Base, error) { - return transform.SliceOrErr([]string{"ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04"}, base.ParseBaseFromString) + s.PatchValue(&upgradevalidation.SupportedJujuBases, func() []base.Base { + return transform.Slice([]string{"ubuntu@24.04", "ubuntu@22.04", "ubuntu@20.04"}, base.MustParseBaseFromString) }) modelUUID := coretesting.ModelTag.Id() @@ -676,7 +683,7 @@ func (s *modelUpgradeSuite) TestUpgradeModelJuju3Failed(c *gc.C) { st.EXPECT().HasUpgradeSeriesLocks().Return(true, nil) // - check if the model has deprecated ubuntu machines; - st.EXPECT().MachineCountForBase(makeBases("ubuntu", []string{"20.04/stable", "22.04/stable", "24.04/stable"})).Return(map[string]int{ + st.EXPECT().MachineCountForBase(makeBases("ubuntu", []string{"24.04/stable", "22.04/stable", "20.04/stable"})).Return(map[string]int{ "ubuntu@20.04": 1, "ubuntu@22.04": 2, "ubuntu@24.04": 3, }, nil) st.EXPECT().AllMachinesCount().Return(7, nil) @@ -700,7 +707,7 @@ func (s *modelUpgradeSuite) TestUpgradeModelJuju3Failed(c *gc.C) { cannot upgrade to "3.9.99" due to issues with these models: "admin/model-1": - unexpected upgrade series lock found -- the model hosts 1 ubuntu machine(s) with an unsupported base. The supported bases are: ubuntu@20.04, ubuntu@22.04, ubuntu@24.04 +- the model hosts 1 ubuntu machine(s) with an unsupported base. The supported bases are: ubuntu@24.04, ubuntu@22.04, ubuntu@20.04 - LXD version has to be at least "5.0.0", but current version is only "4.0.0"`[1:]) } diff --git a/cmd/juju/application/deploy_test.go b/cmd/juju/application/deploy_test.go index c21a2f8e0db..705672118e0 100644 --- a/cmd/juju/application/deploy_test.go +++ b/cmd/juju/application/deploy_test.go @@ -12,7 +12,6 @@ import ( "regexp" "sort" "strings" - "time" "github.com/juju/cmd/v4" "github.com/juju/cmd/v4/cmdtesting" @@ -235,8 +234,8 @@ func (s *DeploySuite) TestDeployFromPathDefaultBase(c *gc.C) { func (s *DeploySuite) TestDeployFromPathUnsupportedSeriesForce(c *gc.C) { // Do not remove this because we want to test: bases supported by the charm and bases supported by Juju have overlap. - s.PatchValue(&deployer.SupportedJujuBases, func(time.Time, corebase.Base, string) ([]corebase.Base, error) { - return transform.SliceOrErr([]string{"ubuntu@22.04", "ubuntu@20.04", "ubuntu@12.10"}, corebase.ParseBaseFromString) + s.PatchValue(&deployer.SupportedJujuBases, func() []corebase.Base { + return transform.Slice([]string{"ubuntu@22.04", "ubuntu@20.04", "ubuntu@12.10"}, corebase.MustParseBaseFromString) }) charmDir := testcharms.RepoWithSeries("bionic").ClonedDir(c.MkDir(), "multi-series") curl := charm.MustParseURL("local:multi-series-1") @@ -249,8 +248,8 @@ func (s *DeploySuite) TestDeployFromPathUnsupportedSeriesForce(c *gc.C) { func (s *DeploySuite) TestDeployFromPathUnsupportedSeriesHaveOverlap(c *gc.C) { // Do not remove this because we want to test: bases supported by the charm and bases supported by Juju have overlap. - s.PatchValue(&deployer.SupportedJujuBases, func(time.Time, corebase.Base, string) ([]corebase.Base, error) { - return transform.SliceOrErr([]string{"ubuntu@22.04", "ubuntu@20.04", "ubuntu@12.10"}, corebase.ParseBaseFromString) + s.PatchValue(&deployer.SupportedJujuBases, func() []corebase.Base { + return transform.Slice([]string{"ubuntu@22.04", "ubuntu@20.04", "ubuntu@12.10"}, corebase.MustParseBaseFromString) }) path := testcharms.RepoWithSeries("bionic").ClonedDirPath(c.MkDir(), "multi-series") @@ -261,8 +260,8 @@ func (s *DeploySuite) TestDeployFromPathUnsupportedSeriesHaveOverlap(c *gc.C) { func (s *DeploySuite) TestDeployFromPathUnsupportedBaseHaveNoOverlap(c *gc.C) { // Do not remove this because we want to test: bases supported by the charm and bases supported by Juju have NO overlap. s.PatchValue(&deployer.SupportedJujuBases, - func(time.Time, corebase.Base, string) ([]corebase.Base, error) { - return []corebase.Base{corebase.MustParseBaseFromString("ubuntu@22.10")}, nil + func() []corebase.Base { + return []corebase.Base{corebase.MustParseBaseFromString("ubuntu@22.10")} }, ) @@ -273,8 +272,8 @@ func (s *DeploySuite) TestDeployFromPathUnsupportedBaseHaveNoOverlap(c *gc.C) { func (s *DeploySuite) TestDeployFromPathUnsupportedLXDProfileForce(c *gc.C) { // TODO remove this patch once we removed all the old bases from tests in current package. - s.PatchValue(&deployer.SupportedJujuBases, func(time.Time, corebase.Base, string) ([]corebase.Base, error) { - return transform.SliceOrErr([]string{"ubuntu@22.04", "ubuntu@20.04", "ubuntu@18.04", "ubuntu@12.10"}, corebase.ParseBaseFromString) + s.PatchValue(&deployer.SupportedJujuBases, func() []corebase.Base { + return transform.Slice([]string{"ubuntu@22.04", "ubuntu@20.04", "ubuntu@18.04", "ubuntu@12.10"}, corebase.MustParseBaseFromString) }) charmDir := testcharms.RepoWithSeries("quantal").ClonedDir(c.MkDir(), "lxd-profile-fail") diff --git a/cmd/juju/application/deployer/bundlehandler.go b/cmd/juju/application/deployer/bundlehandler.go index f1d6f93c2eb..3072e7d26dd 100644 --- a/cmd/juju/application/deployer/bundlehandler.go +++ b/cmd/juju/application/deployer/bundlehandler.go @@ -648,17 +648,13 @@ func (h *bundleHandler) addCharm(change *bundlechanges.AddCharmChange) error { if resolvedOrigin.Type == "bundle" { return errors.Errorf("expected charm, got bundle %q %v", ch.Name, resolvedOrigin) } - workloadBases, err := SupportedJujuBases(jujuclock.WallClock.Now(), base, h.modelConfig.ImageStream()) - if err != nil { - return errors.Trace(err) - } selector, err := corecharm.ConfigureBaseSelector(corecharm.SelectorConfig{ Config: h.modelConfig, Force: h.force, Logger: logger, RequestedBase: base, SupportedCharmBases: supportedBases, - WorkloadBases: workloadBases, + WorkloadBases: SupportedJujuBases(), }) if err != nil { return errors.Trace(err) @@ -980,17 +976,13 @@ func (h *bundleHandler) selectedBase(ch charm.CharmMeta, chBase corebase.Base) ( if err != nil { return corebase.Base{}, errors.Trace(err) } - workloadBases, err := SupportedJujuBases(jujuclock.WallClock.Now(), chBase, h.modelConfig.ImageStream()) - if err != nil { - return corebase.Base{}, errors.Trace(err) - } selector, err := corecharm.ConfigureBaseSelector(corecharm.SelectorConfig{ Config: h.modelConfig, Force: h.force, Logger: logger, RequestedBase: chBase, SupportedCharmBases: supportedBases, - WorkloadBases: workloadBases, + WorkloadBases: SupportedJujuBases(), }) if err != nil { return corebase.Base{}, errors.Trace(err) diff --git a/cmd/juju/application/deployer/bundlehandler_test.go b/cmd/juju/application/deployer/bundlehandler_test.go index 3a33d27352a..76e8bb5ddec 100644 --- a/cmd/juju/application/deployer/bundlehandler_test.go +++ b/cmd/juju/application/deployer/bundlehandler_test.go @@ -8,7 +8,6 @@ import ( "context" "fmt" "strings" - "time" "github.com/juju/cmd/v4" "github.com/juju/collections/set" @@ -64,8 +63,8 @@ func (s *BundleDeployRepositorySuite) SetUpTest(_ *gc.C) { s.deployArgs = make(map[string]application.DeployArgs) s.output = bytes.NewBuffer([]byte{}) - s.PatchValue(&SupportedJujuBases, func(time.Time, corebase.Base, string) ([]corebase.Base, error) { - return transform.SliceOrErr([]string{"ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04"}, corebase.ParseBaseFromString) + s.PatchValue(&SupportedJujuBases, func() []corebase.Base { + return transform.Slice([]string{"ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04"}, corebase.MustParseBaseFromString) }) } diff --git a/cmd/juju/application/deployer/deployer.go b/cmd/juju/application/deployer/deployer.go index 5e13b08e208..bc3d66edd6a 100644 --- a/cmd/juju/application/deployer/deployer.go +++ b/cmd/juju/application/deployer/deployer.go @@ -280,7 +280,6 @@ func (d *factory) localPreDeployedCharmDeployer(getter ModelConfigGetter) (Deplo func (d *factory) determineBaseForLocalCharm(ch charm.Charm, getter ModelConfigGetter) (corebase.Base, string, error) { var ( - imageStream string selectedBase corebase.Base ) modelCfg, err := getModelConfig(getter) @@ -288,12 +287,6 @@ func (d *factory) determineBaseForLocalCharm(ch charm.Charm, getter ModelConfigG return corebase.Base{}, "", errors.Trace(err) } - imageStream = modelCfg.ImageStream() - workloadBases, err := SupportedJujuBases(d.clock.Now(), d.base, imageStream) - if err != nil { - return corebase.Base{}, "", errors.Trace(err) - } - supportedBases, err := corecharm.ComputedBases(ch) if err != nil { return corebase.Base{}, "", errors.Trace(err) @@ -304,7 +297,7 @@ func (d *factory) determineBaseForLocalCharm(ch charm.Charm, getter ModelConfigG Logger: logger, RequestedBase: d.base, SupportedCharmBases: supportedBases, - WorkloadBases: workloadBases, + WorkloadBases: SupportedJujuBases(), UsingImageID: d.constraints.HasImageID() || d.modelConstraints.HasImageID(), }) if err != nil { @@ -315,7 +308,7 @@ func (d *factory) determineBaseForLocalCharm(ch charm.Charm, getter ModelConfigG if err = charmValidationError(ch.Meta().Name, errors.Trace(err)); err != nil { return corebase.Base{}, "", errors.Trace(err) } - return selectedBase, imageStream, nil + return selectedBase, modelCfg.ImageStream(), nil } func (d *factory) checkHandleRevision(userCharmURL *charm.URL, charmHubSchemaCheck bool) (int, error) { @@ -666,12 +659,7 @@ func (d *factory) validateCharmBase(base corebase.Base, imageStream string) erro } // attempt to locate the charm base from the list of known juju bases // that we currently support. - workloadBases, err := SupportedJujuBases(d.clock.Now(), base, imageStream) - if err != nil { - return errors.Trace(err) - } - - for _, workloadBase := range workloadBases { + for _, workloadBase := range SupportedJujuBases() { if workloadBase == base { return nil } diff --git a/cmd/juju/commands/bootstrap.go b/cmd/juju/commands/bootstrap.go index 24ad01f8d40..957cc2d1127 100644 --- a/cmd/juju/commands/bootstrap.go +++ b/cmd/juju/commands/bootstrap.go @@ -524,8 +524,6 @@ var getBootstrapFuncs = func() BootstrapInterface { return &bootstrapFuncs{} } -var supportedJujuBases = corebase.ControllerBases - var ( bootstrapPrepareController = bootstrap.PrepareController environsDestroy = environs.Destroy @@ -771,18 +769,6 @@ func (c *bootstrapCommand) Run(ctx *cmd.Context) (resultErr error) { } } - // Get the supported bootstrap series. - var imageStream string - if cfg, ok := bootstrapCfg.bootstrapModel["image-stream"]; ok { - imageStream = cfg.(string) - } - now := c.clock.Now() - supportedBootstrapBases, err := supportedJujuBases(now, bootstrapBase, imageStream) - if err != nil { - return errors.Annotate(err, "error reading supported bootstrap series") - } - logger.Tracef("supported bootstrap bases %v", supportedBootstrapBases) - bootstrapCfg.controller[controller.ControllerName] = c.controllerName // Handle Ctrl-C during bootstrap by asking the bootstrap process to stop @@ -889,6 +875,9 @@ to create a new model to deploy %sworkloads. } } + supportedBootstrapBases := corebase.ControllerBases() + logger.Tracef("supported bootstrap bases %v", supportedBootstrapBases) + bootstrapParams := bootstrap.BootstrapParams{ ControllerName: c.controllerName, BootstrapBase: bootstrapBase, diff --git a/cmd/juju/commands/bootstrap_test.go b/cmd/juju/commands/bootstrap_test.go index b1d282ff5e8..30f44b80c56 100644 --- a/cmd/juju/commands/bootstrap_test.go +++ b/cmd/juju/commands/bootstrap_test.go @@ -21,8 +21,6 @@ import ( "github.com/juju/cmd/v4/cmdtesting" "github.com/juju/errors" "github.com/juju/loggo/v2" - jujuos "github.com/juju/os/v2" - osseries "github.com/juju/os/v2/series" "github.com/juju/testing" jc "github.com/juju/testing/checkers" "github.com/juju/utils/v4" @@ -118,12 +116,6 @@ func init() { func (s *BootstrapSuite) SetUpSuite(c *gc.C) { s.FakeJujuXDGDataHomeSuite.SetUpSuite(c) s.PatchValue(&keys.JujuPublicKey, sstesting.SignedMetadataPublicKey) - s.PatchValue( - &corebase.LocalSeriesVersionInfo, - func() (jujuos.OSType, map[string]osseries.SeriesVersionInfo, error) { - return jujuos.Ubuntu, nil, nil - }, - ) } func (s *BootstrapSuite) SetUpTest(c *gc.C) { @@ -136,7 +128,6 @@ func (s *BootstrapSuite) SetUpTest(c *gc.C) { s.PatchValue(&jujuversion.Current, v100u64.Number) s.PatchValue(&arch.HostArch, func() string { return v100u64.Arch }) s.PatchValue(&coreos.HostOS, func() ostype.OSType { return ostype.Ubuntu }) - s.PatchValue(&corebase.UbuntuDistroInfo, "/path/notexists") // Ensure KUBECONFIG doesn't interfere with tests. s.PatchEnvironment(k8scmd.RecommendedConfigPathEnvVar, filepath.Join(c.MkDir(), "config")) diff --git a/cmd/jujud-controller/agent/bootstrap_test.go b/cmd/jujud-controller/agent/bootstrap_test.go index 13f68b54062..781e53307c5 100644 --- a/cmd/jujud-controller/agent/bootstrap_test.go +++ b/cmd/jujud-controller/agent/bootstrap_test.go @@ -29,7 +29,6 @@ import ( "github.com/juju/juju/cloud" "github.com/juju/juju/cmd/jujud-controller/agent/agenttest" "github.com/juju/juju/controller" - corebase "github.com/juju/juju/core/base" "github.com/juju/juju/core/constraints" "github.com/juju/juju/core/instance" corelogger "github.com/juju/juju/core/logger" @@ -108,7 +107,6 @@ func (s *BootstrapSuite) SetUpTest(c *gc.C) { s.PatchValue(&sshGenerateKey, func(name string) (string, string, error) { return "private-key", "public-key", nil }) - s.PatchValue(&corebase.UbuntuDistroInfo, "/path/notexists") s.MgoSuite.SetUpTest(c) s.dataDir = c.MkDir() diff --git a/core/base/distrosource_mock_test.go b/core/base/distrosource_mock_test.go deleted file mode 100644 index 39fc67d0a4e..00000000000 --- a/core/base/distrosource_mock_test.go +++ /dev/null @@ -1,117 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/juju/juju/core/base (interfaces: DistroSource) -// -// Generated by this command: -// -// mockgen -typed -package base -destination distrosource_mock_test.go github.com/juju/juju/core/base DistroSource -// - -// Package base is a generated GoMock package. -package base - -import ( - reflect "reflect" - - series "github.com/juju/os/v2/series" - gomock "go.uber.org/mock/gomock" -) - -// MockDistroSource is a mock of DistroSource interface. -type MockDistroSource struct { - ctrl *gomock.Controller - recorder *MockDistroSourceMockRecorder -} - -// MockDistroSourceMockRecorder is the mock recorder for MockDistroSource. -type MockDistroSourceMockRecorder struct { - mock *MockDistroSource -} - -// NewMockDistroSource creates a new mock instance. -func NewMockDistroSource(ctrl *gomock.Controller) *MockDistroSource { - mock := &MockDistroSource{ctrl: ctrl} - mock.recorder = &MockDistroSourceMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockDistroSource) EXPECT() *MockDistroSourceMockRecorder { - return m.recorder -} - -// Refresh mocks base method. -func (m *MockDistroSource) Refresh() error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Refresh") - ret0, _ := ret[0].(error) - return ret0 -} - -// Refresh indicates an expected call of Refresh. -func (mr *MockDistroSourceMockRecorder) Refresh() *MockDistroSourceRefreshCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Refresh", reflect.TypeOf((*MockDistroSource)(nil).Refresh)) - return &MockDistroSourceRefreshCall{Call: call} -} - -// MockDistroSourceRefreshCall wrap *gomock.Call -type MockDistroSourceRefreshCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockDistroSourceRefreshCall) Return(arg0 error) *MockDistroSourceRefreshCall { - c.Call = c.Call.Return(arg0) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockDistroSourceRefreshCall) Do(f func() error) *MockDistroSourceRefreshCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockDistroSourceRefreshCall) DoAndReturn(f func() error) *MockDistroSourceRefreshCall { - c.Call = c.Call.DoAndReturn(f) - return c -} - -// SeriesInfo mocks base method. -func (m *MockDistroSource) SeriesInfo(arg0 string) (series.DistroInfoSerie, bool) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SeriesInfo", arg0) - ret0, _ := ret[0].(series.DistroInfoSerie) - ret1, _ := ret[1].(bool) - return ret0, ret1 -} - -// SeriesInfo indicates an expected call of SeriesInfo. -func (mr *MockDistroSourceMockRecorder) SeriesInfo(arg0 any) *MockDistroSourceSeriesInfoCall { - mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SeriesInfo", reflect.TypeOf((*MockDistroSource)(nil).SeriesInfo), arg0) - return &MockDistroSourceSeriesInfoCall{Call: call} -} - -// MockDistroSourceSeriesInfoCall wrap *gomock.Call -type MockDistroSourceSeriesInfoCall struct { - *gomock.Call -} - -// Return rewrite *gomock.Call.Return -func (c *MockDistroSourceSeriesInfoCall) Return(arg0 series.DistroInfoSerie, arg1 bool) *MockDistroSourceSeriesInfoCall { - c.Call = c.Call.Return(arg0, arg1) - return c -} - -// Do rewrite *gomock.Call.Do -func (c *MockDistroSourceSeriesInfoCall) Do(f func(string) (series.DistroInfoSerie, bool)) *MockDistroSourceSeriesInfoCall { - c.Call = c.Call.Do(f) - return c -} - -// DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockDistroSourceSeriesInfoCall) DoAndReturn(f func(string) (series.DistroInfoSerie, bool)) *MockDistroSourceSeriesInfoCall { - c.Call = c.Call.DoAndReturn(f) - return c -} diff --git a/core/base/package_test.go b/core/base/package_test.go index f45d4ec2b36..bdbe0f7ae66 100644 --- a/core/base/package_test.go +++ b/core/base/package_test.go @@ -12,8 +12,6 @@ import ( coretesting "github.com/juju/juju/testing" ) -//go:generate go run go.uber.org/mock/mockgen -typed -package base -destination distrosource_mock_test.go github.com/juju/juju/core/base DistroSource - func TestPackage(t *testing.T) { gc.TestingT(t) } diff --git a/core/base/series.go b/core/base/series.go index b4cebc15908..4d9e5c9119f 100644 --- a/core/base/series.go +++ b/core/base/series.go @@ -4,22 +4,53 @@ package base import ( - "strings" - "github.com/juju/errors" ) +// seriesBaseMapping is a hard-coded set of pairs +// of equivalent series and bases. We use this to +// convert a base into it's equivalent series +var seriesBaseMapping = []struct { + base Base + series string +}{{ + base: MakeDefaultBase(UbuntuOS, "20.04"), + series: "focal", +}, { + base: MakeDefaultBase(UbuntuOS, "20.10"), + series: "groovy", +}, { + base: MakeDefaultBase(UbuntuOS, "21.04"), + series: "hirsute", +}, { + base: MakeDefaultBase(UbuntuOS, "21.10"), + series: "impish", +}, { + base: MakeDefaultBase(UbuntuOS, "22.04"), + series: "jammy", +}, { + base: MakeDefaultBase(UbuntuOS, "22.10"), + series: "kinetic", +}, { + base: MakeDefaultBase(UbuntuOS, "23.04"), + series: "lunar", +}, { + base: MakeDefaultBase(UbuntuOS, "23.10"), + series: "mantic", +}, { + base: MakeDefaultBase(UbuntuOS, "24.04"), + series: "noble", +}, { + base: MakeDefaultBase(UbuntuOS, "24.10"), + series: "oracular", +}} + // GetSeriesFromBase returns the series name for a // given Base. This is needed to support legacy series. func GetSeriesFromBase(v Base) (string, error) { - var osSeries map[SeriesName]seriesVersion - switch strings.ToLower(v.OS) { - case UbuntuOS: - osSeries = ubuntuSeries - } - for s, vers := range osSeries { - if vers.Version == v.Channel.Track { - return string(s), nil + for _, pair := range seriesBaseMapping { + if v.IsCompatible(pair.base) { + return pair.series, nil } } return "", errors.NotFoundf("os %q version %q", v.OS, v.Channel.Track) diff --git a/core/base/series_test.go b/core/base/series_test.go index d0b192d88b0..d22148afd71 100644 --- a/core/base/series_test.go +++ b/core/base/series_test.go @@ -1,12 +1,14 @@ // Copyright 2024 Canonical Ltd. // Licensed under the AGPLv3, see LICENCE file for details. -package base +package base_test import ( "github.com/juju/testing" jc "github.com/juju/testing/checkers" gc "gopkg.in/check.v1" + + "github.com/juju/juju/core/base" ) type SeriesSuite struct { @@ -14,7 +16,7 @@ type SeriesSuite struct { } func (s *SeriesSuite) TestGetSeriesFromBase(c *gc.C) { - series, err := GetSeriesFromBase(MakeDefaultBase("ubuntu", "22.04")) + series, err := base.GetSeriesFromBase(base.MakeDefaultBase("ubuntu", "22.04")) c.Assert(err, jc.ErrorIsNil) c.Assert(series, gc.Equals, "jammy") } diff --git a/core/base/supported.go b/core/base/supported.go deleted file mode 100644 index f1bfb50ce1f..00000000000 --- a/core/base/supported.go +++ /dev/null @@ -1,389 +0,0 @@ -// Copyright 2020 Canonical Ltd. -// Licensed under the AGPLv3, see LICENCE file for details. - -package base - -import ( - "sort" - "sync" - "time" - - "github.com/juju/errors" - "github.com/juju/os/v2/series" -) - -// DistroSource is the source of the underlying distro source for supported -// series. -type DistroSource interface { - // Refresh will attempt to update the information it has about each distro - // and if the distro is supported or not. - Refresh() error - - // SeriesInfo returns the DistroInfoSerie for the series name. - SeriesInfo(seriesName string) (series.DistroInfoSerie, bool) -} - -// supportedInfo represents all the supported info available. -type supportedInfo struct { - mutex sync.RWMutex - - source DistroSource - values map[SeriesName]seriesVersion -} - -// newSupportedInfo creates a supported info type for knowing if a series is -// supported or not. -func newSupportedInfo(source DistroSource, preset map[SeriesName]seriesVersion) *supportedInfo { - return &supportedInfo{ - source: source, - values: preset, - } -} - -// compile compiles a list of supported info. -func (s *supportedInfo) compile(now time.Time) error { - if err := s.source.Refresh(); err != nil { - return errors.Trace(err) - } - - s.mutex.Lock() - defer s.mutex.Unlock() - - // First thing here, is walk over the controller, workload maps to work out - // if something was previously supported and is no longer or the reverse. - for seriesName, version := range s.values { - distroInfo, ok := s.source.SeriesInfo(seriesName.String()) - if !ok { - // The series isn't found in the distro info, we should continue - // onward as we don't know what to do here. - continue - } - - current := version.Supported - supported := current - - // To prevent the distro info from overriding the supported flag and to - // ensure that we keep the same Supported version as we have set as the - // default (see below). Using the IgnoreDistroInfoUpdate flag states that - // we want to keep the current value. - // Example: adding a new LTS and setting it to be supported will become - // false when reading in the distro information. Setting OverrideSupport - // to true, will force it to be the same value as the default. - if !version.IgnoreDistroInfoUpdate { - if current { - // We only want to update the previously supported to possibly deprecated. - // But we do not want to update a Juju deprecated LTS to supported again. - supported = distroInfo.Supported(now) - } - } - - s.values[seriesName] = seriesVersion{ - WorkloadType: version.WorkloadType, - OS: version.OS, - Version: version.Version, - LTS: version.LTS, - Supported: supported, - ESMSupported: version.ESMSupported, - IgnoreDistroInfoUpdate: version.IgnoreDistroInfoUpdate, - UpdatedByLocalDistroInfo: current != supported, - } - } - - return nil -} - -// controllerBases returns a slice of bases that are supported to run on a -// controller. -func (s *supportedInfo) controllerBases() []Base { - var result []Base - for _, version := range s.values { - if version.WorkloadType != ControllerWorkloadType { - continue - } - if version.ESMSupported || version.Supported { - result = append(result, MakeDefaultBase(version.OS, version.Version)) - } - } - sort.Slice(result, func(i, j int) bool { - return result[i].String() < result[j].String() - }) - return result -} - -// workloadBases returns a slice of bases that are supported to run on a -// target workload (charm). -// Note: workload bases will also include controller workload types, as they -// can also be used for workloads. -func (s *supportedInfo) workloadBases(includeUnsupported bool) []Base { - var result []Base - for _, version := range s.values { - if version.WorkloadType == UnsupportedWorkloadType { - continue - } - if includeUnsupported || version.ESMSupported || version.Supported { - result = append(result, MakeDefaultBase(version.OS, version.Version)) - } - } - sort.Slice(result, func(i, j int) bool { - return result[i].String() < result[j].String() - }) - return result -} - -// workloadVersions returns a slice of versions that are supported to run on a -// target workload (charm). -// Note: workload bases will also include controller workload types, as they -// can also be used for workloads. -func (s *supportedInfo) workloadVersions(includeUnsupported bool) []string { - var result []string - for _, version := range s.values { - if version.WorkloadType == UnsupportedWorkloadType { - continue - } - if includeUnsupported || version.ESMSupported || version.Supported { - result = append(result, version.Version) - } - } - sort.Strings(result) - return result -} - -// WorkloadType defines what type of workload the series is aimed at. -// Controllers only support Ubuntu systems. -type WorkloadType int - -const ( - // ControllerWorkloadType defines a workload type that is for controllers - // only. - ControllerWorkloadType WorkloadType = iota - - // OtherWorkloadType workload type is for everything else. - // In the future we might want to differentiate this. - OtherWorkloadType - - // UnsupportedWorkloadType is used where the series does not support - // running Juju agents. - UnsupportedWorkloadType -) - -// seriesVersion represents a ubuntu series that includes the version, if the -// series is an LTS and the supported defines if Juju supports the series -// version. -type seriesVersion struct { - // WorkloadType defines what type the series version is intended to work - // against. - WorkloadType WorkloadType - - // OS represents the distro of the series - OS string - - // Version represents the version of the series. - Version string - - // LTS provides a lookup for a LTS series. Like seriesVersions, - // the values here are current at the time of writing. - LTS bool - - // Supported defines if Juju classifies the series as officially supported. - Supported bool - - // Extended security maintenance for customers, extends the supported bool - // for how Juju classifies the series. - ESMSupported bool - - // IgnoreDistroInfoUpdate overrides the supported value to ensure that we - // can force supported series, by ignoring the distro info update. - IgnoreDistroInfoUpdate bool - - // UpdatedByLocalDistroInfo indicates that the series version was created - // by the local distro-info information on the system. - // This is useful to understand why a version appears yet is not supported. - UpdatedByLocalDistroInfo bool -} - -// setSupported updates a series map based on the series name. -func setSupported(series map[SeriesName]seriesVersion, base Base) bool { - for name, version := range series { - if version.OS == base.OS && version.Version == base.Channel.Track { - version.Supported = true - version.IgnoreDistroInfoUpdate = true - series[name] = version - return true - } - } - return false -} - -// SeriesName represents a series name for distros -type SeriesName string - -func (s SeriesName) String() string { - return string(s) -} - -const ( - Precise SeriesName = "precise" - Quantal SeriesName = "quantal" - Raring SeriesName = "raring" - Saucy SeriesName = "saucy" - Trusty SeriesName = "trusty" - Utopic SeriesName = "utopic" - Vivid SeriesName = "vivid" - Wily SeriesName = "wily" - Xenial SeriesName = "xenial" - Yakkety SeriesName = "yakkety" - Zesty SeriesName = "zesty" - Artful SeriesName = "artful" - Bionic SeriesName = "bionic" - Cosmic SeriesName = "cosmic" - Disco SeriesName = "disco" - Eoan SeriesName = "eoan" - Focal SeriesName = "focal" - Groovy SeriesName = "groovy" - Hirsute SeriesName = "hirsute" - Impish SeriesName = "impish" - Jammy SeriesName = "jammy" - Kinetic SeriesName = "kinetic" - Lunar SeriesName = "lunar" - Mantic SeriesName = "mantic" - Noble SeriesName = "noble" -) - -var ubuntuSeries = map[SeriesName]seriesVersion{ - Precise: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "12.04", - }, - Quantal: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "12.10", - }, - Raring: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "13.04", - }, - Saucy: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "13.10", - }, - Trusty: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "14.04", - LTS: true, - }, - Utopic: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "14.10", - }, - Vivid: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "15.04", - }, - Wily: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "15.10", - }, - Xenial: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "16.04", - LTS: true, - }, - Yakkety: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "16.10", - }, - Zesty: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "17.04", - }, - Artful: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "17.10", - }, - Bionic: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "18.04", - LTS: true, - }, - Cosmic: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "18.10", - }, - Disco: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "19.04", - }, - Eoan: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "19.10", - }, - Focal: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "20.04", - LTS: true, - Supported: true, - ESMSupported: true, - }, - Groovy: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "20.10", - }, - Hirsute: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "21.04", - }, - Impish: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "21.10", - }, - Jammy: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "22.04", - LTS: true, - Supported: true, - ESMSupported: true, - }, - Kinetic: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "22.10", - }, - Lunar: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "23.04", - }, - Mantic: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "23.10", - }, - Noble: { - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: "24.04", - LTS: true, - ESMSupported: true, - }, -} diff --git a/core/base/supported_test.go b/core/base/supported_test.go deleted file mode 100644 index 453044dceaa..00000000000 --- a/core/base/supported_test.go +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright 2020 Canonical Ltd. -// Licensed under the AGPLv3, see LICENCE file for details. - -package base - -import ( - "github.com/juju/clock" - "github.com/juju/os/v2/series" - "github.com/juju/testing" - jc "github.com/juju/testing/checkers" - "go.uber.org/mock/gomock" - gc "gopkg.in/check.v1" -) - -type SupportedSuite struct { - testing.IsolationSuite -} - -var _ = gc.Suite(&SupportedSuite{}) - -func (s *SupportedSuite) TestCompileForControllers(c *gc.C) { - ctrl := gomock.NewController(c) - defer ctrl.Finish() - - now := clock.WallClock.Now() - - mockDistroSource := NewMockDistroSource(ctrl) - mockDistroSource.EXPECT().Refresh().Return(nil) - mockDistroSource.EXPECT().SeriesInfo("supported").Return(series.DistroInfoSerie{ - Released: now.AddDate(0, 0, -1), - EOL: now.AddDate(0, 0, 1), - }, true) - mockDistroSource.EXPECT().SeriesInfo("deprecated-lts").Return(series.DistroInfoSerie{ - Released: now.AddDate(0, 0, -1), - EOL: now.AddDate(0, 0, 1), - }, true) - mockDistroSource.EXPECT().SeriesInfo("not-updated").Return(series.DistroInfoSerie{ - Released: now.AddDate(0, 0, 1), - EOL: now.AddDate(0, 0, 2), - }, true) - mockDistroSource.EXPECT().SeriesInfo("ignored").Return(series.DistroInfoSerie{}, false) - - preset := map[SeriesName]seriesVersion{ - "supported": { - WorkloadType: ControllerWorkloadType, - OS: "foo", - Version: "1.1.1", - Supported: true, - }, - "deprecated-lts": { - WorkloadType: ControllerWorkloadType, - OS: "foo", - Version: "1.1.2", - Supported: false, - }, - "not-updated": { - WorkloadType: ControllerWorkloadType, - OS: "foo", - Version: "1.1.3", - Supported: false, - }, - "ignored": { - WorkloadType: ControllerWorkloadType, - OS: "foo", - Version: "1.1.4", - Supported: false, - }, - } - - info := newSupportedInfo(mockDistroSource, preset) - err := info.compile(now) - c.Assert(err, jc.ErrorIsNil) - - ctrlBases := info.controllerBases() - - c.Assert(ctrlBases, jc.DeepEquals, []Base{MustParseBaseFromString("foo@1.1.1")}) -} - -func (s *SupportedSuite) TestCompileForControllersWithOverride(c *gc.C) { - ctrl := gomock.NewController(c) - defer ctrl.Finish() - - now := clock.WallClock.Now() - - mockDistroSource := NewMockDistroSource(ctrl) - mockDistroSource.EXPECT().Refresh().Return(nil) - mockDistroSource.EXPECT().SeriesInfo("supported").Return(series.DistroInfoSerie{ - Released: now.AddDate(0, 0, 9), - EOL: now.AddDate(0, 0, 10), - }, true) - - preset := map[SeriesName]seriesVersion{ - "supported": { - WorkloadType: ControllerWorkloadType, - OS: "foo", - Version: "1.1.1", - Supported: true, - IgnoreDistroInfoUpdate: true, - }, - } - - info := newSupportedInfo(mockDistroSource, preset) - err := info.compile(now) - c.Assert(err, jc.ErrorIsNil) - - ctrlBases := info.controllerBases() - - c.Assert(ctrlBases, jc.DeepEquals, []Base{MustParseBaseFromString("foo@1.1.1")}) -} - -func (s *SupportedSuite) TestCompileForControllersNoUpdate(c *gc.C) { - ctrl := gomock.NewController(c) - defer ctrl.Finish() - - now := clock.WallClock.Now() - - mockDistroSource := NewMockDistroSource(ctrl) - mockDistroSource.EXPECT().Refresh().Return(nil) - mockDistroSource.EXPECT().SeriesInfo("supported").Return(series.DistroInfoSerie{ - Released: now.AddDate(0, 0, 9), - EOL: now.AddDate(0, 0, 10), - }, true) - - preset := map[SeriesName]seriesVersion{ - "supported": { - WorkloadType: ControllerWorkloadType, - OS: "foo", - Version: "1.1.1", - Supported: false, - IgnoreDistroInfoUpdate: false, - }, - } - - info := newSupportedInfo(mockDistroSource, preset) - err := info.compile(now) - c.Assert(err, jc.ErrorIsNil) - - ctrlBases := info.controllerBases() - - c.Assert(ctrlBases, jc.DeepEquals, []Base{}) -} - -func (s *SupportedSuite) TestCompileForControllersUpdated(c *gc.C) { - ctrl := gomock.NewController(c) - defer ctrl.Finish() - - now := clock.WallClock.Now() - - mockDistroSource := NewMockDistroSource(ctrl) - mockDistroSource.EXPECT().Refresh().Return(nil) - mockDistroSource.EXPECT().SeriesInfo("supported").Return(series.DistroInfoSerie{ - Released: now.AddDate(0, 0, -10), - EOL: now.AddDate(0, 0, -9), - }, true) - - preset := map[SeriesName]seriesVersion{ - "supported": { - WorkloadType: ControllerWorkloadType, - OS: "foo", - Version: "1.1.1", - Supported: true, - IgnoreDistroInfoUpdate: false, - }, - } - - info := newSupportedInfo(mockDistroSource, preset) - err := info.compile(now) - c.Assert(err, jc.ErrorIsNil) - - ctrlBases := info.controllerBases() - - c.Assert(ctrlBases, jc.DeepEquals, []Base{}) -} - -func (s *SupportedSuite) TestCompileForControllersWithoutOverride(c *gc.C) { - ctrl := gomock.NewController(c) - defer ctrl.Finish() - - now := clock.WallClock.Now() - - mockDistroSource := NewMockDistroSource(ctrl) - mockDistroSource.EXPECT().Refresh().Return(nil) - mockDistroSource.EXPECT().SeriesInfo("supported").Return(series.DistroInfoSerie{ - Released: now.AddDate(0, 0, 9), - EOL: now.AddDate(0, 0, 10), - }, true) - - preset := map[SeriesName]seriesVersion{ - "supported": { - WorkloadType: ControllerWorkloadType, - OS: "foo", - Version: "1.1.1", - Supported: true, - }, - } - - info := newSupportedInfo(mockDistroSource, preset) - err := info.compile(now) - c.Assert(err, jc.ErrorIsNil) - - ctrlBases := info.controllerBases() - - c.Assert(ctrlBases, jc.DeepEquals, []Base{}) -} - -func (s *SupportedSuite) TestCompileForWorkloads(c *gc.C) { - ctrl := gomock.NewController(c) - defer ctrl.Finish() - - now := clock.WallClock.Now() - - mockDistroSource := NewMockDistroSource(ctrl) - mockDistroSource.EXPECT().Refresh().Return(nil) - mockDistroSource.EXPECT().SeriesInfo("ctrl-supported").Return(series.DistroInfoSerie{ - Released: now.AddDate(0, 0, -1), - EOL: now.AddDate(0, 0, 1), - }, true) - mockDistroSource.EXPECT().SeriesInfo("ctrl-deprecated-lts").Return(series.DistroInfoSerie{ - Released: now.AddDate(0, 0, -1), - EOL: now.AddDate(0, 0, 1), - }, true) - mockDistroSource.EXPECT().SeriesInfo("ctrl-not-updated").Return(series.DistroInfoSerie{ - Released: now.AddDate(0, 0, 1), - EOL: now.AddDate(0, 0, 2), - }, true) - mockDistroSource.EXPECT().SeriesInfo("ctrl-ignored").Return(series.DistroInfoSerie{}, false) - mockDistroSource.EXPECT().SeriesInfo("work-supported").Return(series.DistroInfoSerie{ - Released: now.AddDate(0, 0, -1), - EOL: now.AddDate(0, 0, 1), - }, true) - mockDistroSource.EXPECT().SeriesInfo("work-deprecated-lts").Return(series.DistroInfoSerie{ - Released: now.AddDate(0, 0, -1), - EOL: now.AddDate(0, 0, 1), - }, true) - mockDistroSource.EXPECT().SeriesInfo("work-not-updated").Return(series.DistroInfoSerie{ - Released: now.AddDate(0, 0, 1), - EOL: now.AddDate(0, 0, 2), - }, true) - mockDistroSource.EXPECT().SeriesInfo("work-ignored").Return(series.DistroInfoSerie{}, false) - - preset := map[SeriesName]seriesVersion{ - "ctrl-supported": { - WorkloadType: ControllerWorkloadType, - OS: "foo", - Version: "1.1.1", - Supported: true, - }, - "ctrl-deprecated-lts": { - WorkloadType: ControllerWorkloadType, - OS: "foo", - Version: "1.1.2", - Supported: false, - }, - "ctrl-not-updated": { - WorkloadType: ControllerWorkloadType, - OS: "foo", - Version: "1.1.3", - Supported: false, - }, - "ctrl-ignored": { - WorkloadType: ControllerWorkloadType, - OS: "foo", - Version: "1.1.4", - Supported: false, - }, - "work-supported": { - WorkloadType: OtherWorkloadType, - OS: "foo", - Version: "1.1.5", - Supported: true, - }, - "work-deprecated-lts": { - WorkloadType: OtherWorkloadType, - OS: "foo", - Version: "1.1.6", - Supported: false, - }, - "work-not-updated": { - WorkloadType: OtherWorkloadType, - OS: "foo", - Version: "1.1.7", - Supported: false, - }, - "work-ignored": { - WorkloadType: OtherWorkloadType, - OS: "foo", - Version: "1.1.8", - Supported: false, - }, - } - - info := newSupportedInfo(mockDistroSource, preset) - err := info.compile(now) - c.Assert(err, jc.ErrorIsNil) - - workloadBases := info.workloadBases(false) - - c.Assert(workloadBases, jc.DeepEquals, []Base{MustParseBaseFromString("foo@1.1.1"), MustParseBaseFromString("foo@1.1.5")}) - - // Double check that controller series doesn't change when we have workload - // types. - ctrlBases := info.controllerBases() - - c.Assert(ctrlBases, jc.DeepEquals, []Base{MustParseBaseFromString("foo@1.1.1")}) -} diff --git a/core/base/supportedbases.go b/core/base/supportedbases.go index f813f9f977f..496af9b40ed 100644 --- a/core/base/supportedbases.go +++ b/core/base/supportedbases.go @@ -3,76 +3,23 @@ package base -import ( - "time" - - "github.com/juju/collections/set" - "github.com/juju/errors" - "github.com/juju/os/v2/series" -) - -// UbuntuDistroInfo is the path for the Ubuntu distro info file. -var UbuntuDistroInfo = series.UbuntuDistroInfo - // ControllerBases returns the supported workload bases available to it at the // execution time. -func ControllerBases(now time.Time, requestedBase Base, imageStream string) ([]Base, error) { - supported, err := supportedInfoForType(UbuntuDistroInfo, now, requestedBase, imageStream) - if err != nil { - return nil, errors.Trace(err) +func ControllerBases() []Base { + return []Base{ + MakeDefaultBase(UbuntuOS, "20.04"), + MakeDefaultBase(UbuntuOS, "22.04"), + MakeDefaultBase(UbuntuOS, "24.04"), } - return supported.controllerBases(), nil } // WorkloadBases returns the supported workload bases available to it at the // execution time. -func WorkloadBases(now time.Time, requestedBase Base, imageStream string) ([]Base, error) { - supported, err := supportedInfoForType(UbuntuDistroInfo, now, requestedBase, imageStream) - if err != nil { - return nil, errors.Trace(err) - } - return supported.workloadBases(false), nil -} - -// AllWorkloadVersions returns all the workload versions (supported or not). -func AllWorkloadVersions() (set.Strings, error) { - supported, err := supportedInfoForType(UbuntuDistroInfo, time.Now(), Base{}, "") - if err != nil { - return nil, errors.Trace(err) +func WorkloadBases() []Base { + return []Base{ + MakeDefaultBase(UbuntuOS, "20.04"), + MakeDefaultBase(UbuntuOS, "22.04"), + MakeDefaultBase(UbuntuOS, "23.10"), + MakeDefaultBase(UbuntuOS, "24.04"), } - return set.NewStrings(supported.workloadVersions(true)...), nil -} - -// AllWorkloadOSTypes returns all the workload os types (supported or not). -func AllWorkloadOSTypes() (set.Strings, error) { - supported, err := supportedInfoForType(UbuntuDistroInfo, time.Now(), Base{}, "") - if err != nil { - return nil, errors.Trace(err) - } - result := set.NewStrings() - for _, wBase := range supported.workloadBases(true) { - result.Add(wBase.OS) - } - return result, nil -} - -func supportedInfoForType(path string, now time.Time, requestedBase Base, imageStream string) (*supportedInfo, error) { - // For non-LTS releases; they'll appear in juju/os as default available, but - // after reading the `/usr/share/distro-info/ubuntu.csv` on the Ubuntu distro - // the non-LTS should disappear if they're not in the release window for that - // series. - seriesVersionsMutex.Lock() - defer seriesVersionsMutex.Unlock() - updateSeriesVersionsOnce() - all := getAllSeriesVersions() - if !requestedBase.Empty() && imageStream == Daily { - setSupported(all, requestedBase) - } - source := series.NewDistroInfo(path) - supported := newSupportedInfo(source, all) - if err := supported.compile(now); err != nil { - return nil, errors.Trace(err) - } - - return supported, nil } diff --git a/core/base/supportedbases_test.go b/core/base/supportedbases_test.go deleted file mode 100644 index 707db1af38b..00000000000 --- a/core/base/supportedbases_test.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2020 Canonical Ltd. -// Licensed under the AGPLv3, see LICENCE file for details. - -package base - -import ( - "time" - - "github.com/juju/testing" - jc "github.com/juju/testing/checkers" - gc "gopkg.in/check.v1" -) - -type BasesSuite struct { - testing.IsolationSuite -} - -var _ = gc.Suite(&BasesSuite{}) - -func (s *BasesSuite) TestWorkloadBases(c *gc.C) { - tests := []struct { - name string - requestedBase Base - imageStream string - err string - expectedBase []Base - }{{ - name: "no base", - requestedBase: Base{}, - imageStream: Daily, - expectedBase: []Base{ - MustParseBaseFromString("ubuntu@20.04/stable"), - MustParseBaseFromString("ubuntu@22.04/stable"), - MustParseBaseFromString("ubuntu@24.04/stable"), - }, - }, { - name: "requested base", - requestedBase: MustParseBaseFromString("ubuntu@22.04"), - imageStream: Daily, - expectedBase: []Base{ - MustParseBaseFromString("ubuntu@20.04/stable"), - MustParseBaseFromString("ubuntu@22.04/stable"), - MustParseBaseFromString("ubuntu@24.04/stable"), - }, - }} - for _, test := range tests { - c.Logf("test %q", test.name) - - result, err := WorkloadBases(time.Now(), test.requestedBase, test.imageStream) - if test.err != "" { - c.Assert(err, gc.ErrorMatches, test.err) - continue - } - c.Assert(err, jc.ErrorIsNil) - c.Assert(result, gc.DeepEquals, test.expectedBase) - } -} diff --git a/core/base/supportedseries.go b/core/base/supportedseries.go deleted file mode 100644 index a8df4f38a0a..00000000000 --- a/core/base/supportedseries.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2020 Canonical Ltd. -// Licensed under the AGPLv3, see LICENCE file for details. - -package base - -import ( - "sync" - "time" - - "github.com/juju/collections/set" - "github.com/juju/errors" - jujuos "github.com/juju/os/v2" - "github.com/juju/os/v2/series" - - internallogger "github.com/juju/juju/internal/logger" -) - -const ( - // Daily defines if a image-stream is set to this, then you get a different - // set of logic. In this case if you want to test drive new releases, it's - // required that the image-stream modelconfig is set from released to - // daily. - Daily = "daily" -) - -// SupportedSeriesFunc describes a function that has commonality between -// controller and workload types. -type SupportedSeriesFunc = func(time.Time, string, string) (set.Strings, error) - -func getAllSeriesVersions() map[SeriesName]seriesVersion { - copy := make(map[SeriesName]seriesVersion, len(allSeriesVersions)) - for name, v := range allSeriesVersions { - copy[name] = v - } - return copy -} - -// LocalSeriesVersionInfo is patched for tests. -var LocalSeriesVersionInfo = series.LocalSeriesVersionInfo - -func updateSeriesVersions() error { - hostOS, sInfo, err := LocalSeriesVersionInfo() - if err != nil { - return errors.Trace(err) - } - switch hostOS { - case jujuos.Ubuntu: - for seriesName, s := range sInfo { - key := SeriesName(seriesName) - if _, known := ubuntuSeries[key]; known { - // We only update unknown/new series. - continue - } - ubuntuSeries[key] = seriesVersion{ - WorkloadType: ControllerWorkloadType, - OS: UbuntuOS, - Version: s.Version, - LTS: s.LTS, - Supported: s.Supported, - ESMSupported: s.ESMSupported, - IgnoreDistroInfoUpdate: false, - UpdatedByLocalDistroInfo: s.CreatedByLocalDistroInfo, - } - } - default: - } - composeSeriesVersions() - return nil -} - -func composeSeriesVersions() { - allSeriesVersions = make(map[SeriesName]seriesVersion) - for k, v := range ubuntuSeries { - allSeriesVersions[k] = v - } -} - -var ( - logger = internallogger.GetLogger("juju.juju.base") - - seriesVersionsMutex sync.Mutex -) - -// versionSeries provides a mapping between versions and series names. -var ( - versionSeries map[string]string - allSeriesVersions map[SeriesName]seriesVersion -) - -// UpdateSeriesVersions forces an update of the series versions by querying -// distro-info if possible. -func UpdateSeriesVersions() error { - seriesVersionsMutex.Lock() - defer seriesVersionsMutex.Unlock() - - if err := updateSeriesVersions(); err != nil { - return err - } - updateVersionSeries() - return nil -} - -var updatedSeriesVersions bool - -func updateSeriesVersionsOnce() { - if !updatedSeriesVersions { - if err := updateSeriesVersions(); err != nil { - logger.Warningf("failed to update distro info: %v", err) - } - updateVersionSeries() - updatedSeriesVersions = true - } -} - -func updateVersionSeries() { - versionSeries = make(map[string]string, len(allSeriesVersions)) - for k, v := range allSeriesVersions { - versionSeries[v.Version] = string(k) - } -} diff --git a/core/base/supportedseries_linux_test.go b/core/base/supportedseries_linux_test.go deleted file mode 100644 index 986f67d54ea..00000000000 --- a/core/base/supportedseries_linux_test.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2021 Canonical Ltd. -// Licensed under the AGPLv3, see LICENCE file for details. - -package base - -import ( - "time" - - "github.com/juju/collections/transform" - jujuos "github.com/juju/os/v2" - jujuseries "github.com/juju/os/v2/series" - "github.com/juju/testing" - jc "github.com/juju/testing/checkers" - gc "gopkg.in/check.v1" -) - -type SupportedSeriesLinuxSuite struct { - testing.IsolationSuite -} - -var _ = gc.Suite(&SupportedSeriesLinuxSuite{}) - -func (s *SupportedSeriesLinuxSuite) SetUpTest(c *gc.C) { - s.IsolationSuite.SetUpTest(c) - s.PatchValue(&LocalSeriesVersionInfo, func() (jujuos.OSType, map[string]jujuseries.SeriesVersionInfo, error) { - return jujuos.Ubuntu, map[string]jujuseries.SeriesVersionInfo{ - "hairy": {}, - }, nil - }) -} - -func (s *SupportedSeriesLinuxSuite) TestWorkloadBases(c *gc.C) { - tmpFile, close := makeTempFile(c, distroInfoContents) - defer close() - - s.PatchValue(&UbuntuDistroInfo, tmpFile.Name()) - - bases, err := WorkloadBases(time.Time{}, Base{}, "") - c.Assert(err, jc.ErrorIsNil) - c.Assert(bases, gc.DeepEquals, transform.Slice([]string{ - "ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04", - }, MustParseBaseFromString)) -} diff --git a/core/base/supportedseries_test.go b/core/base/supportedseries_test.go deleted file mode 100644 index b4375b3b76b..00000000000 --- a/core/base/supportedseries_test.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2020 Canonical Ltd. -// Licensed under the AGPLv3, see LICENCE file for details. - -package base - -import ( - "os" - "time" - - "github.com/juju/collections/transform" - "github.com/juju/testing" - jc "github.com/juju/testing/checkers" - gc "gopkg.in/check.v1" -) - -const distroInfoContents = `version,codename,series,created,release,eol,eol-server -10.04,Firefox,firefox,2009-10-13,2010-04-26,2016-04-26 -12.04 LTS,Precise Pangolin,precise,2011-10-13,2012-04-26,2017-04-26 -99.04,Focal,focal,2020-04-25,2020-10-17,2365-07-17 -` - -type SupportedSeriesSuite struct { - testing.IsolationSuite -} - -var _ = gc.Suite(&SupportedSeriesSuite{}) - -func (s *SupportedSeriesSuite) TestSupportedInfoForType(c *gc.C) { - tmpFile, close := makeTempFile(c, distroInfoContents) - defer close() - - now := time.Date(2020, 3, 16, 0, 0, 0, 0, time.UTC) - - info, err := supportedInfoForType(tmpFile.Name(), now, Base{}, "") - c.Assert(err, jc.ErrorIsNil) - - ctrlBases := info.controllerBases() - c.Assert(ctrlBases, jc.DeepEquals, transform.Slice([]string{"ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04"}, MustParseBaseFromString)) - - workloadBases := info.workloadBases(false) - c.Assert(workloadBases, jc.DeepEquals, transform.Slice([]string{ - "ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04", - }, MustParseBaseFromString)) -} - -func (s *SupportedSeriesSuite) TestSupportedInfoForTypeUsingImageStream(c *gc.C) { - tmpFile, close := makeTempFile(c, distroInfoContents) - defer close() - - now := time.Date(2020, 3, 16, 0, 0, 0, 0, time.UTC) - - info, err := supportedInfoForType(tmpFile.Name(), now, MustParseBaseFromString("ubuntu@20.04"), "daily") - c.Assert(err, jc.ErrorIsNil) - - ctrlBases := info.controllerBases() - c.Assert(ctrlBases, jc.DeepEquals, transform.Slice([]string{"ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04"}, MustParseBaseFromString)) - - workloadBases := info.workloadBases(false) - c.Assert(workloadBases, jc.DeepEquals, transform.Slice([]string{ - "ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04", - }, MustParseBaseFromString)) -} - -func (s *SupportedSeriesSuite) TestSupportedInfoForTypeUsingInvalidImageStream(c *gc.C) { - tmpFile, close := makeTempFile(c, distroInfoContents) - defer close() - - now := time.Date(2020, 3, 16, 0, 0, 0, 0, time.UTC) - - info, err := supportedInfoForType(tmpFile.Name(), now, MustParseBaseFromString("ubuntu@20.04"), "turtle") - c.Assert(err, jc.ErrorIsNil) - - ctrlBases := info.controllerBases() - c.Assert(ctrlBases, jc.DeepEquals, transform.Slice([]string{"ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04"}, MustParseBaseFromString)) - - workloadBases := info.workloadBases(false) - c.Assert(workloadBases, jc.DeepEquals, transform.Slice([]string{ - "ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04", - }, MustParseBaseFromString)) -} - -func (s *SupportedSeriesSuite) TestSupportedInfoForTypeUsingInvalidSeries(c *gc.C) { - tmpFile, close := makeTempFile(c, distroInfoContents) - defer close() - - now := time.Date(2020, 3, 16, 0, 0, 0, 0, time.UTC) - - info, err := supportedInfoForType(tmpFile.Name(), now, MustParseBaseFromString("ubuntu@10.04"), "daily") - c.Assert(err, jc.ErrorIsNil) - - ctrlBases := info.controllerBases() - c.Assert(ctrlBases, jc.DeepEquals, transform.Slice([]string{"ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04"}, MustParseBaseFromString)) - - workloadBases := info.workloadBases(false) - c.Assert(workloadBases, jc.DeepEquals, transform.Slice([]string{ - "ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04", - }, MustParseBaseFromString)) -} - -func makeTempFile(c *gc.C, content string) (*os.File, func()) { - tmpfile, err := os.CreateTemp("", "distroinfo") - if err != nil { - c.Assert(err, jc.ErrorIsNil) - } - - _, err = tmpfile.Write([]byte(content)) - c.Assert(err, jc.ErrorIsNil) - - // Reset the file for reading. - _, err = tmpfile.Seek(0, 0) - c.Assert(err, jc.ErrorIsNil) - - return tmpfile, func() { - err := os.Remove(tmpfile.Name()) - c.Assert(err, jc.ErrorIsNil) - } -} diff --git a/environs/bootstrap/bootstrap_test.go b/environs/bootstrap/bootstrap_test.go index 33de285d753..404395d4cf3 100644 --- a/environs/bootstrap/bootstrap_test.go +++ b/environs/bootstrap/bootstrap_test.go @@ -89,7 +89,6 @@ func (s *bootstrapSuite) SetUpTest(c *gc.C) { stor, err := filestorage.NewFileStorageWriter(storageDir) c.Assert(err, jc.ErrorIsNil) s.PatchValue(&jujuversion.Current, coretesting.FakeVersionNumber) - s.PatchValue(&corebase.UbuntuDistroInfo, "/path/notexists") envtesting.UploadFakeTools(c, stor, "released", "released") s.callContext = envcontext.WithoutCredentialInvalidator(context.Background()) @@ -911,7 +910,7 @@ func createImageMetadataForArch(c *gc.C, arch string) (dir string, _ []*imagemet im := []*imagemetadata.ImageMetadata{{ Id: "1234", Arch: arch, - Version: "16.04", + Version: "22.04", RegionName: "region", Endpoint: "endpoint", }} @@ -923,7 +922,7 @@ func createImageMetadataForArch(c *gc.C, arch string) (dir string, _ []*imagemet sourceStor, err := filestorage.NewFileStorageWriter(sourceDir) c.Assert(err, jc.ErrorIsNil) ss := simplestreams.NewSimpleStreams(sstesting.TestDataSourceFactory()) - base := corebase.MustParseBaseFromString("ubuntu@16.04") + base := corebase.MustParseBaseFromString("ubuntu@22.04") err = imagemetadata.MergeAndWriteMetadata(context.Background(), ss, base, im, cloudSpec, sourceStor) c.Assert(err, jc.ErrorIsNil) return sourceDir, im diff --git a/environs/bootstrap/tools_test.go b/environs/bootstrap/tools_test.go index f3586ab4f7d..920e502e6d1 100644 --- a/environs/bootstrap/tools_test.go +++ b/environs/bootstrap/tools_test.go @@ -220,7 +220,6 @@ func (s *toolsSuite) TestFindAvailableToolsSpecificVersion(c *gc.C) { func (s *toolsSuite) TestFindAvailableToolsCompleteNoValidate(c *gc.C) { s.PatchValue(&arch.HostArch, func() string { return arch.AMD64 }) - s.PatchValue(&corebase.UbuntuDistroInfo, "/path/notexists") allTools := tools.List{ &tools.Tools{ diff --git a/environs/config/config.go b/environs/config/config.go index e569ca91f05..ba83b65dd18 100644 --- a/environs/config/config.go +++ b/environs/config/config.go @@ -1003,10 +1003,7 @@ func (c *Config) validateDefaultBase() error { return errors.Annotatef(err, "invalid default base %q", defaultBase) } - supported, err := corebase.WorkloadBases(time.Now(), corebase.Base{}, "") - if err != nil { - return errors.Annotate(err, "cannot read supported bases") - } + supported := corebase.WorkloadBases() logger.Tracef("supported bases %s", supported) var found bool for _, supportedBase := range supported { diff --git a/environs/imagedownloads/simplestreams.go b/environs/imagedownloads/simplestreams.go index 388c1dbc9ea..bd82dd0ba84 100644 --- a/environs/imagedownloads/simplestreams.go +++ b/environs/imagedownloads/simplestreams.go @@ -122,12 +122,8 @@ func validateArgs(arch, release, ftype string) error { } validVersion := false - workloadVersions, err := corebase.AllWorkloadVersions() - if err != nil { - return errors.Trace(err) - } - for _, supported := range workloadVersions.Values() { - if release == supported { + for _, supported := range corebase.WorkloadBases() { + if release == supported.Channel.Track { validVersion = true break } diff --git a/environs/imagedownloads/simplestreams_test.go b/environs/imagedownloads/simplestreams_test.go index dc88f8207b3..441b00d8e29 100644 --- a/environs/imagedownloads/simplestreams_test.go +++ b/environs/imagedownloads/simplestreams_test.go @@ -17,7 +17,6 @@ import ( openpgperrors "golang.org/x/crypto/openpgp/errors" gc "gopkg.in/check.v1" - corebase "github.com/juju/juju/core/base" "github.com/juju/juju/environs/imagedownloads" "github.com/juju/juju/environs/imagemetadata" "github.com/juju/juju/environs/simplestreams" @@ -42,7 +41,6 @@ func newTestDataSourceFunc(s string) func() simplestreams.DataSource { } func (s *Suite) SetUpTest(c *gc.C) { - s.PatchValue(&corebase.UbuntuDistroInfo, "/path/notexists") imagemetadata.SimplestreamsImagesPublicKey = streamstesting.SignedMetadataPublicKey // The index.sjson file used by these tests have been regenerated using @@ -207,16 +205,16 @@ func (*Suite) TestOneAmd64XenialTarGz(c *gc.C) { ss := simplestreams.NewSimpleStreams(streamstesting.TestDataSourceFactory()) ts := httptest.NewServer(&sstreamsHandler{}) defer ts.Close() - got, err := imagedownloads.One(context.Background(), ss, "amd64", "16.04", "", "tar.gz", newTestDataSourceFunc(ts.URL)) + got, err := imagedownloads.One(context.Background(), ss, "amd64", "22.04", "", "tar.gz", newTestDataSourceFunc(ts.URL)) c.Check(err, jc.ErrorIsNil) c.Assert(got, jc.DeepEquals, &imagedownloads.Metadata{ Arch: "amd64", - Release: "xenial", - Version: "16.04", + Release: "jammy", + Version: "22.04", FType: "tar.gz", - SHA256: "c48036699274351be132f2aec7fec9fd2da936b6b512c65b2d9fd6531e5623ea", - Path: "server/releases/xenial/release-20211001/ubuntu-16.04-server-cloudimg-amd64.tar.gz", - Size: 287684992, + SHA256: "4e466ce60488c520e34c5f3e4aa57b88528b9500b2f48bf40773192c9260ed93", + Path: "server/releases/jammy/release-20220923/ubuntu-22.04-server-cloudimg-amd64.tar.gz", + Size: 610831936, }) } diff --git a/environs/imagemetadata/generate_test.go b/environs/imagemetadata/generate_test.go index cb862a48ae2..fdc5b94040c 100644 --- a/environs/imagemetadata/generate_test.go +++ b/environs/imagemetadata/generate_test.go @@ -20,8 +20,8 @@ import ( ) var ( - testBase = corebase.MustParseBaseFromString("ubuntu@16.04") - testVersion = "16.04" + testBase = corebase.MustParseBaseFromString("ubuntu@22.04") + testVersion = "22.04" ) var _ = gc.Suite(&generateSuite{}) @@ -30,10 +30,6 @@ type generateSuite struct { coretesting.BaseSuite } -func (s *generateSuite) SetUpTest(c *gc.C) { - s.PatchValue(&corebase.UbuntuDistroInfo, "/path/notexists") -} - func assertFetch(c *gc.C, ss *simplestreams.Simplestreams, stor storage.Storage, version, arch, region, endpoint string, ids ...string) { cons, err := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ CloudSpec: simplestreams.CloudSpec{region, endpoint}, diff --git a/environs/imagemetadata/simplestreams.go b/environs/imagemetadata/simplestreams.go index d9536535f76..d585cbd42f2 100644 --- a/environs/imagemetadata/simplestreams.go +++ b/environs/imagemetadata/simplestreams.go @@ -8,6 +8,7 @@ import ( "fmt" "sort" + "github.com/juju/collections/transform" "github.com/juju/errors" "github.com/juju/juju/core/arch" @@ -140,11 +141,7 @@ type ImageConstraint struct { func NewImageConstraint(params simplestreams.LookupParams) (*ImageConstraint, error) { if len(params.Releases) == 0 { - workloadVersions, err := corebase.AllWorkloadVersions() - if err != nil { - return nil, errors.Trace(err) - } - params.Releases = workloadVersions.SortedValues() + params.Releases = transform.Slice(corebase.WorkloadBases(), func(b corebase.Base) string { return b.Channel.Track }) } if len(params.Arches) == 0 { params.Arches = arch.AllSupportedArches diff --git a/environs/sync/sync_test.go b/environs/sync/sync_test.go index aebbb80b1b2..2c399a6f3f3 100644 --- a/environs/sync/sync_test.go +++ b/environs/sync/sync_test.go @@ -24,7 +24,6 @@ import ( gc "gopkg.in/check.v1" "github.com/juju/juju/core/arch" - corebase "github.com/juju/juju/core/base" coreos "github.com/juju/juju/core/os" "github.com/juju/juju/core/os/ostype" "github.com/juju/juju/environs/filestorage" @@ -232,7 +231,6 @@ type uploadSuite struct { func (s *uploadSuite) SetUpTest(c *gc.C) { s.FakeJujuXDGDataHomeSuite.SetUpTest(c) s.ToolsFixture.SetUpTest(c) - s.PatchValue(&corebase.UbuntuDistroInfo, "/path/notexists") // Create a target storage. stor, err := filestorage.NewFileStorageWriter(c.MkDir()) diff --git a/environs/tools/simplestreams_test.go b/environs/tools/simplestreams_test.go index 792544dc52b..83d1cb3fd74 100644 --- a/environs/tools/simplestreams_test.go +++ b/environs/tools/simplestreams_test.go @@ -24,7 +24,6 @@ import ( "github.com/juju/version/v2" gc "gopkg.in/check.v1" - corebase "github.com/juju/juju/core/base" coreos "github.com/juju/juju/core/os" "github.com/juju/juju/environs/filestorage" "github.com/juju/juju/environs/simplestreams" @@ -145,7 +144,6 @@ type simplestreamsSuite struct { func (s *simplestreamsSuite) SetUpSuite(c *gc.C) { s.LocalLiveSimplestreamsSuite.SetUpSuite(c) s.TestDataSuite.SetUpSuite(c) - s.PatchValue(&corebase.UbuntuDistroInfo, "/path/notexists") } func (s *simplestreamsSuite) TearDownSuite(c *gc.C) { diff --git a/environs/tools/tools.go b/environs/tools/tools.go index 4181659eab7..f12cf940da8 100644 --- a/environs/tools/tools.go +++ b/environs/tools/tools.go @@ -53,12 +53,8 @@ func makeToolsConstraint(cloudSpec simplestreams.CloudSpec, stream string, major if filter.OSType != "" { osToSearch = []string{filter.OSType} } else { - workloadOSTypes, err := corebase.AllWorkloadOSTypes() - if err != nil { - return nil, errors.Trace(err) - } - osToSearch = workloadOSTypes.Values() - logger.Tracef("no os type specified when finding agent binaries, looking for %v", osToSearch) + osToSearch = []string{corebase.UbuntuOS} + logger.Tracef("no os type specified when finding agent binaries, looking for ubuntu") } toolsConstraint.Releases = osToSearch return toolsConstraint, nil diff --git a/environs/tools/tools_test.go b/environs/tools/tools_test.go index 6a9853a60ce..9d24c3ed532 100644 --- a/environs/tools/tools_test.go +++ b/environs/tools/tools_test.go @@ -16,7 +16,6 @@ import ( "golang.org/x/net/context" gc "gopkg.in/check.v1" - corebase "github.com/juju/juju/core/base" "github.com/juju/juju/environs" "github.com/juju/juju/environs/bootstrap" "github.com/juju/juju/environs/simplestreams" @@ -51,7 +50,6 @@ func (s *SimpleStreamsToolsSuite) SetUpSuite(c *gc.C) { s.customToolsDir = c.MkDir() s.publicToolsDir = c.MkDir() s.PatchValue(&keys.JujuPublicKey, sstesting.SignedMetadataPublicKey) - s.PatchValue(&corebase.UbuntuDistroInfo, "/path/notexists") } func (s *SimpleStreamsToolsSuite) SetUpTest(c *gc.C) { @@ -220,7 +218,7 @@ func (s *SimpleStreamsToolsSuite) TestFindToolsFiltering(c *gc.C) { {loggo.DEBUG, "reading agent binaries with major version 1"}, {loggo.DEBUG, "filtering agent binaries by version: \\d+\\.\\d+\\.\\d+"}, {loggo.TRACE, "no architecture specified when finding agent binaries, looking for "}, - {loggo.TRACE, "no os type specified when finding agent binaries, looking for \\[.*\\]"}, + {loggo.TRACE, "no os type specified when finding agent binaries, looking for .*"}, } sources, err := envtools.GetMetadataSources(s.env, ss) c.Assert(err, jc.ErrorIsNil) diff --git a/internal/migration/precheck_test.go b/internal/migration/precheck_test.go index 8a48bce4af8..975493a8ee6 100644 --- a/internal/migration/precheck_test.go +++ b/internal/migration/precheck_test.go @@ -14,6 +14,7 @@ import ( gc "gopkg.in/check.v1" "github.com/juju/juju/cloud" + "github.com/juju/juju/core/base" "github.com/juju/juju/core/credential" coremigration "github.com/juju/juju/core/migration" "github.com/juju/juju/core/presence" @@ -107,6 +108,15 @@ func (s *SourcePrecheckSuite) TestTargetController3Failed(c *gc.C) { return s.serverFactory }, ) + + s.PatchValue(&upgradevalidation.SupportedJujuBases, func() []base.Base { + return []base.Base{ + base.MustParseBaseFromString("ubuntu@24.04"), + base.MustParseBaseFromString("ubuntu@22.04"), + base.MustParseBaseFromString("ubuntu@20.04"), + } + }) + cloudSpec := lxd.CloudSpec{CloudSpec: environscloudspec.CloudSpec{Type: "lxd"}} backend := newFakeBackend() @@ -139,13 +149,21 @@ func (s *SourcePrecheckSuite) TestTargetController3Failed(c *gc.C) { cannot migrate to controller due to issues: "foo/model-1": - unexpected upgrade series lock found -- the model hosts 1 ubuntu machine(s) with an unsupported base. The supported bases are: ubuntu@20.04, ubuntu@22.04, ubuntu@24.04 +- the model hosts 1 ubuntu machine(s) with an unsupported base. The supported bases are: ubuntu@24.04, ubuntu@22.04, ubuntu@20.04 - LXD version has to be at least "5.0.0", but current version is only "4.0.0"`[1:]) } func (s *SourcePrecheckSuite) TestTargetController2Failed(c *gc.C) { defer s.setupMocks(c).Finish() + s.PatchValue(&upgradevalidation.SupportedJujuBases, func() []base.Base { + return []base.Base{ + base.MustParseBaseFromString("ubuntu@24.04"), + base.MustParseBaseFromString("ubuntu@22.04"), + base.MustParseBaseFromString("ubuntu@20.04"), + } + }) + backend := newFakeBackend() hasUpgradeSeriesLocks := true backend.hasUpgradeSeriesLocks = &hasUpgradeSeriesLocks @@ -171,7 +189,7 @@ func (s *SourcePrecheckSuite) TestTargetController2Failed(c *gc.C) { cannot migrate to controller due to issues: "foo/model-1": - unexpected upgrade series lock found -- the model hosts 1 ubuntu machine(s) with an unsupported base. The supported bases are: ubuntu@20.04, ubuntu@22.04, ubuntu@24.04`[1:]) +- the model hosts 1 ubuntu machine(s) with an unsupported base. The supported bases are: ubuntu@24.04, ubuntu@22.04, ubuntu@20.04`[1:]) } func (s *SourcePrecheckSuite) TestImportingModel(c *gc.C) { diff --git a/internal/provider/maas/environ.go b/internal/provider/maas/environ.go index 823d0c29e54..b62a6f7270b 100644 --- a/internal/provider/maas/environ.go +++ b/internal/provider/maas/environ.go @@ -22,7 +22,7 @@ import ( "github.com/juju/retry" "github.com/juju/version/v2" - corebase "github.com/juju/juju/core/base" + "github.com/juju/juju/core/base" "github.com/juju/juju/core/constraints" "github.com/juju/juju/core/instance" corenetwork "github.com/juju/juju/core/network" @@ -829,7 +829,7 @@ func (env *maasEnviron) distroSeries(args environs.StartInstanceParams) (string, if args.Constraints.HasImageID() { return *args.Constraints.ImageID, nil } - return corebase.GetSeriesFromBase(args.InstanceConfig.Base) + return base.GetSeriesFromBase(args.InstanceConfig.Base) } func (env *maasEnviron) waitForNodeDeployment(ctx envcontext.ProviderCallContext, id instance.Id, timeout time.Duration) error { diff --git a/internal/provider/openstack/local_test.go b/internal/provider/openstack/local_test.go index 068dc7304a0..3f8928ad02d 100644 --- a/internal/provider/openstack/local_test.go +++ b/internal/provider/openstack/local_test.go @@ -3646,19 +3646,15 @@ func (s *localServerSuite) TestIPv6RuleCreationForEmptyCIDR(c *gc.C) { func (s *localServerSuite) ensureAMDImages(c *gc.C) environs.Environ { // Ensure amd64 tools are available, to ensure an amd64 image. amd64Version := version.Binary{ - Number: jujuversion.Current, - Arch: arch.AMD64, - } - workloadOSList, err := corebase.AllWorkloadOSTypes() - c.Assert(err, jc.ErrorIsNil) - for _, workloadOS := range workloadOSList.Values() { - amd64Version.Release = workloadOS - envtesting.AssertUploadFakeToolsVersions( - c, s.toolsMetadataStorage, s.env.Config().AgentStream(), s.env.Config().AgentStream(), amd64Version) + Number: jujuversion.Current, + Arch: arch.AMD64, + Release: corebase.UbuntuOS, } + envtesting.AssertUploadFakeToolsVersions( + c, s.toolsMetadataStorage, s.env.Config().AgentStream(), s.env.Config().AgentStream(), amd64Version) // Destroy the old Environ - err = environs.Destroy(s.env.Config().Name(), s.env, s.callCtx, s.ControllerStore) + err := environs.Destroy(s.env.Config().Name(), s.env, s.callCtx, s.ControllerStore) c.Assert(err, jc.ErrorIsNil) // Prepare a new Environ diff --git a/internal/upgrades/preupgradesteps.go b/internal/upgrades/preupgradesteps.go index 9e7280a7b6b..58843a24121 100644 --- a/internal/upgrades/preupgradesteps.go +++ b/internal/upgrades/preupgradesteps.go @@ -9,8 +9,6 @@ import ( "github.com/juju/utils/v4/du" "github.com/juju/juju/agent" - corebase "github.com/juju/juju/core/base" - "github.com/juju/juju/internal/packaging/manager" ) // PreUpgradeStepsFunc is the function type of PreUpgradeSteps. This may be @@ -24,14 +22,6 @@ func PreUpgradeSteps(agentConf agent.Config, isController bool) error { if err := CheckFreeDiskSpace(agentConf.DataDir(), MinDiskSpaceMib); err != nil { return errors.Trace(err) } - if isController { - // Update distro info in case the new Juju controller version - // is aware of new supported series. We'll keep going if this - // fails, and the user can manually update it if they need to. - logger.Infof("updating distro-info") - err := updateDistroInfo() - return errors.Annotate(err, "failed to update distro-info") - } return nil } @@ -39,14 +29,6 @@ func PreUpgradeSteps(agentConf agent.Config, isController bool) error { // performing an upgrade. If any check fails, an error is returned which // aborts the upgrade. func PreUpgradeStepsCAAS(agentConf agent.Config, isController bool) error { - if isController { - // Update distro info in case the new Juju controller version - // is aware of new supported series. We'll keep going if this - // fails, and the user can manually update it if they need to. - logger.Infof("updating distro-info") - err := updateDistroInfo() - return errors.Annotate(err, "failed to update distro-info") - } return nil } @@ -66,14 +48,3 @@ func CheckFreeDiskSpace(dir string, thresholdMib uint64) error { } return nil } - -func updateDistroInfo() error { - pm := manager.NewAptPackageManager() - if err := pm.Update(); err != nil { - return errors.Annotate(err, "updating package list") - } - if err := pm.Install("distro-info"); err != nil { - return errors.Annotate(err, "updating distro-info package") - } - return corebase.UpdateSeriesVersions() -} diff --git a/internal/upgrades/preupgradesteps_test.go b/internal/upgrades/preupgradesteps_test.go index e7e4f3fb3b3..8488337c874 100644 --- a/internal/upgrades/preupgradesteps_test.go +++ b/internal/upgrades/preupgradesteps_test.go @@ -4,13 +4,9 @@ package upgrades_test import ( - "os/exec" - "github.com/dustin/go-humanize" - jc "github.com/juju/testing/checkers" gc "gopkg.in/check.v1" - pkgmgr "github.com/juju/juju/internal/packaging/manager" "github.com/juju/juju/internal/upgrades" "github.com/juju/juju/testing" ) @@ -27,38 +23,3 @@ func (s *preupgradechecksSuite) TestCheckFreeDiskSpace(c *gc.C) { err := upgrades.PreUpgradeSteps(&mockAgentConfig{dataDir: "/"}, false) c.Assert(err, gc.ErrorMatches, `not enough free disk space on "/" for upgrade: .* available, require 1073741824MiB`) } - -func (s *preupgradechecksSuite) TestUpdateDistroInfo(c *gc.C) { - s.PatchValue(&upgrades.MinDiskSpaceMib, uint64(0)) - expectedAptCommandArgs := [][]string{ - {"update"}, - {"install", "distro-info"}, - } - - commandChan := s.HookCommandOutput(&pkgmgr.CommandOutput, nil, nil) - err := upgrades.PreUpgradeSteps(&mockAgentConfig{dataDir: "/"}, true) - c.Assert(err, jc.ErrorIsNil) - - var commands []*exec.Cmd -loop: - for i := 0; i < cap(expectedAptCommandArgs)+1; i++ { - select { - case cmd := <-commandChan: - commands = append(commands, cmd) - default: - break loop - } - } - if len(commands) != len(expectedAptCommandArgs) { - c.Fatalf("expected %d commands, got %d", len(expectedAptCommandArgs), len(commands)) - } - - assertAptCommand := func(cmd *exec.Cmd, tailArgs ...string) { - args := cmd.Args - c.Assert(len(args), jc.GreaterThan, len(tailArgs)) - c.Assert(args[0], gc.Equals, "apt-get") - c.Assert(args[len(args)-len(tailArgs):], gc.DeepEquals, tailArgs) - } - assertAptCommand(commands[0], "update") - assertAptCommand(commands[1], "install", "distro-info") -} diff --git a/internal/upgrades/upgradevalidation/migrate_test.go b/internal/upgrades/upgradevalidation/migrate_test.go index fbdf530e674..205e0de047e 100644 --- a/internal/upgrades/upgradevalidation/migrate_test.go +++ b/internal/upgrades/upgradevalidation/migrate_test.go @@ -4,8 +4,6 @@ package upgradevalidation_test import ( - "time" - "github.com/juju/collections/transform" jujutesting "github.com/juju/testing" jc "github.com/juju/testing/checkers" @@ -88,8 +86,8 @@ func (s *migrateSuite) setupMocks(c *gc.C) (*gomock.Controller, environscloudspe }, ) - s.PatchValue(&upgradevalidation.SupportedJujuBases, func(time.Time, base.Base, string) ([]base.Base, error) { - return transform.SliceOrErr([]string{"ubuntu@24.04", "ubuntu@22.04", "ubuntu@20.04"}, base.ParseBaseFromString) + s.PatchValue(&upgradevalidation.SupportedJujuBases, func() []base.Base { + return transform.Slice([]string{"ubuntu@24.04", "ubuntu@22.04", "ubuntu@20.04"}, base.MustParseBaseFromString) }) // - check no upgrade series in process. diff --git a/internal/upgrades/upgradevalidation/upgrade_test.go b/internal/upgrades/upgradevalidation/upgrade_test.go index 7b437ea4153..fe9ff9882ea 100644 --- a/internal/upgrades/upgradevalidation/upgrade_test.go +++ b/internal/upgrades/upgradevalidation/upgrade_test.go @@ -4,8 +4,6 @@ package upgradevalidation_test import ( - "time" - "github.com/juju/collections/transform" "github.com/juju/names/v5" "github.com/juju/replicaset/v3" @@ -31,8 +29,8 @@ func (s *upgradeValidationSuite) TestValidatorsForControllerUpgradeJuju3(c *gc.C 3: version.MustParse("2.9.1"), }) - s.PatchValue(&upgradevalidation.SupportedJujuBases, func(time.Time, base.Base, string) ([]base.Base, error) { - return transform.SliceOrErr([]string{"ubuntu@24.04", "ubuntu@22.04", "ubuntu@20.04"}, base.ParseBaseFromString) + s.PatchValue(&upgradevalidation.SupportedJujuBases, func() []base.Base { + return transform.Slice([]string{"ubuntu@24.04", "ubuntu@22.04", "ubuntu@20.04"}, base.MustParseBaseFromString) }) ctrlModelTag := names.NewModelTag("deadpork-0bad-400d-8000-4b1d0d06f00d") @@ -113,8 +111,8 @@ func (s *upgradeValidationSuite) TestValidatorsForModelUpgradeJuju3(c *gc.C) { ctrl := gomock.NewController(c) defer ctrl.Finish() - s.PatchValue(&upgradevalidation.SupportedJujuBases, func(time.Time, base.Base, string) ([]base.Base, error) { - return transform.SliceOrErr([]string{"ubuntu@24.04", "ubuntu@22.04", "ubuntu@20.04"}, base.ParseBaseFromString) + s.PatchValue(&upgradevalidation.SupportedJujuBases, func() []base.Base { + return transform.Slice([]string{"ubuntu@24.04", "ubuntu@22.04", "ubuntu@20.04"}, base.MustParseBaseFromString) }) modelTag := coretesting.ModelTag diff --git a/internal/upgrades/upgradevalidation/validation.go b/internal/upgrades/upgradevalidation/validation.go index 34d291e9c42..e4716e4a200 100644 --- a/internal/upgrades/upgradevalidation/validation.go +++ b/internal/upgrades/upgradevalidation/validation.go @@ -7,7 +7,6 @@ import ( "fmt" "net/http" "strings" - "time" "github.com/juju/collections/transform" "github.com/juju/errors" @@ -160,11 +159,7 @@ var SupportedJujuBases = corebase.WorkloadBases func checkForDeprecatedUbuntuSeriesForModel( _ string, _ StatePool, st State, _ Model, ) (*Blocker, error) { - supportedBases, err := SupportedJujuBases(time.Now(), corebase.Base{}, "") - if err != nil { - return nil, errors.Annotate(err, "cannot ready supported bases") - } - + supportedBases := SupportedJujuBases() stateBases := transform.Slice(supportedBases, func(b corebase.Base) state.Base { return state.Base{OS: b.OS, Channel: b.Channel.String()} }) diff --git a/internal/upgrades/upgradevalidation/validation_test.go b/internal/upgrades/upgradevalidation/validation_test.go index 30a5cb3ba6f..df0b16e29e7 100644 --- a/internal/upgrades/upgradevalidation/validation_test.go +++ b/internal/upgrades/upgradevalidation/validation_test.go @@ -5,7 +5,6 @@ package upgradevalidation_test import ( "fmt" - "time" "github.com/juju/collections/transform" "github.com/juju/errors" @@ -117,8 +116,8 @@ func (s *upgradeValidationSuite) TestCheckForDeprecatedUbuntuSeriesForModel(c *g ctrl := gomock.NewController(c) defer ctrl.Finish() - s.PatchValue(&upgradevalidation.SupportedJujuBases, func(time.Time, base.Base, string) ([]base.Base, error) { - return transform.SliceOrErr([]string{"ubuntu@24.04", "ubuntu@22.04", "ubuntu@20.04"}, base.ParseBaseFromString) + s.PatchValue(&upgradevalidation.SupportedJujuBases, func() []base.Base { + return transform.Slice([]string{"ubuntu@24.04", "ubuntu@22.04", "ubuntu@20.04"}, base.MustParseBaseFromString) }) st := mocks.NewMockState(ctrl)