github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/core/base/supportedseries_test.go (about)

     1  // Copyright 2020 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package base
     5  
     6  import (
     7  	"os"
     8  	"time"
     9  
    10  	"github.com/juju/collections/transform"
    11  	"github.com/juju/testing"
    12  	jc "github.com/juju/testing/checkers"
    13  	gc "gopkg.in/check.v1"
    14  
    15  	"github.com/juju/juju/core/os/ostype"
    16  )
    17  
    18  const distroInfoContents = `version,codename,series,created,release,eol,eol-server
    19  10.04,Firefox,firefox,2009-10-13,2010-04-26,2016-04-26
    20  12.04 LTS,Precise Pangolin,precise,2011-10-13,2012-04-26,2017-04-26
    21  99.04,Focal,focal,2020-04-25,2020-10-17,2365-07-17
    22  `
    23  
    24  type SupportedSeriesSuite struct {
    25  	testing.IsolationSuite
    26  }
    27  
    28  var _ = gc.Suite(&SupportedSeriesSuite{})
    29  
    30  func (s *SupportedSeriesSuite) TestSupportedInfoForType(c *gc.C) {
    31  	tmpFile, close := makeTempFile(c, distroInfoContents)
    32  	defer close()
    33  
    34  	now := time.Date(2020, 3, 16, 0, 0, 0, 0, time.UTC)
    35  
    36  	info, err := supportedInfoForType(tmpFile.Name(), now, Base{}, "")
    37  	c.Assert(err, jc.ErrorIsNil)
    38  
    39  	ctrlBases := info.controllerBases()
    40  	c.Assert(ctrlBases, jc.DeepEquals, transform.Slice([]string{"ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04"}, MustParseBaseFromString))
    41  
    42  	workloadBases := info.workloadBases(false)
    43  	c.Assert(workloadBases, jc.DeepEquals, transform.Slice([]string{
    44  		"centos@7", "centos@9", "genericlinux@genericlinux", "kubernetes@kubernetes",
    45  		"ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04",
    46  	}, MustParseBaseFromString))
    47  }
    48  
    49  func (s *SupportedSeriesSuite) TestSupportedInfoForTypeUsingImageStream(c *gc.C) {
    50  	tmpFile, close := makeTempFile(c, distroInfoContents)
    51  	defer close()
    52  
    53  	now := time.Date(2020, 3, 16, 0, 0, 0, 0, time.UTC)
    54  
    55  	info, err := supportedInfoForType(tmpFile.Name(), now, MustParseBaseFromString("ubuntu@20.04"), "daily")
    56  	c.Assert(err, jc.ErrorIsNil)
    57  
    58  	ctrlBases := info.controllerBases()
    59  	c.Assert(ctrlBases, jc.DeepEquals, transform.Slice([]string{"ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04"}, MustParseBaseFromString))
    60  
    61  	workloadBases := info.workloadBases(false)
    62  	c.Assert(workloadBases, jc.DeepEquals, transform.Slice([]string{
    63  		"centos@7", "centos@9", "genericlinux@genericlinux", "kubernetes@kubernetes",
    64  		"ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04",
    65  	}, MustParseBaseFromString))
    66  }
    67  
    68  func (s *SupportedSeriesSuite) TestSupportedInfoForTypeUsingInvalidImageStream(c *gc.C) {
    69  	tmpFile, close := makeTempFile(c, distroInfoContents)
    70  	defer close()
    71  
    72  	now := time.Date(2020, 3, 16, 0, 0, 0, 0, time.UTC)
    73  
    74  	info, err := supportedInfoForType(tmpFile.Name(), now, MustParseBaseFromString("ubuntu@20.04"), "turtle")
    75  	c.Assert(err, jc.ErrorIsNil)
    76  
    77  	ctrlBases := info.controllerBases()
    78  	c.Assert(ctrlBases, jc.DeepEquals, transform.Slice([]string{"ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04"}, MustParseBaseFromString))
    79  
    80  	workloadBases := info.workloadBases(false)
    81  	c.Assert(workloadBases, jc.DeepEquals, transform.Slice([]string{
    82  		"centos@7", "centos@9", "genericlinux@genericlinux", "kubernetes@kubernetes",
    83  		"ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04",
    84  	}, MustParseBaseFromString))
    85  }
    86  
    87  func (s *SupportedSeriesSuite) TestSupportedInfoForTypeUsingInvalidSeries(c *gc.C) {
    88  	tmpFile, close := makeTempFile(c, distroInfoContents)
    89  	defer close()
    90  
    91  	now := time.Date(2020, 3, 16, 0, 0, 0, 0, time.UTC)
    92  
    93  	info, err := supportedInfoForType(tmpFile.Name(), now, MustParseBaseFromString("ubuntu@10.04"), "daily")
    94  	c.Assert(err, jc.ErrorIsNil)
    95  
    96  	ctrlBases := info.controllerBases()
    97  	c.Assert(ctrlBases, jc.DeepEquals, transform.Slice([]string{"ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04"}, MustParseBaseFromString))
    98  
    99  	workloadBases := info.workloadBases(false)
   100  	c.Assert(workloadBases, jc.DeepEquals, transform.Slice([]string{
   101  		"centos@7", "centos@9", "genericlinux@genericlinux", "kubernetes@kubernetes",
   102  		"ubuntu@20.04", "ubuntu@22.04", "ubuntu@24.04",
   103  	}, MustParseBaseFromString))
   104  }
   105  
   106  var getOSFromSeriesTests = []struct {
   107  	series string
   108  	want   ostype.OSType
   109  	err    string
   110  }{{
   111  	series: "precise",
   112  	want:   ostype.Ubuntu,
   113  }, {
   114  	series: "centos7",
   115  	want:   ostype.CentOS,
   116  }, {
   117  	series: "kubernetes",
   118  	want:   ostype.Kubernetes,
   119  }, {
   120  	series: "genericlinux",
   121  	want:   ostype.GenericLinux,
   122  }, {
   123  	series: "",
   124  	err:    "series \"\" not valid",
   125  },
   126  }
   127  
   128  func (s *SupportedSeriesSuite) TestGetOSFromSeries(c *gc.C) {
   129  	for _, t := range getOSFromSeriesTests {
   130  		got, err := GetOSFromSeries(t.series)
   131  		if t.err != "" {
   132  			c.Assert(err, gc.ErrorMatches, t.err)
   133  		} else {
   134  			c.Check(err, jc.ErrorIsNil)
   135  			c.Assert(got, gc.Equals, t.want)
   136  		}
   137  	}
   138  }
   139  
   140  func (s *SupportedSeriesSuite) TestUnknownOSFromSeries(c *gc.C) {
   141  	_, err := GetOSFromSeries("Xuanhuaceratops")
   142  	c.Assert(err, jc.Satisfies, IsUnknownOSForSeriesError)
   143  	c.Assert(err, gc.ErrorMatches, `unknown OS for series: "Xuanhuaceratops"`)
   144  }
   145  
   146  func (s *SupportedSeriesSuite) TestSeriesVersionEmpty(c *gc.C) {
   147  	_, err := SeriesVersion("")
   148  	c.Assert(err, gc.ErrorMatches, `.*unknown version for series: "".*`)
   149  }
   150  
   151  func boolPtr(b bool) *bool {
   152  	return &b
   153  }
   154  
   155  func (s *SupportedSeriesSuite) TestGetBaseFromSeries(c *gc.C) {
   156  	vers, err := GetBaseFromSeries("jammy")
   157  	c.Assert(err, jc.ErrorIsNil)
   158  	c.Assert(vers, jc.DeepEquals, MakeDefaultBase("ubuntu", "22.04"))
   159  	_, err = GetBaseFromSeries("unknown")
   160  	c.Assert(err, gc.ErrorMatches, `series "unknown" not valid`)
   161  	vers, err = GetBaseFromSeries("centos7")
   162  	c.Assert(err, jc.ErrorIsNil)
   163  	c.Assert(vers, jc.DeepEquals, MakeDefaultBase("centos", "7"))
   164  }
   165  
   166  func (s *SupportedSeriesSuite) TestGetSeriesFromOSVersion(c *gc.C) {
   167  	series, err := GetSeriesFromChannel("ubuntu", "22.04")
   168  	c.Assert(err, jc.ErrorIsNil)
   169  	c.Assert(series, gc.Equals, "jammy")
   170  	_, err = GetSeriesFromChannel("bad", "22.04")
   171  	c.Assert(err, gc.ErrorMatches, `os "bad" version "22.04" not found`)
   172  	series, err = GetSeriesFromChannel("centos", "7/stable")
   173  	c.Assert(err, jc.ErrorIsNil)
   174  	c.Assert(series, gc.Equals, "centos7")
   175  }
   176  
   177  func (s *SupportedSeriesSuite) TestUbuntuVersions(c *gc.C) {
   178  	ubuntuSeries := map[SeriesName]seriesVersion{
   179  		Precise: {
   180  			WorkloadType: ControllerWorkloadType,
   181  			OS:           UbuntuOS,
   182  			Version:      "12.04",
   183  		},
   184  		Quantal: {
   185  			WorkloadType: ControllerWorkloadType,
   186  			OS:           UbuntuOS,
   187  			Version:      "12.10",
   188  		},
   189  		Raring: {
   190  			WorkloadType: ControllerWorkloadType,
   191  			OS:           UbuntuOS,
   192  			Version:      "13.04",
   193  		},
   194  		Saucy: {
   195  			WorkloadType: ControllerWorkloadType,
   196  			OS:           UbuntuOS,
   197  			Version:      "13.10",
   198  		},
   199  		Trusty: {
   200  			WorkloadType: ControllerWorkloadType,
   201  			OS:           UbuntuOS,
   202  			Version:      "14.04",
   203  			LTS:          true,
   204  			ESMSupported: true,
   205  		},
   206  		Utopic: {
   207  			WorkloadType: ControllerWorkloadType,
   208  			OS:           UbuntuOS,
   209  			Version:      "14.10",
   210  		},
   211  		Vivid: {
   212  			WorkloadType: ControllerWorkloadType,
   213  			OS:           UbuntuOS,
   214  			Version:      "15.04",
   215  		},
   216  		Wily: {
   217  			WorkloadType: ControllerWorkloadType,
   218  			OS:           UbuntuOS,
   219  			Version:      "15.10",
   220  		},
   221  		Xenial: {
   222  			WorkloadType: ControllerWorkloadType,
   223  			OS:           UbuntuOS,
   224  			Version:      "16.04",
   225  			LTS:          true,
   226  			ESMSupported: true,
   227  		},
   228  		Yakkety: {
   229  			WorkloadType: ControllerWorkloadType,
   230  			OS:           UbuntuOS,
   231  			Version:      "16.10",
   232  		},
   233  		Zesty: {
   234  			WorkloadType: ControllerWorkloadType,
   235  			OS:           UbuntuOS,
   236  			Version:      "17.04",
   237  		},
   238  		Artful: {
   239  			WorkloadType: ControllerWorkloadType,
   240  			OS:           UbuntuOS,
   241  			Version:      "17.10",
   242  		},
   243  		Bionic: {
   244  			WorkloadType: ControllerWorkloadType,
   245  			OS:           UbuntuOS,
   246  			Version:      "18.04",
   247  			LTS:          true,
   248  			ESMSupported: true,
   249  		},
   250  		Cosmic: {
   251  			WorkloadType: ControllerWorkloadType,
   252  			OS:           UbuntuOS,
   253  			Version:      "18.10",
   254  		},
   255  		Disco: {
   256  			WorkloadType: ControllerWorkloadType,
   257  			OS:           UbuntuOS,
   258  			Version:      "19.04",
   259  		},
   260  		Eoan: {
   261  			WorkloadType: ControllerWorkloadType,
   262  			OS:           UbuntuOS,
   263  			Version:      "19.10",
   264  		},
   265  		Focal: {
   266  			WorkloadType: ControllerWorkloadType,
   267  			OS:           UbuntuOS,
   268  			Version:      "20.04",
   269  			LTS:          true,
   270  			Supported:    true,
   271  			ESMSupported: true,
   272  		},
   273  		Groovy: {
   274  			WorkloadType: ControllerWorkloadType,
   275  			OS:           UbuntuOS,
   276  			Version:      "20.10",
   277  		},
   278  		Hirsute: {
   279  			WorkloadType: ControllerWorkloadType,
   280  			OS:           UbuntuOS,
   281  			Version:      "21.04",
   282  		},
   283  		Impish: {
   284  			WorkloadType: ControllerWorkloadType,
   285  			OS:           UbuntuOS,
   286  			Version:      "21.10",
   287  		},
   288  		Jammy: {
   289  			WorkloadType: ControllerWorkloadType,
   290  			OS:           UbuntuOS,
   291  			Version:      "22.04",
   292  			LTS:          true,
   293  			Supported:    true,
   294  			ESMSupported: true,
   295  		},
   296  		Kinetic: {
   297  			WorkloadType: ControllerWorkloadType,
   298  			OS:           UbuntuOS,
   299  			Version:      "22.10",
   300  		},
   301  		Lunar: {
   302  			WorkloadType: ControllerWorkloadType,
   303  			OS:           UbuntuOS,
   304  			Version:      "23.04",
   305  		},
   306  		Mantic: {
   307  			WorkloadType: ControllerWorkloadType,
   308  			OS:           UbuntuOS,
   309  			Version:      "23.10",
   310  		},
   311  		Noble: {
   312  			WorkloadType: ControllerWorkloadType,
   313  			OS:           UbuntuOS,
   314  			Version:      "24.04",
   315  			LTS:          true,
   316  			ESMSupported: true,
   317  		},
   318  	}
   319  
   320  	result := ubuntuVersions(nil, nil, ubuntuSeries)
   321  	c.Check(result, gc.DeepEquals, map[string]string{"artful": "17.10", "bionic": "18.04", "cosmic": "18.10", "disco": "19.04", "eoan": "19.10", "focal": "20.04", "groovy": "20.10", "hirsute": "21.04", "impish": "21.10", "jammy": "22.04", "kinetic": "22.10", "lunar": "23.04", "mantic": "23.10", "noble": "24.04", "precise": "12.04", "quantal": "12.10", "raring": "13.04", "saucy": "13.10", "trusty": "14.04", "utopic": "14.10", "vivid": "15.04", "wily": "15.10", "xenial": "16.04", "yakkety": "16.10", "zesty": "17.04"})
   322  
   323  	result = ubuntuVersions(boolPtr(true), boolPtr(true), ubuntuSeries)
   324  	c.Check(result, gc.DeepEquals, map[string]string{"focal": "20.04", "jammy": "22.04"})
   325  
   326  	result = ubuntuVersions(boolPtr(false), boolPtr(false), ubuntuSeries)
   327  	c.Check(result, gc.DeepEquals, map[string]string{"artful": "17.10", "cosmic": "18.10", "disco": "19.04", "eoan": "19.10", "groovy": "20.10", "hirsute": "21.04", "impish": "21.10", "kinetic": "22.10", "lunar": "23.04", "mantic": "23.10", "precise": "12.04", "quantal": "12.10", "raring": "13.04", "saucy": "13.10", "utopic": "14.10", "vivid": "15.04", "wily": "15.10", "yakkety": "16.10", "zesty": "17.04"})
   328  
   329  	result = ubuntuVersions(boolPtr(true), boolPtr(false), ubuntuSeries)
   330  	c.Check(result, gc.DeepEquals, map[string]string{})
   331  
   332  	result = ubuntuVersions(boolPtr(false), boolPtr(true), ubuntuSeries)
   333  	c.Check(result, gc.DeepEquals, map[string]string{"bionic": "18.04", "noble": "24.04", "trusty": "14.04", "xenial": "16.04"})
   334  
   335  	result = ubuntuVersions(boolPtr(true), nil, ubuntuSeries)
   336  	c.Check(result, gc.DeepEquals, map[string]string{"focal": "20.04", "jammy": "22.04"})
   337  
   338  	result = ubuntuVersions(boolPtr(false), nil, ubuntuSeries)
   339  	c.Check(result, gc.DeepEquals, map[string]string{"artful": "17.10", "bionic": "18.04", "cosmic": "18.10", "disco": "19.04", "eoan": "19.10", "groovy": "20.10", "hirsute": "21.04", "impish": "21.10", "kinetic": "22.10", "lunar": "23.04", "mantic": "23.10", "noble": "24.04", "precise": "12.04", "quantal": "12.10", "raring": "13.04", "saucy": "13.10", "trusty": "14.04", "utopic": "14.10", "vivid": "15.04", "wily": "15.10", "xenial": "16.04", "yakkety": "16.10", "zesty": "17.04"})
   340  
   341  	result = ubuntuVersions(nil, boolPtr(true), ubuntuSeries)
   342  	c.Check(result, gc.DeepEquals, map[string]string{"bionic": "18.04", "focal": "20.04", "jammy": "22.04", "noble": "24.04", "trusty": "14.04", "xenial": "16.04"})
   343  
   344  	result = ubuntuVersions(nil, boolPtr(false), ubuntuSeries)
   345  	c.Check(result, gc.DeepEquals, map[string]string{"artful": "17.10", "cosmic": "18.10", "disco": "19.04", "eoan": "19.10", "groovy": "20.10", "hirsute": "21.04", "impish": "21.10", "kinetic": "22.10", "lunar": "23.04", "mantic": "23.10", "precise": "12.04", "quantal": "12.10", "raring": "13.04", "saucy": "13.10", "utopic": "14.10", "vivid": "15.04", "wily": "15.10", "yakkety": "16.10", "zesty": "17.04"})
   346  }
   347  
   348  func makeTempFile(c *gc.C, content string) (*os.File, func()) {
   349  	tmpfile, err := os.CreateTemp("", "distroinfo")
   350  	if err != nil {
   351  		c.Assert(err, jc.ErrorIsNil)
   352  	}
   353  
   354  	_, err = tmpfile.Write([]byte(content))
   355  	c.Assert(err, jc.ErrorIsNil)
   356  
   357  	// Reset the file for reading.
   358  	_, err = tmpfile.Seek(0, 0)
   359  	c.Assert(err, jc.ErrorIsNil)
   360  
   361  	return tmpfile, func() {
   362  		err := os.Remove(tmpfile.Name())
   363  		c.Assert(err, jc.ErrorIsNil)
   364  	}
   365  }