From 7de540ad001b477322878d71ee79d30d2fe5c70b Mon Sep 17 00:00:00 2001 From: Jack Shaw Date: Fri, 31 May 2024 13:07:53 +0100 Subject: [PATCH 1/3] Hardcode mapping between bases and series We have decided that relying on distro-info was a mistake, so are removing this with hardcoded maps. Start this by hard coding the mapping between series and bases. Whilst we're here, move GetSeriesFromBase into 'internal/provider/common', since it is only used by our providers, since some providers still need a series to find images (azure, maas) --- core/base/series.go | 51 +++++++++++++++++++++++++------ core/base/series_test.go | 6 ++-- internal/provider/maas/environ.go | 4 +-- 3 files changed, 47 insertions(+), 14 deletions(-) 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/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 { From b257bf1be2165ec841203e5209fa23fa8fdc8a30 Mon Sep 17 00:00:00 2001 From: Jack Shaw Date: Fri, 31 May 2024 13:49:59 +0100 Subject: [PATCH 2/3] Hardcode ControllerBases + WorkloadBases It was decided in Madrid that, going forward, we want to provide a hard coded list of ubuntu bases which we wish to support for 1) controllers 2) other workloads So hardcode the output to ControllerBases & WorkloadBases This means we can simplify the signature of these functions. This resulted in many small changes across Juju Also, importantly, this means we can remove all the code which searches distro info. This simplifies core/base dramatically! I also took the decision to remove 1) AllWorkloadVersions. This can simply be calculated using WorkloadBases. 2) AllWorkloadOSypes. This is only ubuntu now, so I just use the const instead --- .../client/application/deployrepository.go | 7 +- .../machinemanager/machinemanager_test.go | 4 +- .../client/modelupgrader/upgrader_test.go | 31 +- cmd/juju/application/deploy_test.go | 17 +- .../application/deployer/bundlehandler.go | 12 +- .../deployer/bundlehandler_test.go | 5 +- cmd/juju/application/deployer/deployer.go | 18 +- cmd/juju/commands/bootstrap.go | 17 +- cmd/juju/commands/bootstrap_test.go | 9 - cmd/jujud-controller/agent/bootstrap_test.go | 2 - core/base/distrosource_mock_test.go | 117 ------ core/base/package_test.go | 2 - core/base/supported.go | 389 ------------------ core/base/supported_test.go | 305 -------------- core/base/supportedbases.go | 74 +--- core/base/supportedbases_test.go | 57 --- core/base/supportedseries.go | 120 ------ core/base/supportedseries_linux_test.go | 43 -- core/base/supportedseries_test.go | 117 ------ environs/bootstrap/bootstrap_test.go | 5 +- environs/bootstrap/tools_test.go | 1 - environs/config/config.go | 5 +- environs/imagedownloads/simplestreams.go | 8 +- environs/imagedownloads/simplestreams_test.go | 14 +- environs/imagemetadata/generate_test.go | 8 +- environs/imagemetadata/simplestreams.go | 7 +- environs/sync/sync_test.go | 2 - environs/tools/simplestreams_test.go | 2 - environs/tools/tools.go | 8 +- environs/tools/tools_test.go | 4 +- internal/migration/precheck_test.go | 22 +- internal/provider/openstack/local_test.go | 16 +- internal/upgrades/preupgradesteps.go | 29 -- internal/upgrades/preupgradesteps_test.go | 39 -- .../upgradevalidation/migrate_test.go | 6 +- .../upgradevalidation/upgrade_test.go | 10 +- .../upgrades/upgradevalidation/validation.go | 7 +- .../upgradevalidation/validation_test.go | 5 +- 38 files changed, 102 insertions(+), 1442 deletions(-) delete mode 100644 core/base/distrosource_mock_test.go delete mode 100644 core/base/supported.go delete mode 100644 core/base/supported_test.go delete mode 100644 core/base/supportedbases_test.go delete mode 100644 core/base/supportedseries.go delete mode 100644 core/base/supportedseries_linux_test.go delete mode 100644 core/base/supportedseries_test.go 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 6b29404a45d..47dce11a85d 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 8dbbe246bdd..6c986841526 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 49febe9bd94..21697906919 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/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..2edc1d7c25a 100644 --- a/core/base/supportedbases.go +++ b/core/base/supportedbases.go @@ -3,76 +3,22 @@ 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"), } - 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/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) From ed9f7b0a914f0da17c595602be14bf9fc95714ea Mon Sep 17 00:00:00 2001 From: Jack Shaw Date: Fri, 7 Jun 2024 10:57:45 +0100 Subject: [PATCH 3/3] Add ubuntu@24.04 as a supported controller base We are imminently about to release a controller char for noble. Make sure it's supported! --- core/base/supportedbases.go | 1 + 1 file changed, 1 insertion(+) diff --git a/core/base/supportedbases.go b/core/base/supportedbases.go index 2edc1d7c25a..496af9b40ed 100644 --- a/core/base/supportedbases.go +++ b/core/base/supportedbases.go @@ -9,6 +9,7 @@ func ControllerBases() []Base { return []Base{ MakeDefaultBase(UbuntuOS, "20.04"), MakeDefaultBase(UbuntuOS, "22.04"), + MakeDefaultBase(UbuntuOS, "24.04"), } }