github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/oci/images_test.go (about) 1 // Copyright 2018 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package oci_test 5 6 import ( 7 "context" 8 "time" 9 10 gomock "github.com/golang/mock/gomock" 11 "github.com/juju/errors" 12 ocitesting "github.com/juju/juju/provider/oci/testing" 13 jujutesting "github.com/juju/juju/testing" 14 jc "github.com/juju/testing/checkers" 15 gc "gopkg.in/check.v1" 16 17 ociCore "github.com/oracle/oci-go-sdk/core" 18 19 "github.com/juju/juju/provider/oci" 20 ) 21 22 type imagesSuite struct { 23 jujutesting.BaseSuite 24 25 testImageID string 26 testCompartment string 27 } 28 29 var _ = gc.Suite(&imagesSuite{}) 30 31 func (i *imagesSuite) SetUpTest(c *gc.C) { 32 i.BaseSuite.SetUpTest(c) 33 oci.SetImageCache(&oci.ImageCache{}) 34 35 i.testImageID = "ocid1.image.oc1.phx.aaaaaaaaa5mikpf5fktj4x47bx4p4ak4g5jyuyukkxpdg4nll36qzqwjzd2q" 36 i.testCompartment = "ocid1.compartment.oc1..aaaaaaaaakr75vvb5yx4nkm7ag7ekvluap7afa2y4zprswuprcnehqecwqga" 37 } 38 39 func (i *imagesSuite) TestNewImageVersion(c *gc.C) { 40 name := "Canonical-Ubuntu-14.04-2017.08.22-0" 41 img := ociCore.Image{ 42 DisplayName: &name, 43 } 44 timeStamp, _ := time.Parse("2006.01.02", "2017.08.22") 45 version, err := oci.NewImageVersion(img) 46 c.Assert(err, gc.IsNil) 47 c.Assert(version.TimeStamp, gc.Equals, timeStamp) 48 c.Assert(version.Revision, gc.Equals, 0) 49 } 50 51 func (i *imagesSuite) TestNewImageVersionInvalidDate(c *gc.C) { 52 name := "Canonical-Ubuntu-14.04-NotARealDate-0" 53 img := ociCore.Image{ 54 DisplayName: &name, 55 } 56 _, err := oci.NewImageVersion(img) 57 c.Assert(err, gc.ErrorMatches, "parsing time for.*") 58 } 59 60 func (i *imagesSuite) TestNewImageVersionInvalidRevision(c *gc.C) { 61 name := "Canonical-Ubuntu-14.04-2017.08.22-IShouldBeNumeric" 62 img := ociCore.Image{ 63 DisplayName: &name, 64 } 65 _, err := oci.NewImageVersion(img) 66 c.Assert(err, gc.ErrorMatches, "parsing revision for.*") 67 } 68 69 func (i *imagesSuite) TestNewImageVersionInvalidName(c *gc.C) { 70 name := "fakeInvalidName" 71 img := ociCore.Image{ 72 DisplayName: &name, 73 } 74 _, err := oci.NewImageVersion(img) 75 c.Assert(err, gc.ErrorMatches, "invalid image display name.*") 76 77 img = ociCore.Image{} 78 _, err = oci.NewImageVersion(img) 79 c.Assert(err, gc.ErrorMatches, "image does not have a display name") 80 } 81 82 func makeStringPointer(name string) *string { 83 return &name 84 } 85 86 func makeIntPointer(name int) *int { 87 return &name 88 } 89 90 func (i *imagesSuite) TestInstanceTypes(c *gc.C) { 91 ctrl := gomock.NewController(c) 92 compute := ocitesting.NewMockOCIComputeClient(ctrl) 93 defer ctrl.Finish() 94 95 request := ociCore.ListShapesRequest{ 96 CompartmentId: &i.testCompartment, 97 ImageId: &i.testImageID, 98 } 99 100 response := ociCore.ListShapesResponse{ 101 Items: []ociCore.Shape{ 102 { 103 Shape: makeStringPointer("VM.Standard1.1"), 104 }, 105 { 106 Shape: makeStringPointer("VM.Standard2.1"), 107 }, 108 { 109 Shape: makeStringPointer("VM.Standard1.2"), 110 }, 111 }, 112 } 113 114 compute.EXPECT().ListShapes(context.Background(), request).Return(response, nil) 115 116 types, err := oci.InstanceTypes(compute, &i.testCompartment, &i.testImageID) 117 c.Assert(err, gc.IsNil) 118 c.Check(types, gc.HasLen, 3) 119 120 spec, ok := oci.ShapeSpecs["VM.Standard1.1"] 121 c.Assert(ok, jc.IsTrue) 122 c.Check(int(types[0].Mem), gc.Equals, spec.Memory) 123 c.Check(int(types[0].CpuCores), gc.Equals, spec.Cpus) 124 125 spec, ok = oci.ShapeSpecs["VM.Standard2.1"] 126 c.Assert(ok, jc.IsTrue) 127 c.Check(int(types[1].Mem), gc.Equals, spec.Memory) 128 c.Check(int(types[1].CpuCores), gc.Equals, spec.Cpus) 129 130 spec, ok = oci.ShapeSpecs["VM.Standard1.2"] 131 c.Assert(ok, jc.IsTrue) 132 c.Check(int(types[2].Mem), gc.Equals, spec.Memory) 133 c.Check(int(types[2].CpuCores), gc.Equals, spec.Cpus) 134 } 135 136 func (i *imagesSuite) TestInstanceTypesNilClient(c *gc.C) { 137 _, err := oci.InstanceTypes(nil, &i.testCompartment, &i.testImageID) 138 c.Assert(err, gc.ErrorMatches, "cannot use nil client") 139 } 140 141 func (i *imagesSuite) TestInstanceTypesImageWithUnknownShape(c *gc.C) { 142 ctrl := gomock.NewController(c) 143 compute := ocitesting.NewMockOCIComputeClient(ctrl) 144 defer ctrl.Finish() 145 146 request := ociCore.ListShapesRequest{ 147 CompartmentId: &i.testCompartment, 148 ImageId: &i.testImageID, 149 } 150 151 response := ociCore.ListShapesResponse{ 152 Items: []ociCore.Shape{ 153 { 154 Shape: makeStringPointer("IDontExistInTheOCIProviderWasProbablyAddedLaterAndThatsWhyIHopeTheyWillAddResourceDetailsToShapesAPISoWeDontNeedToMaintainAMapping"), 155 }, 156 { 157 Shape: makeStringPointer("VM.Standard2.1"), 158 }, 159 { 160 Shape: makeStringPointer("VM.Standard1.2"), 161 }, 162 }, 163 } 164 165 compute.EXPECT().ListShapes(context.Background(), request).Return(response, nil) 166 167 types, err := oci.InstanceTypes(compute, &i.testCompartment, &i.testImageID) 168 c.Assert(err, gc.IsNil) 169 c.Check(types, gc.HasLen, 2) 170 } 171 172 func (i *imagesSuite) TestNewInstanceImage(c *gc.C) { 173 image := ociCore.Image{ 174 CompartmentId: &i.testCompartment, 175 Id: &i.testImageID, 176 OperatingSystem: makeStringPointer("Canonical Ubuntu"), 177 OperatingSystemVersion: makeStringPointer("14.04"), 178 DisplayName: makeStringPointer("Canonical-Ubuntu-14.04-2018.01.11-0"), 179 } 180 181 imgType, err := oci.NewInstanceImage(image, &i.testCompartment) 182 c.Assert(err, gc.IsNil) 183 c.Check(imgType.ImageType, gc.Equals, oci.ImageTypeGeneric) 184 c.Check(imgType.Series, gc.Equals, "trusty") 185 c.Check(imgType.CompartmentId, gc.NotNil) 186 c.Check(*imgType.CompartmentId, gc.Equals, i.testCompartment) 187 c.Check(imgType.Id, gc.Equals, i.testImageID) 188 } 189 190 func (i *imagesSuite) TestNewInstanceImageUnknownOS(c *gc.C) { 191 image := ociCore.Image{ 192 CompartmentId: &i.testCompartment, 193 Id: &i.testImageID, 194 OperatingSystem: makeStringPointer("NotKnownToJuju"), 195 OperatingSystemVersion: makeStringPointer("14.04"), 196 DisplayName: makeStringPointer("Canonical-Ubuntu-14.04-2018.01.11-0"), 197 } 198 199 _, err := oci.NewInstanceImage(image, &i.testCompartment) 200 c.Assert(err, gc.ErrorMatches, "os NotKnownToJuju not supported") 201 } 202 203 func (i *imagesSuite) TestRefreshImageCache(c *gc.C) { 204 ctrl := gomock.NewController(c) 205 compute := ocitesting.NewMockOCIComputeClient(ctrl) 206 defer ctrl.Finish() 207 208 fakeUbuntuID := "fakeUbuntu1" 209 fakeUbuntuIDSecond := "fakeUbuntu2" 210 211 listImageRequest, listImageResponse := makeListImageRequestResponse( 212 []ociCore.Image{ 213 { 214 CompartmentId: &i.testCompartment, 215 Id: &fakeUbuntuID, 216 OperatingSystem: makeStringPointer("Canonical Ubuntu"), 217 OperatingSystemVersion: makeStringPointer("14.04"), 218 DisplayName: makeStringPointer("Canonical-Ubuntu-14.04-2018.01.11-0"), 219 }, 220 { 221 CompartmentId: &i.testCompartment, 222 Id: &fakeUbuntuIDSecond, 223 OperatingSystem: makeStringPointer("Canonical Ubuntu"), 224 OperatingSystemVersion: makeStringPointer("14.04"), 225 DisplayName: makeStringPointer("Canonical-Ubuntu-14.04-2018.01.12-0"), 226 }, 227 { 228 CompartmentId: &i.testCompartment, 229 Id: makeStringPointer("fakeCentOS"), 230 OperatingSystem: makeStringPointer("CentOS"), 231 OperatingSystemVersion: makeStringPointer("7"), 232 DisplayName: makeStringPointer("CentOS-7-2017.10.19-0"), 233 }, 234 }, 235 ) 236 shapesRequestUbuntu, shapesResponseUbuntu := makeShapesRequestResponse( 237 i.testCompartment, fakeUbuntuID, []string{"VM.Standard2.1", "VM.Standard1.2"}) 238 239 shapesRequestUbuntuSecond := ociCore.ListShapesRequest{ 240 CompartmentId: &i.testCompartment, 241 ImageId: &fakeUbuntuIDSecond, 242 } 243 244 shapesRequestCentOS, shapesResponseCentOS := makeShapesRequestResponse( 245 i.testCompartment, "fakeCentOS", []string{"VM.Standard1.2"}) 246 247 gomock.InOrder( 248 compute.EXPECT().ListImages(context.Background(), listImageRequest).Return(listImageResponse, nil), 249 compute.EXPECT().ListShapes(context.Background(), shapesRequestUbuntu).Return(shapesResponseUbuntu, nil), 250 compute.EXPECT().ListShapes(context.Background(), shapesRequestUbuntuSecond).Return(shapesResponseUbuntu, nil), 251 compute.EXPECT().ListShapes(context.Background(), shapesRequestCentOS).Return(shapesResponseCentOS, nil), 252 ) 253 254 imgCache, err := oci.RefreshImageCache(compute, &i.testCompartment) 255 c.Assert(err, gc.IsNil) 256 c.Assert(imgCache, gc.NotNil) 257 c.Check(imgCache.ImageMap(), gc.HasLen, 2) 258 259 imageMap := imgCache.ImageMap() 260 c.Check(imageMap["trusty"], gc.HasLen, 2) 261 c.Check(imageMap["centos7"], gc.HasLen, 1) 262 263 timeStamp, _ := time.Parse("2006.01.02", "2018.01.12") 264 265 // Check that the first image in the array is the newest one 266 c.Assert(imageMap["trusty"][0].Version.TimeStamp, gc.Equals, timeStamp) 267 268 // Check that InstanceTypes are set 269 c.Assert(imageMap["trusty"][0].InstanceTypes, gc.HasLen, 2) 270 c.Assert(imageMap["centos7"][0].InstanceTypes, gc.HasLen, 1) 271 } 272 273 func (i *imagesSuite) TestRefreshImageCacheFetchFromCache(c *gc.C) { 274 ctrl := gomock.NewController(c) 275 compute := ocitesting.NewMockOCIComputeClient(ctrl) 276 defer ctrl.Finish() 277 278 compute.EXPECT().ListImages(gomock.Any(), gomock.Any()).Return(ociCore.ListImagesResponse{}, nil) 279 280 imgCache, err := oci.RefreshImageCache(compute, &i.testCompartment) 281 c.Assert(err, gc.IsNil) 282 c.Assert(imgCache, gc.NotNil) 283 284 fromCache, err := oci.RefreshImageCache(compute, &i.testCompartment) 285 c.Assert(err, gc.IsNil) 286 c.Check(imgCache, gc.DeepEquals, fromCache) 287 } 288 289 func (i *imagesSuite) TestRefreshImageCacheStaleCache(c *gc.C) { 290 ctrl := gomock.NewController(c) 291 compute := ocitesting.NewMockOCIComputeClient(ctrl) 292 defer ctrl.Finish() 293 294 compute.EXPECT().ListImages(gomock.Any(), gomock.Any()).Return(ociCore.ListImagesResponse{}, nil).Times(2) 295 296 imgCache, err := oci.RefreshImageCache(compute, &i.testCompartment) 297 c.Assert(err, gc.IsNil) 298 c.Assert(imgCache, gc.NotNil) 299 300 now := time.Now() 301 302 // No need to check the value. gomock will assert if ListImages 303 // is not called twice 304 imgCache.SetLastRefresh(now.Add(-31 * time.Minute)) 305 _, err = oci.RefreshImageCache(compute, &i.testCompartment) 306 c.Assert(err, gc.IsNil) 307 } 308 309 func (i *imagesSuite) TestRefreshImageCacheWithInvalidImage(c *gc.C) { 310 ctrl := gomock.NewController(c) 311 compute := ocitesting.NewMockOCIComputeClient(ctrl) 312 defer ctrl.Finish() 313 314 listImageRequest, listImageResponse := makeListImageRequestResponse( 315 []ociCore.Image{ 316 { 317 CompartmentId: &i.testCompartment, 318 Id: makeStringPointer("fakeUbuntu1"), 319 OperatingSystem: makeStringPointer("Canonical Ubuntu"), 320 OperatingSystemVersion: makeStringPointer("14.04"), 321 DisplayName: makeStringPointer("Canonical-Ubuntu-14.04-2018.01.11-0"), 322 }, 323 { 324 CompartmentId: &i.testCompartment, 325 Id: makeStringPointer("fake image id for bad image"), 326 OperatingSystem: makeStringPointer("CentOS"), 327 OperatingSystemVersion: makeStringPointer("7"), 328 DisplayName: makeStringPointer("BadlyFormatedDisplayName_IshouldBeIgnored"), 329 }, 330 }, 331 ) 332 333 shapesRequestUbuntu, shapesResponseUbuntu := makeShapesRequestResponse( 334 i.testCompartment, "fakeUbuntu1", []string{"VM.Standard2.1", "VM.Standard1.2"}) 335 336 shapesRequestBadImage, shapesResponseBadImage := makeShapesRequestResponse( 337 i.testCompartment, "fake image id for bad image", []string{"VM.Standard1.2"}) 338 339 gomock.InOrder( 340 compute.EXPECT().ListImages(context.Background(), listImageRequest).Return(listImageResponse, nil), 341 compute.EXPECT().ListShapes(context.Background(), shapesRequestUbuntu).Return(shapesResponseUbuntu, nil), 342 compute.EXPECT().ListShapes(context.Background(), shapesRequestBadImage).Return(shapesResponseBadImage, nil), 343 ) 344 345 imgCache, err := oci.RefreshImageCache(compute, &i.testCompartment) 346 c.Assert(err, gc.IsNil) 347 c.Assert(imgCache, gc.NotNil) 348 c.Check(imgCache.ImageMap(), gc.HasLen, 1) 349 imageMap := imgCache.ImageMap() 350 351 c.Check(imageMap["trusty"][0].Id, gc.Equals, "fakeUbuntu1") 352 } 353 354 func (i *imagesSuite) TestRefreshImageCacheWithAPIError(c *gc.C) { 355 ctrl := gomock.NewController(c) 356 compute := ocitesting.NewMockOCIComputeClient(ctrl) 357 defer ctrl.Finish() 358 359 compute.EXPECT().ListImages(gomock.Any(), gomock.Any()).Return(ociCore.ListImagesResponse{}, errors.Errorf("awww snap!")) 360 _, err := oci.RefreshImageCache(compute, &i.testCompartment) 361 c.Assert(err, gc.ErrorMatches, "listing provider images.*awww snap!") 362 } 363 364 func (i *imagesSuite) TestImageMetadataFromCache(c *gc.C) { 365 image := ociCore.Image{ 366 CompartmentId: &i.testCompartment, 367 Id: &i.testImageID, 368 OperatingSystem: makeStringPointer("Canonical Ubuntu"), 369 OperatingSystemVersion: makeStringPointer("14.04"), 370 DisplayName: makeStringPointer("Canonical-Ubuntu-14.04-2018.01.11-0"), 371 } 372 373 imgType, err := oci.NewInstanceImage(image, &i.testCompartment) 374 c.Assert(err, gc.IsNil) 375 376 cache := &oci.ImageCache{} 377 images := map[string][]oci.InstanceImage{ 378 "trusty": { 379 imgType, 380 }, 381 } 382 cache.SetImages(images) 383 metadata := cache.ImageMetadata("trusty", "") 384 c.Assert(metadata, gc.HasLen, 1) 385 // generic images default to ImageTypeVM 386 c.Assert(metadata[0].VirtType, gc.Equals, string(oci.ImageTypeVM)) 387 388 // explicitly set ImageTypeBM on generic images 389 metadata = cache.ImageMetadata("trusty", string(oci.ImageTypeBM)) 390 c.Assert(metadata, gc.HasLen, 1) 391 c.Assert(metadata[0].VirtType, gc.Equals, string(oci.ImageTypeBM)) 392 } 393 394 func (i *imagesSuite) TestImageMetadataSpecificImageType(c *gc.C) { 395 image := ociCore.Image{ 396 CompartmentId: &i.testCompartment, 397 Id: &i.testImageID, 398 OperatingSystem: makeStringPointer("Canonical Ubuntu"), 399 OperatingSystemVersion: makeStringPointer("14.04"), 400 DisplayName: makeStringPointer("Canonical-Ubuntu-14.04-Gen2-GPU-2018.01.11-0"), 401 } 402 403 imgType, err := oci.NewInstanceImage(image, &i.testCompartment) 404 c.Assert(err, gc.IsNil) 405 406 cache := &oci.ImageCache{} 407 images := map[string][]oci.InstanceImage{ 408 "trusty": { 409 imgType, 410 }, 411 } 412 cache.SetImages(images) 413 metadata := cache.ImageMetadata("trusty", "") 414 c.Assert(metadata, gc.HasLen, 1) 415 // generic images default to ImageTypeVM 416 c.Assert(metadata[0].VirtType, gc.Equals, string(oci.ImageTypeGPU)) 417 418 // explicitly set ImageTypeBM on generic images 419 metadata = cache.ImageMetadata("trusty", string(oci.ImageTypeBM)) 420 c.Assert(metadata, gc.HasLen, 1) 421 c.Assert(metadata[0].VirtType, gc.Equals, string(oci.ImageTypeGPU)) 422 }