github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/provider/gce/disks_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package gce_test 5 6 import ( 7 "github.com/juju/names/v5" 8 jc "github.com/juju/testing/checkers" 9 gc "gopkg.in/check.v1" 10 11 "github.com/juju/juju/core/instance" 12 "github.com/juju/juju/provider/gce" 13 "github.com/juju/juju/provider/gce/google" 14 "github.com/juju/juju/storage" 15 ) 16 17 type storageProviderSuite struct { 18 gce.BaseSuite 19 provider storage.Provider 20 } 21 22 var _ = gc.Suite(&storageProviderSuite{}) 23 24 func (s *storageProviderSuite) SetUpTest(c *gc.C) { 25 s.BaseSuite.SetUpTest(c) 26 27 var err error 28 s.provider, err = s.Env.StorageProvider("gce") 29 c.Assert(err, jc.ErrorIsNil) 30 } 31 32 func (s *storageProviderSuite) TestValidateConfig(c *gc.C) { 33 // ValidateConfig performs no validation at all yet, this test 34 // it is just here to make sure that the placeholder will 35 // accept a config. 36 cfg := &storage.Config{} 37 err := s.provider.ValidateConfig(cfg) 38 c.Check(err, jc.ErrorIsNil) 39 } 40 41 func (s *storageProviderSuite) TestBlockStorageSupport(c *gc.C) { 42 supports := s.provider.Supports(storage.StorageKindBlock) 43 c.Check(supports, jc.IsTrue) 44 } 45 46 func (s *storageProviderSuite) TestFSStorageSupport(c *gc.C) { 47 supports := s.provider.Supports(storage.StorageKindFilesystem) 48 c.Check(supports, jc.IsFalse) 49 } 50 51 func (s *storageProviderSuite) TestFSSource(c *gc.C) { 52 sConfig := &storage.Config{} 53 _, err := s.provider.FilesystemSource(sConfig) 54 c.Check(err, gc.ErrorMatches, "filesystems not supported") 55 } 56 57 func (s *storageProviderSuite) TestVolumeSource(c *gc.C) { 58 storageCfg := &storage.Config{} 59 _, err := s.provider.VolumeSource(storageCfg) 60 c.Check(err, jc.ErrorIsNil) 61 } 62 63 type volumeSourceSuite struct { 64 gce.BaseSuite 65 source storage.VolumeSource 66 params []storage.VolumeParams 67 instId instance.Id 68 attachmentParams *storage.VolumeAttachmentParams 69 } 70 71 var _ = gc.Suite(&volumeSourceSuite{}) 72 73 func (s *volumeSourceSuite) SetUpTest(c *gc.C) { 74 s.BaseSuite.SetUpTest(c) 75 76 provider, err := s.Env.StorageProvider("gce") 77 c.Assert(err, jc.ErrorIsNil) 78 s.source, err = provider.VolumeSource(&storage.Config{}) 79 c.Check(err, jc.ErrorIsNil) 80 81 inst := gce.NewInstance(s.BaseInstance, s.Env) 82 vTag := names.NewVolumeTag("0") 83 mTag := names.NewMachineTag("0") 84 s.instId = inst.Id() 85 s.attachmentParams = &storage.VolumeAttachmentParams{ 86 AttachmentParams: storage.AttachmentParams{ 87 Provider: "gce", 88 Machine: mTag, 89 InstanceId: s.instId, 90 }, 91 VolumeId: s.BaseDisk.Name, 92 Volume: names.NewVolumeTag("0"), 93 } 94 s.params = []storage.VolumeParams{{ 95 Tag: vTag, 96 Size: 1024, 97 Provider: "gce", 98 Attachment: s.attachmentParams, 99 }} 100 101 } 102 103 func (s *volumeSourceSuite) TestCreateVolumesNoInstance(c *gc.C) { 104 res, err := s.source.CreateVolumes(s.CallCtx, s.params) 105 c.Check(err, jc.ErrorIsNil) 106 c.Check(res, gc.HasLen, 1) 107 expectedErr := "cannot obtain \"spam\" from instance cache: cannot attach to non-running instance spam" 108 c.Assert(res[0].Error, gc.ErrorMatches, expectedErr) 109 110 } 111 112 func (s *volumeSourceSuite) TestCreateVolumesNoDiskCreated(c *gc.C) { 113 s.FakeConn.Insts = []google.Instance{*s.BaseInstance} 114 res, err := s.source.CreateVolumes(s.CallCtx, s.params) 115 c.Check(err, jc.ErrorIsNil) 116 c.Check(res, gc.HasLen, 1) 117 c.Assert(res[0].Error, gc.ErrorMatches, "unexpected number of disks created: 0") 118 119 } 120 121 func (s *volumeSourceSuite) TestCreateVolumesInvalidCredentialError(c *gc.C) { 122 s.FakeConn.Err = gce.InvalidCredentialError 123 c.Assert(s.InvalidatedCredentials, jc.IsFalse) 124 _, err := s.source.CreateVolumes(s.CallCtx, s.params) 125 c.Check(err, gc.NotNil) 126 c.Assert(s.InvalidatedCredentials, jc.IsTrue) 127 } 128 129 func (s *volumeSourceSuite) TestCreateVolumes(c *gc.C) { 130 s.FakeConn.Insts = []google.Instance{*s.BaseInstance} 131 s.FakeConn.GoogleDisks = []*google.Disk{s.BaseDisk} 132 s.FakeConn.GoogleDisk = s.BaseDisk 133 s.FakeConn.AttachedDisk = &google.AttachedDisk{ 134 VolumeName: s.BaseDisk.Name, 135 DeviceName: "home-zone-1234567", 136 Mode: "READ_WRITE", 137 } 138 res, err := s.source.CreateVolumes(s.CallCtx, s.params) 139 c.Check(err, jc.ErrorIsNil) 140 c.Check(res, gc.HasLen, 1) 141 // Volume was created 142 c.Assert(res[0].Error, jc.ErrorIsNil) 143 c.Assert(res[0].Volume.VolumeId, gc.Equals, s.BaseDisk.Name) 144 c.Assert(res[0].Volume.HardwareId, gc.Equals, "") 145 146 // Volume was also attached as indicated by Attachment in params. 147 c.Assert(res[0].VolumeAttachment.DeviceName, gc.Equals, "") 148 c.Assert(res[0].VolumeAttachment.DeviceLink, gc.Equals, "/dev/disk/by-id/google-home-zone-1234567") 149 c.Assert(res[0].VolumeAttachment.Machine.String(), gc.Equals, "machine-0") 150 c.Assert(res[0].VolumeAttachment.ReadOnly, jc.IsFalse) 151 c.Assert(res[0].VolumeAttachment.Volume.String(), gc.Equals, "volume-0") 152 153 // Internals where properly called 154 // Disk Creation 155 createCalled, call := s.FakeConn.WasCalled("CreateDisks") 156 c.Check(call, gc.HasLen, 1) 157 c.Assert(createCalled, jc.IsTrue) 158 c.Assert(call[0].ZoneName, gc.Equals, "home-zone") 159 c.Assert(call[0].Disks[0].Name, jc.HasPrefix, "home-zone--") 160 161 // Instance existence Checking 162 instanceDisksCalled, call := s.FakeConn.WasCalled("InstanceDisks") 163 c.Check(call, gc.HasLen, 1) 164 c.Assert(instanceDisksCalled, jc.IsTrue) 165 c.Assert(call[0].ZoneName, gc.Equals, "home-zone") 166 c.Assert(call[0].InstanceId, gc.Equals, string(s.instId)) 167 168 // Disk Was attached 169 attachCalled, call := s.FakeConn.WasCalled("AttachDisk") 170 c.Check(call, gc.HasLen, 1) 171 c.Assert(attachCalled, jc.IsTrue) 172 c.Assert(call[0].ZoneName, gc.Equals, "home-zone") 173 c.Assert(call[0].VolumeName, jc.HasPrefix, "home-zone--") 174 c.Assert(call[0].InstanceId, gc.Equals, string(s.instId)) 175 } 176 177 func (s *volumeSourceSuite) TestDestroyVolumesInvalidCredentialError(c *gc.C) { 178 s.FakeConn.Err = gce.InvalidCredentialError 179 c.Assert(s.InvalidatedCredentials, jc.IsFalse) 180 _, err := s.source.DestroyVolumes(s.CallCtx, []string{"a--volume-name"}) 181 c.Check(err, jc.ErrorIsNil) 182 c.Assert(s.InvalidatedCredentials, jc.IsTrue) 183 } 184 185 func (s *volumeSourceSuite) TestDestroyVolumes(c *gc.C) { 186 errs, err := s.source.DestroyVolumes(s.CallCtx, []string{"a--volume-name"}) 187 c.Check(err, jc.ErrorIsNil) 188 c.Check(errs, gc.HasLen, 1) 189 c.Assert(errs[0], jc.ErrorIsNil) 190 191 destroyCalled, call := s.FakeConn.WasCalled("RemoveDisk") 192 c.Check(call, gc.HasLen, 1) 193 c.Assert(destroyCalled, jc.IsTrue) 194 c.Assert(call[0].ZoneName, gc.Equals, "a") 195 c.Assert(call[0].ID, gc.Equals, "a--volume-name") 196 } 197 198 func (s *volumeSourceSuite) TestReleaseVolumesInvalidCredentialError(c *gc.C) { 199 s.FakeConn.Err = gce.InvalidCredentialError 200 c.Assert(s.InvalidatedCredentials, jc.IsFalse) 201 _, err := s.source.ReleaseVolumes(s.CallCtx, []string{s.BaseDisk.Name}) 202 c.Check(err, jc.ErrorIsNil) 203 c.Assert(s.InvalidatedCredentials, jc.IsTrue) 204 } 205 206 func (s *volumeSourceSuite) TestReleaseVolumes(c *gc.C) { 207 s.FakeConn.GoogleDisk = s.BaseDisk 208 209 errs, err := s.source.ReleaseVolumes(s.CallCtx, []string{s.BaseDisk.Name}) 210 c.Check(err, jc.ErrorIsNil) 211 c.Check(errs, gc.HasLen, 1) 212 c.Assert(errs[0], jc.ErrorIsNil) 213 214 called, calls := s.FakeConn.WasCalled("SetDiskLabels") 215 c.Check(called, jc.IsTrue) 216 c.Assert(calls, gc.HasLen, 1) 217 c.Assert(calls[0].ZoneName, gc.Equals, "home-zone") 218 c.Assert(calls[0].ID, gc.Equals, s.BaseDisk.Name) 219 c.Assert(calls[0].Labels, jc.DeepEquals, map[string]string{ 220 "yodel": "eh", 221 // Note, no controller/model labels 222 }) 223 } 224 225 func (s *volumeSourceSuite) TestImportVolumesInvalidCredentialError(c *gc.C) { 226 s.FakeConn.Err = gce.InvalidCredentialError 227 c.Assert(s.InvalidatedCredentials, jc.IsFalse) 228 _, err := s.source.(storage.VolumeImporter).ImportVolume( 229 s.CallCtx, 230 s.BaseDisk.Name, map[string]string{ 231 "juju-model-uuid": "foo", 232 "juju-controller-uuid": "bar", 233 }, 234 ) 235 c.Check(err, gc.NotNil) 236 c.Assert(s.InvalidatedCredentials, jc.IsTrue) 237 } 238 239 func (s *volumeSourceSuite) TestImportVolume(c *gc.C) { 240 s.FakeConn.GoogleDisk = s.BaseDisk 241 242 c.Assert(s.source, gc.Implements, new(storage.VolumeImporter)) 243 volumeInfo, err := s.source.(storage.VolumeImporter).ImportVolume( 244 s.CallCtx, 245 s.BaseDisk.Name, map[string]string{ 246 "juju-model-uuid": "foo", 247 "juju-controller-uuid": "bar", 248 }, 249 ) 250 c.Check(err, jc.ErrorIsNil) 251 c.Assert(volumeInfo, jc.DeepEquals, storage.VolumeInfo{ 252 VolumeId: s.BaseDisk.Name, 253 Size: 1024, 254 Persistent: true, 255 }) 256 257 called, calls := s.FakeConn.WasCalled("SetDiskLabels") 258 c.Check(called, jc.IsTrue) 259 c.Assert(calls, gc.HasLen, 1) 260 c.Assert(calls[0].ZoneName, gc.Equals, "home-zone") 261 c.Assert(calls[0].ID, gc.Equals, s.BaseDisk.Name) 262 c.Assert(calls[0].Labels, jc.DeepEquals, map[string]string{ 263 "juju-model-uuid": "foo", 264 "juju-controller-uuid": "bar", 265 "yodel": "eh", // other existing tags left alone 266 }) 267 } 268 269 func (s *volumeSourceSuite) TestImportVolumeNotReady(c *gc.C) { 270 s.FakeConn.GoogleDisk = s.BaseDisk 271 s.FakeConn.GoogleDisk.Status = "floop" 272 273 _, err := s.source.(storage.VolumeImporter).ImportVolume( 274 s.CallCtx, 275 s.BaseDisk.Name, map[string]string{}, 276 ) 277 c.Check(err, gc.ErrorMatches, `cannot import volume "`+s.BaseDisk.Name+`" with status "floop"`) 278 279 called, _ := s.FakeConn.WasCalled("SetDiskLabels") 280 c.Check(called, jc.IsFalse) 281 } 282 283 func (s *volumeSourceSuite) TestListVolumesInvalidCredentialError(c *gc.C) { 284 s.FakeConn.Err = gce.InvalidCredentialError 285 c.Assert(s.InvalidatedCredentials, jc.IsFalse) 286 _, err := s.source.ListVolumes(s.CallCtx) 287 c.Check(err, gc.NotNil) 288 c.Assert(s.InvalidatedCredentials, jc.IsTrue) 289 } 290 291 func (s *volumeSourceSuite) TestListVolumes(c *gc.C) { 292 s.FakeConn.GoogleDisks = []*google.Disk{s.BaseDisk} 293 vols, err := s.source.ListVolumes(s.CallCtx) 294 c.Check(err, jc.ErrorIsNil) 295 c.Assert(vols, gc.HasLen, 1) 296 297 disksCalled, call := s.FakeConn.WasCalled("Disks") 298 c.Check(call, gc.HasLen, 1) 299 c.Assert(disksCalled, jc.IsTrue) 300 } 301 302 func (s *volumeSourceSuite) TestListVolumesOnlyListsCurrentModelUUID(c *gc.C) { 303 otherDisk := &google.Disk{ 304 Id: 1234568, 305 Name: "home-zone--566fe7b2-c026-4a86-a2cc-84cb7f9a4868", 306 Zone: "home-zone", 307 Status: google.StatusReady, 308 Size: 1024, 309 Description: "a-different-model-uuid", 310 Labels: map[string]string{ 311 "juju-model-uuid": "foo", 312 }, 313 } 314 s.FakeConn.GoogleDisks = []*google.Disk{s.BaseDisk, otherDisk} 315 vols, err := s.source.ListVolumes(s.CallCtx) 316 c.Check(err, jc.ErrorIsNil) 317 c.Assert(vols, gc.HasLen, 1) 318 } 319 320 func (s *volumeSourceSuite) TestListVolumesIgnoresNamesFormatteDifferently(c *gc.C) { 321 otherDisk := &google.Disk{ 322 Id: 1234568, 323 Name: "juju-566fe7b2-c026-4a86-a2cc-84cb7f9a4868", 324 Zone: "home-zone", 325 Status: google.StatusReady, 326 Size: 1024, 327 Description: "", 328 } 329 s.FakeConn.GoogleDisks = []*google.Disk{s.BaseDisk, otherDisk} 330 vols, err := s.source.ListVolumes(s.CallCtx) 331 c.Check(err, jc.ErrorIsNil) 332 c.Assert(vols, gc.HasLen, 1) 333 } 334 335 func (s *volumeSourceSuite) TestDescribeVolumesInvalidCredentialError(c *gc.C) { 336 s.FakeConn.Err = gce.InvalidCredentialError 337 c.Assert(s.InvalidatedCredentials, jc.IsFalse) 338 volName := "home-zone--c930380d-8337-4bf5-b07a-9dbb5ae771e4" 339 _, err := s.source.DescribeVolumes(s.CallCtx, []string{volName}) 340 c.Check(err, gc.NotNil) 341 c.Assert(s.InvalidatedCredentials, jc.IsTrue) 342 } 343 344 func (s *volumeSourceSuite) TestDescribeVolumes(c *gc.C) { 345 s.FakeConn.GoogleDisk = s.BaseDisk 346 volName := "home-zone--c930380d-8337-4bf5-b07a-9dbb5ae771e4" 347 res, err := s.source.DescribeVolumes(s.CallCtx, []string{volName}) 348 c.Check(err, jc.ErrorIsNil) 349 c.Assert(res, gc.HasLen, 1) 350 c.Assert(res[0].VolumeInfo.Size, gc.Equals, uint64(1024)) 351 c.Assert(res[0].VolumeInfo.VolumeId, gc.Equals, volName) 352 353 diskCalled, call := s.FakeConn.WasCalled("Disk") 354 c.Check(call, gc.HasLen, 1) 355 c.Assert(diskCalled, jc.IsTrue) 356 c.Assert(call[0].ZoneName, gc.Equals, "home-zone") 357 c.Assert(call[0].ID, gc.Equals, volName) 358 } 359 360 func (s *volumeSourceSuite) TestAttachVolumes(c *gc.C) { 361 volName := "home-zone--c930380d-8337-4bf5-b07a-9dbb5ae771e4" 362 attachments := []storage.VolumeAttachmentParams{*s.attachmentParams} 363 s.FakeConn.AttachedDisk = &google.AttachedDisk{ 364 VolumeName: s.BaseDisk.Name, 365 DeviceName: "home-zone-1234567", 366 Mode: "READ_WRITE", 367 } 368 res, err := s.source.AttachVolumes(s.CallCtx, attachments) 369 c.Check(err, jc.ErrorIsNil) 370 c.Assert(res, gc.HasLen, 1) 371 c.Assert(res[0].VolumeAttachment.Volume.String(), gc.Equals, "volume-0") 372 c.Assert(res[0].VolumeAttachment.Machine.String(), gc.Equals, "machine-0") 373 c.Assert(res[0].VolumeAttachment.VolumeAttachmentInfo.DeviceName, gc.Equals, "") 374 c.Assert(res[0].VolumeAttachment.VolumeAttachmentInfo.DeviceLink, gc.Equals, "/dev/disk/by-id/google-home-zone-1234567") 375 376 // Disk Was attached 377 attachCalled, call := s.FakeConn.WasCalled("AttachDisk") 378 c.Check(call, gc.HasLen, 1) 379 c.Assert(attachCalled, jc.IsTrue) 380 c.Assert(call[0].ZoneName, gc.Equals, "home-zone") 381 c.Assert(call[0].VolumeName, gc.Equals, volName) 382 c.Assert(call[0].InstanceId, gc.Equals, string(s.instId)) 383 384 } 385 386 func (s *volumeSourceSuite) TestAttachVolumesInvalidCredentialError(c *gc.C) { 387 s.FakeConn.Err = gce.InvalidCredentialError 388 c.Assert(s.InvalidatedCredentials, jc.IsFalse) 389 _, err := s.source.AttachVolumes(s.CallCtx, []storage.VolumeAttachmentParams{*s.attachmentParams}) 390 c.Check(err, gc.NotNil) 391 c.Assert(s.InvalidatedCredentials, jc.IsTrue) 392 } 393 394 func (s *volumeSourceSuite) TestDetachVolumes(c *gc.C) { 395 volName := "home-zone--c930380d-8337-4bf5-b07a-9dbb5ae771e4" 396 attachments := []storage.VolumeAttachmentParams{*s.attachmentParams} 397 errs, err := s.source.DetachVolumes(s.CallCtx, attachments) 398 c.Check(err, jc.ErrorIsNil) 399 c.Assert(errs, gc.HasLen, 1) 400 c.Assert(errs[0], jc.ErrorIsNil) 401 402 // Disk Was detached 403 attachCalled, call := s.FakeConn.WasCalled("DetachDisk") 404 c.Check(call, gc.HasLen, 1) 405 c.Assert(attachCalled, jc.IsTrue) 406 c.Assert(call[0].ZoneName, gc.Equals, "home-zone") 407 c.Assert(call[0].InstanceId, gc.Equals, string(s.instId)) 408 c.Assert(call[0].VolumeName, gc.Equals, volName) 409 } 410 411 func (s *volumeSourceSuite) TestDetachVolumesInvalidCredentialError(c *gc.C) { 412 s.FakeConn.Err = gce.InvalidCredentialError 413 c.Assert(s.InvalidatedCredentials, jc.IsFalse) 414 _, err := s.source.DetachVolumes(s.CallCtx, []storage.VolumeAttachmentParams{*s.attachmentParams}) 415 c.Check(err, gc.NotNil) 416 c.Assert(s.InvalidatedCredentials, jc.IsTrue) 417 }