github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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 "github.com/juju/names" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 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.volumeAttachmentWatcher.C <- struct{}{} 178 s.blockDevicesWatcher = apiservertesting.NewFakeNotifyWatcher() 179 s.blockDevicesWatcher.C <- struct{}{} 180 s.storageAttachmentWatcher = apiservertesting.NewFakeNotifyWatcher() 181 s.storageAttachmentWatcher.C <- struct{}{} 182 s.st = &fakeStorage{ 183 storageInstance: func(tag names.StorageTag) (state.StorageInstance, error) { 184 return s.storageInstance, nil 185 }, 186 storageInstanceVolume: func(tag names.StorageTag) (state.Volume, error) { 187 return s.volume, nil 188 }, 189 watchVolumeAttachment: func(names.MachineTag, names.VolumeTag) state.NotifyWatcher { 190 return s.volumeAttachmentWatcher 191 }, 192 watchBlockDevices: func(names.MachineTag) state.NotifyWatcher { 193 return s.blockDevicesWatcher 194 }, 195 watchStorageAttachment: func(names.StorageTag, names.UnitTag) state.NotifyWatcher { 196 return s.storageAttachmentWatcher 197 }, 198 } 199 } 200 201 func (s *watchStorageAttachmentSuite) TestWatchStorageAttachmentVolumeAttachmentChanges(c *gc.C) { 202 s.testWatchBlockStorageAttachment(c, func() { 203 s.volumeAttachmentWatcher.C <- struct{}{} 204 }) 205 } 206 207 func (s *watchStorageAttachmentSuite) TestWatchStorageAttachmentStorageAttachmentChanges(c *gc.C) { 208 s.testWatchBlockStorageAttachment(c, func() { 209 s.storageAttachmentWatcher.C <- struct{}{} 210 }) 211 } 212 213 func (s *watchStorageAttachmentSuite) TestWatchStorageAttachmentBlockDevicesChange(c *gc.C) { 214 s.testWatchBlockStorageAttachment(c, func() { 215 s.blockDevicesWatcher.C <- struct{}{} 216 }) 217 } 218 219 func (s *watchStorageAttachmentSuite) testWatchBlockStorageAttachment(c *gc.C, change func()) { 220 s.testWatchStorageAttachment(c, change) 221 s.st.CheckCallNames(c, 222 "StorageInstance", 223 "StorageInstanceVolume", 224 "WatchVolumeAttachment", 225 "WatchBlockDevices", 226 "WatchStorageAttachment", 227 ) 228 } 229 230 func (s *watchStorageAttachmentSuite) testWatchStorageAttachment(c *gc.C, change func()) { 231 w, err := storagecommon.WatchStorageAttachment( 232 s.st, 233 s.storageTag, 234 s.machineTag, 235 s.unitTag, 236 ) 237 c.Assert(err, jc.ErrorIsNil) 238 wc := statetesting.NewNotifyWatcherC(c, nopSyncStarter{}, w) 239 wc.AssertOneChange() 240 change() 241 wc.AssertOneChange() 242 }