github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/common/storagecommon/storage_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package storagecommon_test
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	jc "github.com/juju/testing/checkers"
     9  	gc "gopkg.in/check.v1"
    10  	"gopkg.in/juju/names.v2"
    11  
    12  	"github.com/juju/juju/apiserver/common/storagecommon"
    13  	"github.com/juju/juju/state"
    14  	"github.com/juju/juju/storage"
    15  )
    16  
    17  type VolumeStorageAttachmentInfoSuite struct {
    18  	machineTag           names.MachineTag
    19  	volumeTag            names.VolumeTag
    20  	storageTag           names.StorageTag
    21  	st                   *fakeStorage
    22  	storageInstance      *fakeStorageInstance
    23  	storageAttachment    *fakeStorageAttachment
    24  	volume               *fakeVolume
    25  	volumeAttachment     *fakeVolumeAttachment
    26  	volumeAttachmentPlan *fakeVolumeAttachmentPlan
    27  	blockDevices         []state.BlockDeviceInfo
    28  }
    29  
    30  var _ = gc.Suite(&VolumeStorageAttachmentInfoSuite{})
    31  
    32  func (s *VolumeStorageAttachmentInfoSuite) SetUpTest(c *gc.C) {
    33  	s.machineTag = names.NewMachineTag("0")
    34  	s.volumeTag = names.NewVolumeTag("0")
    35  	s.storageTag = names.NewStorageTag("osd-devices/0")
    36  	s.storageInstance = &fakeStorageInstance{
    37  		tag:   s.storageTag,
    38  		owner: s.machineTag,
    39  		kind:  state.StorageKindBlock,
    40  	}
    41  	s.storageAttachment = &fakeStorageAttachment{
    42  		storageTag: s.storageTag,
    43  	}
    44  	s.volume = &fakeVolume{
    45  		tag: s.volumeTag,
    46  		info: &state.VolumeInfo{
    47  			VolumeId: "vol-ume",
    48  			Pool:     "radiance",
    49  			Size:     1024,
    50  		},
    51  	}
    52  	s.volumeAttachment = &fakeVolumeAttachment{
    53  		info: &state.VolumeAttachmentInfo{},
    54  	}
    55  	s.volumeAttachmentPlan = &fakeVolumeAttachmentPlan{
    56  		err:       errors.NotFoundf("volume attachment plans"),
    57  		blockInfo: &state.BlockDeviceInfo{},
    58  	}
    59  	s.blockDevices = []state.BlockDeviceInfo{{
    60  		DeviceName:  "sda",
    61  		DeviceLinks: []string{"/dev/disk/by-id/verbatim"},
    62  		HardwareId:  "whatever",
    63  		WWN:         "drbr",
    64  	}, {
    65  		DeviceName:  "sdb",
    66  		DeviceLinks: []string{"/dev/disk/by-id/a-second-device"},
    67  		HardwareId:  "whatever",
    68  		WWN:         "drbr",
    69  	},
    70  	}
    71  	s.st = &fakeStorage{
    72  		storageInstance: func(tag names.StorageTag) (state.StorageInstance, error) {
    73  			return s.storageInstance, nil
    74  		},
    75  		storageInstanceVolume: func(tag names.StorageTag) (state.Volume, error) {
    76  			return s.volume, nil
    77  		},
    78  		volumeAttachment: func(m names.Tag, v names.VolumeTag) (state.VolumeAttachment, error) {
    79  			return s.volumeAttachment, nil
    80  		},
    81  		blockDevices: func(m names.MachineTag) ([]state.BlockDeviceInfo, error) {
    82  			return s.blockDevices, nil
    83  		},
    84  		volumeAttachmentPlan: func(names.Tag, names.VolumeTag) (state.VolumeAttachmentPlan, error) {
    85  			return s.volumeAttachmentPlan, nil
    86  		},
    87  	}
    88  }
    89  
    90  func (s *VolumeStorageAttachmentInfoSuite) TestStorageAttachmentPlanInfoDeviceNameSet(c *gc.C) {
    91  	// Plan block info takes precedence to attachment info, planInfo is observed directly
    92  	// on the machine itself, as opposed to volumeInfo which is "guessed" by the provider
    93  	s.volumeAttachmentPlan.blockInfo.DeviceName = "sdb"
    94  	s.volumeAttachmentPlan.err = nil
    95  	s.volumeAttachment.info.DeviceName = "sda"
    96  	info, err := storagecommon.StorageAttachmentInfo(s.st, s.st, s.st, s.storageAttachment, s.machineTag)
    97  	c.Assert(err, jc.ErrorIsNil)
    98  	s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "VolumeAttachmentPlan", "BlockDevices")
    99  	c.Assert(info, jc.DeepEquals, &storage.StorageAttachmentInfo{
   100  		Kind:     storage.StorageKindBlock,
   101  		Location: "/dev/sdb",
   102  	})
   103  }
   104  
   105  func (s *VolumeStorageAttachmentInfoSuite) TestStorageAttachmentInfoPersistentDeviceName(c *gc.C) {
   106  	s.volumeAttachment.info.DeviceName = "sda"
   107  	info, err := storagecommon.StorageAttachmentInfo(s.st, s.st, s.st, s.storageAttachment, s.machineTag)
   108  	c.Assert(err, jc.ErrorIsNil)
   109  	s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "VolumeAttachmentPlan", "BlockDevices")
   110  	c.Assert(info, jc.DeepEquals, &storage.StorageAttachmentInfo{
   111  		Kind:     storage.StorageKindBlock,
   112  		Location: "/dev/sda",
   113  	})
   114  }
   115  
   116  func (s *VolumeStorageAttachmentInfoSuite) TestStorageAttachmentInfoMissingBlockDevice(c *gc.C) {
   117  	// If the block device has not shown up yet,
   118  	// then we should get a NotProvisioned error.
   119  	s.blockDevices = nil
   120  	s.volumeAttachment.info.DeviceName = "sda"
   121  	_, err := storagecommon.StorageAttachmentInfo(s.st, s.st, s.st, s.storageAttachment, s.machineTag)
   122  	c.Assert(err, jc.Satisfies, errors.IsNotProvisioned)
   123  	s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "VolumeAttachmentPlan", "BlockDevices")
   124  }
   125  
   126  func (s *VolumeStorageAttachmentInfoSuite) TestStorageAttachmentInfoPersistentDeviceNameIgnoresEmptyLinks(c *gc.C) {
   127  	s.volumeAttachment.info.DeviceLink = "/dev/disk/by-id/verbatim"
   128  	s.volumeAttachment.info.DeviceName = "sda"
   129  	// Clear the machine block device link to force a match on name.
   130  	s.blockDevices[0].DeviceLinks = nil
   131  	info, err := storagecommon.StorageAttachmentInfo(s.st, s.st, s.st, s.storageAttachment, s.machineTag)
   132  	c.Assert(err, jc.ErrorIsNil)
   133  	s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "VolumeAttachmentPlan", "BlockDevices")
   134  	c.Assert(info, jc.DeepEquals, &storage.StorageAttachmentInfo{
   135  		Kind:     storage.StorageKindBlock,
   136  		Location: "/dev/sda",
   137  	})
   138  }
   139  
   140  func (s *VolumeStorageAttachmentInfoSuite) TestStorageAttachmentInfoPersistentDeviceLink(c *gc.C) {
   141  	s.volumeAttachment.info.DeviceLink = "/dev/disk/by-id/verbatim"
   142  	info, err := storagecommon.StorageAttachmentInfo(s.st, s.st, s.st, s.storageAttachment, s.machineTag)
   143  	c.Assert(err, jc.ErrorIsNil)
   144  	s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "VolumeAttachmentPlan", "BlockDevices")
   145  	c.Assert(info, jc.DeepEquals, &storage.StorageAttachmentInfo{
   146  		Kind:     storage.StorageKindBlock,
   147  		Location: "/dev/disk/by-id/verbatim",
   148  	})
   149  }
   150  
   151  func (s *VolumeStorageAttachmentInfoSuite) TestStorageAttachmentInfoPersistentHardwareId(c *gc.C) {
   152  	s.volume.info.HardwareId = "whatever"
   153  	info, err := storagecommon.StorageAttachmentInfo(s.st, s.st, s.st, s.storageAttachment, s.machineTag)
   154  	c.Assert(err, jc.ErrorIsNil)
   155  	s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "VolumeAttachmentPlan", "BlockDevices")
   156  	c.Assert(info, jc.DeepEquals, &storage.StorageAttachmentInfo{
   157  		Kind:     storage.StorageKindBlock,
   158  		Location: "/dev/disk/by-id/whatever",
   159  	})
   160  }
   161  
   162  func (s *VolumeStorageAttachmentInfoSuite) TestStorageAttachmentInfoPersistentWWN(c *gc.C) {
   163  	s.volume.info.WWN = "drbr"
   164  	info, err := storagecommon.StorageAttachmentInfo(s.st, s.st, s.st, s.storageAttachment, s.machineTag)
   165  	c.Assert(err, jc.ErrorIsNil)
   166  	s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "VolumeAttachmentPlan", "BlockDevices")
   167  	c.Assert(info, jc.DeepEquals, &storage.StorageAttachmentInfo{
   168  		Kind:     storage.StorageKindBlock,
   169  		Location: "/dev/disk/by-id/wwn-drbr",
   170  	})
   171  }
   172  
   173  func (s *VolumeStorageAttachmentInfoSuite) TestStorageAttachmentInfoMatchingBlockDevice(c *gc.C) {
   174  	// The bus address alone is not enough to produce a path to the block
   175  	// device; we need to find a published block device with the matching
   176  	// bus address.
   177  	s.volumeAttachment.info.BusAddress = "scsi@1:2.3.4"
   178  	s.blockDevices = []state.BlockDeviceInfo{{
   179  		DeviceName: "sda",
   180  	}, {
   181  		DeviceName: "sdb",
   182  		BusAddress: s.volumeAttachment.info.BusAddress,
   183  	}}
   184  	info, err := storagecommon.StorageAttachmentInfo(s.st, s.st, s.st, s.storageAttachment, s.machineTag)
   185  	c.Assert(err, jc.ErrorIsNil)
   186  	s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "VolumeAttachmentPlan", "BlockDevices")
   187  	c.Assert(info, jc.DeepEquals, &storage.StorageAttachmentInfo{
   188  		Kind:     storage.StorageKindBlock,
   189  		Location: "/dev/sdb",
   190  	})
   191  }
   192  
   193  func (s *VolumeStorageAttachmentInfoSuite) TestStorageAttachmentInfoNoBlockDevice(c *gc.C) {
   194  	// Neither the volume nor the volume attachment has enough information
   195  	// to persistently identify the path, so we must enquire about block
   196  	// devices; there are none (yet), so NotProvisioned is returned.
   197  	s.volumeAttachment.info.BusAddress = "scsi@1:2.3.4"
   198  	_, err := storagecommon.StorageAttachmentInfo(s.st, s.st, s.st, s.storageAttachment, s.machineTag)
   199  	c.Assert(err, jc.Satisfies, errors.IsNotProvisioned)
   200  	s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "VolumeAttachmentPlan", "BlockDevices")
   201  }
   202  
   203  func (s *VolumeStorageAttachmentInfoSuite) TestStorageAttachmentInfoVolumeNotFound(c *gc.C) {
   204  	s.st.storageInstanceVolume = func(tag names.StorageTag) (state.Volume, error) {
   205  		return nil, errors.NotFoundf("volume for storage %s", tag.Id())
   206  	}
   207  	_, err := storagecommon.StorageAttachmentInfo(s.st, s.st, s.st, s.storageAttachment, s.machineTag)
   208  	c.Assert(err, jc.Satisfies, errors.IsNotProvisioned)
   209  	s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume")
   210  }
   211  
   212  type FilesystemStorageAttachmentInfoSuite struct {
   213  	hostTag              names.Tag
   214  	filsystemTag         names.FilesystemTag
   215  	storageTag           names.StorageTag
   216  	st                   *fakeStorage
   217  	storageInstance      *fakeStorageInstance
   218  	storageAttachment    *fakeStorageAttachment
   219  	filesystem           *fakeFilesystem
   220  	filesystemAttachment *fakeFilesystemAttachment
   221  }
   222  
   223  var _ = gc.Suite(&FilesystemStorageAttachmentInfoSuite{})
   224  
   225  func (s *FilesystemStorageAttachmentInfoSuite) SetUpTest(c *gc.C) {
   226  	s.hostTag = names.NewUnitTag("mysql/0")
   227  	s.filsystemTag = names.NewFilesystemTag("0")
   228  	s.storageTag = names.NewStorageTag("data/0")
   229  	s.storageInstance = &fakeStorageInstance{
   230  		tag:   s.storageTag,
   231  		owner: s.hostTag,
   232  		kind:  state.StorageKindFilesystem,
   233  	}
   234  	s.storageAttachment = &fakeStorageAttachment{
   235  		storageTag: s.storageTag,
   236  	}
   237  	s.filesystem = &fakeFilesystem{
   238  		tag: s.filsystemTag,
   239  		info: &state.FilesystemInfo{
   240  			FilesystemId: "file-system",
   241  			Pool:         "radiance",
   242  			Size:         1024,
   243  		},
   244  	}
   245  	s.filesystemAttachment = &fakeFilesystemAttachment{
   246  		info: &state.FilesystemAttachmentInfo{},
   247  	}
   248  	s.st = &fakeStorage{
   249  		storageInstance: func(tag names.StorageTag) (state.StorageInstance, error) {
   250  			return s.storageInstance, nil
   251  		},
   252  		storageInstanceFilesystem: func(tag names.StorageTag) (state.Filesystem, error) {
   253  			return s.filesystem, nil
   254  		},
   255  		filesystemAttachment: func(m names.Tag, fs names.FilesystemTag) (state.FilesystemAttachment, error) {
   256  			return s.filesystemAttachment, nil
   257  		},
   258  	}
   259  }
   260  
   261  func (s *FilesystemStorageAttachmentInfoSuite) TestStorageAttachmentInfo(c *gc.C) {
   262  	s.filesystemAttachment.info.MountPoint = "/path/to/here"
   263  	info, err := storagecommon.StorageAttachmentInfo(s.st, s.st, s.st, s.storageAttachment, s.hostTag)
   264  	c.Assert(err, jc.ErrorIsNil)
   265  	s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceFilesystem", "FilesystemAttachment")
   266  	c.Assert(info, jc.DeepEquals, &storage.StorageAttachmentInfo{
   267  		Kind:     storage.StorageKindFilesystem,
   268  		Location: "/path/to/here",
   269  	})
   270  }
   271  
   272  func (s *FilesystemStorageAttachmentInfoSuite) TestStorageAttachmentInfoFilesystemNotFound(c *gc.C) {
   273  	s.st.storageInstanceFilesystem = func(tag names.StorageTag) (state.Filesystem, error) {
   274  		return nil, errors.NotFoundf("filesystem for storage %s", tag.Id())
   275  	}
   276  	_, err := storagecommon.StorageAttachmentInfo(s.st, s.st, s.st, s.storageAttachment, s.hostTag)
   277  	c.Assert(err, jc.Satisfies, errors.IsNotProvisioned)
   278  	s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceFilesystem")
   279  }