github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/ec2/image_test.go (about)

     1  // Copyright 2011, 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package ec2
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/os/series"
    10  	jc "github.com/juju/testing/checkers"
    11  	gc "gopkg.in/check.v1"
    12  
    13  	"github.com/juju/juju/core/constraints"
    14  	"github.com/juju/juju/environs/imagemetadata"
    15  	"github.com/juju/juju/environs/instances"
    16  	"github.com/juju/juju/juju/version"
    17  	"github.com/juju/juju/provider/ec2/internal/ec2instancetypes"
    18  	"github.com/juju/juju/testing"
    19  )
    20  
    21  var _ = gc.Suite(&specSuite{})
    22  
    23  type specSuite struct {
    24  	testing.BaseSuite
    25  }
    26  
    27  var findInstanceSpecTests = []struct {
    28  	// LTS-dependent requires new or updated entries upon a new LTS release.
    29  	series  string
    30  	arches  []string
    31  	cons    string
    32  	itype   string
    33  	image   string
    34  	storage []string
    35  }{
    36  	{
    37  		series: "xenial",
    38  		arches: []string{"amd64"},
    39  		itype:  "t3.micro",
    40  		image:  "ami-00000133",
    41  	}, {
    42  		series: "quantal",
    43  		arches: []string{"amd64"},
    44  		itype:  "t3.micro",
    45  		image:  "ami-01000035",
    46  	}, {
    47  		series: "xenial",
    48  		arches: []string{"amd64"},
    49  		cons:   "cores=4",
    50  		itype:  "t3.xlarge",
    51  		image:  "ami-00000133",
    52  	}, {
    53  		series: "bionic",
    54  		arches: []string{"arm64"},
    55  		cons:   "cores=4",
    56  		itype:  "a1.xlarge",
    57  		image:  "ami-00002133",
    58  	}, {
    59  		series: "xenial",
    60  		arches: []string{"amd64"},
    61  		cons:   "mem=10G",
    62  		itype:  "r5a.large",
    63  		image:  "ami-00000133",
    64  	}, {
    65  		series: "xenial",
    66  		arches: []string{"amd64"},
    67  		cons:   "mem=",
    68  		itype:  "t3.nano",
    69  		image:  "ami-00000133",
    70  	}, {
    71  		series: "xenial",
    72  		arches: []string{"amd64"},
    73  		cons:   "cpu-power=",
    74  		itype:  "t3.micro",
    75  		image:  "ami-00000133",
    76  	}, {
    77  		series: "xenial",
    78  		arches: []string{"amd64"},
    79  		cons:   "cpu-power=800",
    80  		itype:  "c5.large",
    81  		image:  "ami-00000133",
    82  	}, {
    83  		series: "xenial",
    84  		arches: []string{"amd64"},
    85  		cons:   "instance-type=m1.medium cpu-power=100",
    86  		itype:  "m1.medium",
    87  		image:  "ami-00000135",
    88  	}, {
    89  		series: "xenial",
    90  		arches: []string{"amd64"},
    91  		cons:   "mem=2G root-disk=16384M",
    92  		itype:  "t3.small",
    93  		image:  "ami-00000133",
    94  	}, {
    95  		series:  "xenial",
    96  		arches:  []string{"amd64"},
    97  		cons:    "mem=4G root-disk=16384M",
    98  		itype:   "t3.medium",
    99  		storage: []string{"ssd", "ebs"},
   100  		image:   "ami-00000133",
   101  	}, {
   102  		series:  "xenial",
   103  		arches:  []string{"amd64"},
   104  		cons:    "mem=4G root-disk=16384M",
   105  		itype:   "t3.medium",
   106  		storage: []string{"ebs", "ssd"},
   107  		image:   "ami-00000139",
   108  	}, {
   109  		series:  "xenial",
   110  		arches:  []string{"amd64"},
   111  		cons:    "mem=4G root-disk=16384M",
   112  		itype:   "t3.medium",
   113  		storage: []string{"ebs"},
   114  		image:   "ami-00000139",
   115  	}, {
   116  		series: "trusty",
   117  		arches: []string{"amd64"},
   118  		itype:  "t3.micro",
   119  		image:  "ami-00000033",
   120  	}, {
   121  		series: "trusty",
   122  		arches: []string{"i386"},
   123  		cons:   "instance-type=c1.medium",
   124  		itype:  "c1.medium",
   125  		image:  "ami-00000034",
   126  	}, {
   127  		series: "bionic",
   128  		arches: []string{"amd64", "i386"},
   129  		cons:   "arch=amd64",
   130  		itype:  "t3.micro",
   131  		image:  "ami-00001133",
   132  	}, {
   133  		series: "bionic",
   134  		arches: []string{"amd64", "i386"},
   135  		cons:   "instance-type=cc2.8xlarge",
   136  		itype:  "cc2.8xlarge",
   137  		image:  "ami-00001133",
   138  	},
   139  }
   140  
   141  func (s *specSuite) TestFindInstanceSpec(c *gc.C) {
   142  	size := len(findInstanceSpecTests)
   143  	for i, test := range findInstanceSpecTests {
   144  		c.Logf("\ntest %d of %d: %q; %q; %q; %q; %q; %v", i+1, size,
   145  			test.series, test.arches, test.cons, test.itype, test.image,
   146  			test.storage)
   147  		stor := test.storage
   148  		if len(stor) == 0 {
   149  			stor = []string{ssdStorage, ebsStorage}
   150  		}
   151  		// We need to filter the image metadata to the test's
   152  		// arches and series; the provisioner and bootstrap
   153  		// code will do this.
   154  		imageMetadata := filterImageMetadata(
   155  			c, TestImageMetadata, test.series, test.arches,
   156  		)
   157  		spec, err := findInstanceSpec(
   158  			false, // non-controller
   159  			imageMetadata,
   160  			ec2instancetypes.RegionInstanceTypes("test"),
   161  			&instances.InstanceConstraint{
   162  				Region:      "test",
   163  				Series:      test.series,
   164  				Arches:      test.arches,
   165  				Constraints: constraints.MustParse(test.cons),
   166  				Storage:     stor,
   167  			})
   168  		c.Assert(err, jc.ErrorIsNil)
   169  		c.Check(spec.InstanceType.Name, gc.Equals, test.itype)
   170  		c.Check(spec.Image.Id, gc.Equals, test.image)
   171  	}
   172  }
   173  
   174  func (s *specSuite) TestFindInstanceSpecNotSetCpuPowerWhenInstanceTypeSet(c *gc.C) {
   175  
   176  	instanceConstraint := &instances.InstanceConstraint{
   177  		Region:      "test",
   178  		Series:      version.SupportedLTS(),
   179  		Constraints: constraints.MustParse("instance-type=t2.medium"),
   180  	}
   181  
   182  	c.Check(instanceConstraint.Constraints.CpuPower, gc.IsNil)
   183  	findInstanceSpec(
   184  		false, // non-controller
   185  		TestImageMetadata,
   186  		ec2instancetypes.RegionInstanceTypes("test"),
   187  		instanceConstraint,
   188  	)
   189  
   190  	c.Check(instanceConstraint.Constraints.CpuPower, gc.IsNil)
   191  }
   192  
   193  var findInstanceSpecErrorTests = []struct {
   194  	series string
   195  	arches []string
   196  	cons   string
   197  	err    string
   198  }{
   199  	{
   200  		series: version.SupportedLTS(),
   201  		arches: []string{"arm"},
   202  		err:    fmt.Sprintf(`no "%s" images in test with arches \[arm\]`, version.SupportedLTS()),
   203  	}, {
   204  		series: "raring",
   205  		arches: []string{"amd64", "i386"},
   206  		cons:   "mem=4G",
   207  		err:    `no "raring" images in test matching instance types \[.*\]`,
   208  	}, {
   209  		series: version.SupportedLTS(),
   210  		arches: []string{"amd64"},
   211  		cons:   "instance-type=m1.small mem=4G",
   212  		err:    `no instance types in test matching constraints "instance-type=m1.small mem=4096M"`,
   213  	},
   214  }
   215  
   216  func (s *specSuite) TestFindInstanceSpecErrors(c *gc.C) {
   217  	for i, t := range findInstanceSpecErrorTests {
   218  		c.Logf("test %d", i)
   219  		// We need to filter the image metadata to the test's
   220  		// arches and series; the provisioner and bootstrap
   221  		// code will do this.
   222  		imageMetadata := filterImageMetadata(
   223  			c, TestImageMetadata, t.series, t.arches,
   224  		)
   225  		_, err := findInstanceSpec(
   226  			false, // non-controller
   227  			imageMetadata,
   228  			ec2instancetypes.RegionInstanceTypes("test"),
   229  			&instances.InstanceConstraint{
   230  				Region:      "test",
   231  				Series:      t.series,
   232  				Arches:      t.arches,
   233  				Constraints: constraints.MustParse(t.cons),
   234  			})
   235  		c.Check(err, gc.ErrorMatches, t.err)
   236  	}
   237  }
   238  
   239  func filterImageMetadata(
   240  	c *gc.C,
   241  	in []*imagemetadata.ImageMetadata,
   242  	filterSeries string, filterArches []string,
   243  ) []*imagemetadata.ImageMetadata {
   244  	var imageMetadata []*imagemetadata.ImageMetadata
   245  	for _, im := range in {
   246  		version, err := series.SeriesVersion(filterSeries)
   247  		c.Assert(err, jc.ErrorIsNil)
   248  		if im.Version != version {
   249  			continue
   250  		}
   251  		match := false
   252  		for _, arch := range filterArches {
   253  			match = match || im.Arch == arch
   254  		}
   255  		if match {
   256  			imageMetadata = append(imageMetadata, im)
   257  		}
   258  	}
   259  	return imageMetadata
   260  }
   261  
   262  func (*specSuite) TestFilterImagesAcceptsNil(c *gc.C) {
   263  	c.Check(filterImages(nil, nil), gc.HasLen, 0)
   264  }
   265  
   266  func (*specSuite) TestFilterImagesReturnsSelectively(c *gc.C) {
   267  	good := imagemetadata.ImageMetadata{Id: "good", Storage: "ebs"}
   268  	bad := imagemetadata.ImageMetadata{Id: "bad", Storage: "ftp"}
   269  	input := []*imagemetadata.ImageMetadata{&good, &bad}
   270  	expectation := []*imagemetadata.ImageMetadata{&good}
   271  
   272  	ic := &instances.InstanceConstraint{Storage: []string{"ebs"}}
   273  	c.Check(filterImages(input, ic), gc.DeepEquals, expectation)
   274  }
   275  
   276  func (*specSuite) TestFilterImagesMaintainsOrdering(c *gc.C) {
   277  	input := []*imagemetadata.ImageMetadata{
   278  		{Id: "one", Storage: "ebs"},
   279  		{Id: "two", Storage: "ebs"},
   280  		{Id: "three", Storage: "ebs"},
   281  	}
   282  	ic := &instances.InstanceConstraint{Storage: []string{"ebs"}}
   283  	c.Check(filterImages(input, ic), gc.DeepEquals, input)
   284  }