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