github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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 "path/filepath" 8 9 "github.com/juju/errors" 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 "gopkg.in/juju/names.v2" 13 14 "github.com/juju/juju/apiserver/common/storagecommon" 15 apiservertesting "github.com/juju/juju/apiserver/testing" 16 "github.com/juju/juju/state" 17 statetesting "github.com/juju/juju/state/testing" 18 "github.com/juju/juju/storage" 19 ) 20 21 type storageAttachmentInfoSuite struct { 22 machineTag names.MachineTag 23 volumeTag names.VolumeTag 24 storageTag names.StorageTag 25 st *fakeStorage 26 storageInstance *fakeStorageInstance 27 storageAttachment *fakeStorageAttachment 28 volume *fakeVolume 29 volumeAttachment *fakeVolumeAttachment 30 blockDevices []state.BlockDeviceInfo 31 } 32 33 var _ = gc.Suite(&storageAttachmentInfoSuite{}) 34 35 func (s *storageAttachmentInfoSuite) SetUpTest(c *gc.C) { 36 s.machineTag = names.NewMachineTag("0") 37 s.volumeTag = names.NewVolumeTag("0") 38 s.storageTag = names.NewStorageTag("osd-devices/0") 39 s.storageInstance = &fakeStorageInstance{ 40 tag: s.storageTag, 41 owner: s.machineTag, 42 kind: state.StorageKindBlock, 43 } 44 s.storageAttachment = &fakeStorageAttachment{ 45 storageTag: s.storageTag, 46 } 47 s.volume = &fakeVolume{ 48 tag: s.volumeTag, 49 info: &state.VolumeInfo{ 50 VolumeId: "vol-ume", 51 Pool: "radiance", 52 Size: 1024, 53 }, 54 } 55 s.volumeAttachment = &fakeVolumeAttachment{ 56 info: &state.VolumeAttachmentInfo{}, 57 } 58 s.blockDevices = []state.BlockDeviceInfo{{ 59 DeviceName: "sda", 60 DeviceLinks: []string{"/dev/disk/by-id/verbatim"}, 61 HardwareId: "whatever", 62 }} 63 s.st = &fakeStorage{ 64 storageInstance: func(tag names.StorageTag) (state.StorageInstance, error) { 65 return s.storageInstance, nil 66 }, 67 storageInstanceVolume: func(tag names.StorageTag) (state.Volume, error) { 68 return s.volume, nil 69 }, 70 volumeAttachment: func(m names.MachineTag, v names.VolumeTag) (state.VolumeAttachment, error) { 71 return s.volumeAttachment, nil 72 }, 73 blockDevices: func(m names.MachineTag) ([]state.BlockDeviceInfo, error) { 74 return s.blockDevices, nil 75 }, 76 } 77 } 78 79 func (s *storageAttachmentInfoSuite) TestStorageAttachmentInfoPersistentDeviceName(c *gc.C) { 80 s.volumeAttachment.info.DeviceName = "sda" 81 info, err := storagecommon.StorageAttachmentInfo(s.st, s.storageAttachment, s.machineTag) 82 c.Assert(err, jc.ErrorIsNil) 83 s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "BlockDevices") 84 c.Assert(info, jc.DeepEquals, &storage.StorageAttachmentInfo{ 85 Kind: storage.StorageKindBlock, 86 Location: filepath.FromSlash("/dev/sda"), 87 }) 88 } 89 90 func (s *storageAttachmentInfoSuite) TestStorageAttachmentInfoMissingBlockDevice(c *gc.C) { 91 // If the block device has not shown up yet, 92 // then we should get a NotProvisioned error. 93 s.blockDevices = nil 94 s.volumeAttachment.info.DeviceName = "sda" 95 _, err := storagecommon.StorageAttachmentInfo(s.st, s.storageAttachment, s.machineTag) 96 c.Assert(err, jc.Satisfies, errors.IsNotProvisioned) 97 s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "BlockDevices") 98 } 99 100 func (s *storageAttachmentInfoSuite) TestStorageAttachmentInfoPersistentDeviceLink(c *gc.C) { 101 s.volumeAttachment.info.DeviceLink = "/dev/disk/by-id/verbatim" 102 info, err := storagecommon.StorageAttachmentInfo(s.st, s.storageAttachment, s.machineTag) 103 c.Assert(err, jc.ErrorIsNil) 104 s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "BlockDevices") 105 c.Assert(info, jc.DeepEquals, &storage.StorageAttachmentInfo{ 106 Kind: storage.StorageKindBlock, 107 Location: "/dev/disk/by-id/verbatim", 108 }) 109 } 110 111 func (s *storageAttachmentInfoSuite) TestStorageAttachmentInfoPersistentHardwareId(c *gc.C) { 112 s.volume.info.HardwareId = "whatever" 113 info, err := storagecommon.StorageAttachmentInfo(s.st, s.storageAttachment, s.machineTag) 114 c.Assert(err, jc.ErrorIsNil) 115 s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "BlockDevices") 116 c.Assert(info, jc.DeepEquals, &storage.StorageAttachmentInfo{ 117 Kind: storage.StorageKindBlock, 118 Location: filepath.FromSlash("/dev/disk/by-id/whatever"), 119 }) 120 } 121 122 func (s *storageAttachmentInfoSuite) TestStorageAttachmentInfoMatchingBlockDevice(c *gc.C) { 123 // The bus address alone is not enough to produce a path to the block 124 // device; we need to find a published block device with the matching 125 // bus address. 126 s.volumeAttachment.info.BusAddress = "scsi@1:2.3.4" 127 s.blockDevices = []state.BlockDeviceInfo{{ 128 DeviceName: "sda", 129 }, { 130 DeviceName: "sdb", 131 BusAddress: s.volumeAttachment.info.BusAddress, 132 }} 133 info, err := storagecommon.StorageAttachmentInfo(s.st, s.storageAttachment, s.machineTag) 134 c.Assert(err, jc.ErrorIsNil) 135 s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "BlockDevices") 136 c.Assert(info, jc.DeepEquals, &storage.StorageAttachmentInfo{ 137 Kind: storage.StorageKindBlock, 138 Location: filepath.FromSlash("/dev/sdb"), 139 }) 140 } 141 142 func (s *storageAttachmentInfoSuite) TestStorageAttachmentInfoNoBlockDevice(c *gc.C) { 143 // Neither the volume nor the volume attachment has enough information 144 // to persistently identify the path, so we must enquire about block 145 // devices; there are none (yet), so NotProvisioned is returned. 146 s.volumeAttachment.info.BusAddress = "scsi@1:2.3.4" 147 _, err := storagecommon.StorageAttachmentInfo(s.st, s.storageAttachment, s.machineTag) 148 c.Assert(err, jc.Satisfies, errors.IsNotProvisioned) 149 s.st.CheckCallNames(c, "StorageInstance", "StorageInstanceVolume", "VolumeAttachment", "BlockDevices") 150 } 151 152 type watchStorageAttachmentSuite struct { 153 storageTag names.StorageTag 154 machineTag names.MachineTag 155 unitTag names.UnitTag 156 st *fakeStorage 157 storageInstance *fakeStorageInstance 158 volume *fakeVolume 159 volumeAttachmentWatcher *apiservertesting.FakeNotifyWatcher 160 blockDevicesWatcher *apiservertesting.FakeNotifyWatcher 161 storageAttachmentWatcher *apiservertesting.FakeNotifyWatcher 162 } 163 164 var _ = gc.Suite(&watchStorageAttachmentSuite{}) 165 166 func (s *watchStorageAttachmentSuite) SetUpTest(c *gc.C) { 167 s.storageTag = names.NewStorageTag("osd-devices/0") 168 s.machineTag = names.NewMachineTag("0") 169 s.unitTag = names.NewUnitTag("ceph/0") 170 s.storageInstance = &fakeStorageInstance{ 171 tag: s.storageTag, 172 owner: s.machineTag, 173 kind: state.StorageKindBlock, 174 } 175 s.volume = &fakeVolume{tag: names.NewVolumeTag("0")} 176 s.volumeAttachmentWatcher = apiservertesting.NewFakeNotifyWatcher() 177 s.blockDevicesWatcher = apiservertesting.NewFakeNotifyWatcher() 178 s.storageAttachmentWatcher = apiservertesting.NewFakeNotifyWatcher() 179 s.st = &fakeStorage{ 180 storageInstance: func(tag names.StorageTag) (state.StorageInstance, error) { 181 return s.storageInstance, nil 182 }, 183 storageInstanceVolume: func(tag names.StorageTag) (state.Volume, error) { 184 return s.volume, nil 185 }, 186 watchVolumeAttachment: func(names.MachineTag, names.VolumeTag) state.NotifyWatcher { 187 return s.volumeAttachmentWatcher 188 }, 189 watchBlockDevices: func(names.MachineTag) state.NotifyWatcher { 190 return s.blockDevicesWatcher 191 }, 192 watchStorageAttachment: func(names.StorageTag, names.UnitTag) state.NotifyWatcher { 193 return s.storageAttachmentWatcher 194 }, 195 } 196 } 197 198 func (s *watchStorageAttachmentSuite) TestWatchStorageAttachmentVolumeAttachmentChanges(c *gc.C) { 199 s.testWatchBlockStorageAttachment(c, func() { 200 s.volumeAttachmentWatcher.C <- struct{}{} 201 }) 202 } 203 204 func (s *watchStorageAttachmentSuite) TestWatchStorageAttachmentStorageAttachmentChanges(c *gc.C) { 205 s.testWatchBlockStorageAttachment(c, func() { 206 s.storageAttachmentWatcher.C <- struct{}{} 207 }) 208 } 209 210 func (s *watchStorageAttachmentSuite) TestWatchStorageAttachmentBlockDevicesChange(c *gc.C) { 211 s.testWatchBlockStorageAttachment(c, func() { 212 s.blockDevicesWatcher.C <- struct{}{} 213 }) 214 } 215 216 func (s *watchStorageAttachmentSuite) testWatchBlockStorageAttachment(c *gc.C, change func()) { 217 s.testWatchStorageAttachment(c, change) 218 s.st.CheckCallNames(c, 219 "StorageInstance", 220 "StorageInstanceVolume", 221 "WatchVolumeAttachment", 222 "WatchBlockDevices", 223 "WatchStorageAttachment", 224 ) 225 } 226 227 func (s *watchStorageAttachmentSuite) testWatchStorageAttachment(c *gc.C, change func()) { 228 w, err := storagecommon.WatchStorageAttachment( 229 s.st, 230 s.storageTag, 231 s.machineTag, 232 s.unitTag, 233 ) 234 c.Assert(err, jc.ErrorIsNil) 235 wc := statetesting.NewNotifyWatcherC(c, nopSyncStarter{}, w) 236 wc.AssertOneChange() 237 change() 238 wc.AssertOneChange() 239 }