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 }