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  }