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 }