github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/state/blockdevices_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_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/mgo.v2/txn" 11 12 "github.com/juju/juju/state" 13 "github.com/juju/juju/state/testing" 14 ) 15 16 type BlockDevicesSuite struct { 17 ConnSuite 18 machine *state.Machine 19 } 20 21 var _ = gc.Suite(&BlockDevicesSuite{}) 22 23 func (s *BlockDevicesSuite) SetUpTest(c *gc.C) { 24 s.ConnSuite.SetUpTest(c) 25 var err error 26 s.machine, err = s.State.AddMachine("quantal", state.JobHostUnits) 27 c.Assert(err, jc.ErrorIsNil) 28 } 29 30 func (s *BlockDevicesSuite) assertBlockDevices(c *gc.C, m *state.Machine, expected map[string]state.BlockDeviceInfo) { 31 devices, err := m.BlockDevices() 32 c.Assert(err, jc.ErrorIsNil) 33 info := make(map[string]state.BlockDeviceInfo) 34 for _, dev := range devices { 35 devInfo, err := dev.Info() 36 if err != nil { 37 c.Assert(err, jc.Satisfies, errors.IsNotProvisioned) 38 devInfo = state.BlockDeviceInfo{} 39 } 40 info[dev.Name()] = devInfo 41 } 42 c.Assert(info, gc.DeepEquals, expected) 43 } 44 45 func (s *BlockDevicesSuite) TestSetMachineBlockDevices(c *gc.C) { 46 sda := state.BlockDeviceInfo{DeviceName: "sda"} 47 err := s.machine.SetMachineBlockDevices(sda) 48 c.Assert(err, jc.ErrorIsNil) 49 s.assertBlockDevices(c, s.machine, map[string]state.BlockDeviceInfo{"0": sda}) 50 } 51 52 func (s *BlockDevicesSuite) TestSetMachineBlockDevicesReplaces(c *gc.C) { 53 sda := state.BlockDeviceInfo{DeviceName: "sda"} 54 err := s.machine.SetMachineBlockDevices(sda) 55 c.Assert(err, jc.ErrorIsNil) 56 57 sdb := state.BlockDeviceInfo{DeviceName: "sdb"} 58 err = s.machine.SetMachineBlockDevices(sdb) 59 c.Assert(err, jc.ErrorIsNil) 60 s.assertBlockDevices(c, s.machine, map[string]state.BlockDeviceInfo{"1": sdb}) 61 } 62 63 func (s *BlockDevicesSuite) TestSetMachineBlockDevicesUpdates(c *gc.C) { 64 sda := state.BlockDeviceInfo{DeviceName: "sda"} 65 sdb := state.BlockDeviceInfo{DeviceName: "sdb"} 66 err := s.machine.SetMachineBlockDevices(sda, sdb) 67 c.Assert(err, jc.ErrorIsNil) 68 s.assertBlockDevices(c, s.machine, map[string]state.BlockDeviceInfo{"0": sda, "1": sdb}) 69 70 sdb.Label = "root" 71 err = s.machine.SetMachineBlockDevices(sdb) 72 c.Assert(err, jc.ErrorIsNil) 73 s.assertBlockDevices(c, s.machine, map[string]state.BlockDeviceInfo{"1": sdb}) 74 75 // If a device is attached, unattached, then attached again, 76 // then it gets a new name. 77 sdb.Label = "" // Label should be reset. 78 err = s.machine.SetMachineBlockDevices(sda, sdb) 79 c.Assert(err, jc.ErrorIsNil) 80 s.assertBlockDevices(c, s.machine, map[string]state.BlockDeviceInfo{ 81 "2": sda, 82 "1": sdb, 83 }) 84 } 85 86 func (s *BlockDevicesSuite) TestSetMachineBlockDevicesConcurrently(c *gc.C) { 87 sdaInner := state.BlockDeviceInfo{DeviceName: "sda"} 88 defer state.SetBeforeHooks(c, s.State, func() { 89 err := s.machine.SetMachineBlockDevices(sdaInner) 90 c.Assert(err, jc.ErrorIsNil) 91 }).Check() 92 93 sdaOuter := state.BlockDeviceInfo{ 94 DeviceName: "sda", 95 Label: "root", 96 } 97 err := s.machine.SetMachineBlockDevices(sdaOuter) 98 c.Assert(err, jc.ErrorIsNil) 99 100 // SetMachineBlockDevices will not remove concurrently added 101 // block devices. This is fine in practice, because there is 102 // a single worker responsible for populating machine block 103 // devices. 104 s.assertBlockDevices(c, s.machine, map[string]state.BlockDeviceInfo{ 105 "1": sdaInner, 106 // The outer call gets 0 because it's called first; 107 // the before-hook call is called second but completes 108 // first. 109 "0": sdaOuter, 110 }) 111 } 112 113 func (s *BlockDevicesSuite) TestSetMachineBlockDevicesEmpty(c *gc.C) { 114 sda := state.BlockDeviceInfo{DeviceName: "sda"} 115 err := s.machine.SetMachineBlockDevices(sda) 116 c.Assert(err, jc.ErrorIsNil) 117 s.assertBlockDevices(c, s.machine, map[string]state.BlockDeviceInfo{"0": sda}) 118 119 err = s.machine.SetMachineBlockDevices() 120 c.Assert(err, jc.ErrorIsNil) 121 s.assertBlockDevices(c, s.machine, map[string]state.BlockDeviceInfo{}) 122 } 123 124 func (s *BlockDevicesSuite) TestSetMachineBlockDevicesLeavesUnprovisioned(c *gc.C) { 125 m, err := s.State.AddOneMachine(state.MachineTemplate{ 126 Series: "quantal", 127 Jobs: []state.MachineJob{state.JobHostUnits}, 128 BlockDevices: []state.BlockDeviceParams{ 129 {Size: 123}, 130 }, 131 }) 132 c.Assert(err, jc.ErrorIsNil) 133 134 sda := state.BlockDeviceInfo{DeviceName: "sda"} 135 err = m.SetMachineBlockDevices(sda) 136 c.Assert(err, jc.ErrorIsNil) 137 s.assertBlockDevices(c, m, map[string]state.BlockDeviceInfo{ 138 "0": {}, // unprovisioned 139 "1": sda, 140 }) 141 } 142 143 func (s *BlockDevicesSuite) TestSetMachineBlockDevicesUpdatesProvisioned(c *gc.C) { 144 m, err := s.State.AddOneMachine(state.MachineTemplate{ 145 Series: "quantal", 146 Jobs: []state.MachineJob{state.JobHostUnits}, 147 BlockDevices: []state.BlockDeviceParams{ 148 {Size: 123}, 149 }, 150 }) 151 c.Assert(err, jc.ErrorIsNil) 152 153 sda := state.BlockDeviceInfo{ 154 DeviceName: "sda", Size: 123, 155 } 156 err = state.SetProvisionedBlockDeviceInfo(s.State, m.Id(), map[string]state.BlockDeviceInfo{ 157 "0": sda, 158 }) 159 c.Assert(err, jc.ErrorIsNil) 160 devices, err := m.BlockDevices() 161 c.Assert(err, jc.ErrorIsNil) 162 c.Assert(devices[0].Attached(), jc.IsFalse) 163 164 err = m.SetMachineBlockDevices(sda) 165 c.Assert(err, jc.ErrorIsNil) 166 s.assertBlockDevices(c, m, map[string]state.BlockDeviceInfo{ 167 "0": sda, 168 }) 169 devices, err = m.BlockDevices() 170 c.Assert(err, jc.ErrorIsNil) 171 c.Assert(devices[0].Attached(), jc.IsTrue) 172 } 173 174 func (s *BlockDevicesSuite) TestBlockDevicesMachineRemove(c *gc.C) { 175 sda := state.BlockDeviceInfo{DeviceName: "sda"} 176 err := s.machine.SetMachineBlockDevices(sda) 177 c.Assert(err, jc.ErrorIsNil) 178 179 err = s.machine.EnsureDead() 180 c.Assert(err, jc.ErrorIsNil) 181 err = s.machine.Remove() 182 c.Assert(err, jc.ErrorIsNil) 183 184 s.assertBlockDevices(c, s.machine, map[string]state.BlockDeviceInfo{}) 185 } 186 187 func (s *BlockDevicesSuite) TestBlockDeviceInfo(c *gc.C) { 188 sdaInfo := state.BlockDeviceInfo{DeviceName: "sda"} 189 err := state.RunTransaction(s.State, []txn.Op{{ 190 C: state.BlockDevicesC, 191 Id: "0", 192 Insert: &state.BlockDeviceDoc{Name: "0"}, 193 }, { 194 C: state.BlockDevicesC, 195 Id: "1", 196 Insert: &state.BlockDeviceDoc{Name: "1", Info: &sdaInfo}, 197 }}) 198 c.Assert(err, jc.ErrorIsNil) 199 200 b0, err := s.State.BlockDevice("0") 201 c.Assert(err, jc.ErrorIsNil) 202 _, err = b0.Info() 203 c.Assert(err, jc.Satisfies, errors.IsNotProvisioned) 204 b1, err := s.State.BlockDevice("1") 205 c.Assert(err, jc.ErrorIsNil) 206 info, err := b1.Info() 207 c.Assert(err, jc.ErrorIsNil) 208 c.Assert(info, gc.DeepEquals, sdaInfo) 209 } 210 211 func (s *BlockDevicesSuite) TestBlockDeviceParamsMethod(c *gc.C) { 212 disk1Params := state.BlockDeviceParams{Size: 123} 213 err := state.RunTransaction(s.State, []txn.Op{{ 214 C: state.BlockDevicesC, 215 Id: "0", 216 Insert: &state.BlockDeviceDoc{Name: "0"}, 217 }, { 218 C: state.BlockDevicesC, 219 Id: "1", 220 Insert: &state.BlockDeviceDoc{Name: "1", Params: &disk1Params}, 221 }}) 222 c.Assert(err, jc.ErrorIsNil) 223 224 b0, err := s.State.BlockDevice("0") 225 c.Assert(err, jc.ErrorIsNil) 226 _, ok := b0.Params() 227 c.Assert(ok, jc.IsFalse) 228 b1, err := s.State.BlockDevice("1") 229 c.Assert(err, jc.ErrorIsNil) 230 params, ok := b1.Params() 231 c.Assert(ok, jc.IsTrue) 232 c.Assert(params, gc.DeepEquals, disk1Params) 233 } 234 235 func (s *BlockDevicesSuite) TestMachineWatchBlockDevices(c *gc.C) { 236 sda := state.BlockDeviceInfo{DeviceName: "sda"} 237 sdb := state.BlockDeviceInfo{DeviceName: "sdb"} 238 sdc := state.BlockDeviceInfo{DeviceName: "sdc"} 239 err := s.machine.SetMachineBlockDevices(sda, sdb, sdc) 240 c.Assert(err, jc.ErrorIsNil) 241 242 // Start block device watcher. 243 w := s.machine.WatchBlockDevices() 244 defer testing.AssertStop(c, w) 245 wc := testing.NewStringsWatcherC(c, s.State, w) 246 assertOneChange := func(names ...string) { 247 wc.AssertChangeInSingleEvent(names...) 248 wc.AssertNoChange() 249 } 250 assertOneChange("0", "1", "2") 251 252 // Setting the same should not trigger the watcher. 253 err = s.machine.SetMachineBlockDevices(sdc, sdb, sda) 254 c.Assert(err, jc.ErrorIsNil) 255 wc.AssertNoChange() 256 257 // change sdb's label. 258 sdb.Label = "fatty" 259 err = s.machine.SetMachineBlockDevices(sda, sdb, sdc) 260 c.Assert(err, jc.ErrorIsNil) 261 assertOneChange("1") 262 263 // change sda's label and sdb's UUID at once. 264 sda.Label = "giggly" 265 sdb.UUID = "4c062658-6225-4f4b-96f3-debf00b964b4" 266 err = s.machine.SetMachineBlockDevices(sda, sdb, sdc) 267 c.Assert(err, jc.ErrorIsNil) 268 assertOneChange("0", "1") 269 270 // drop sdc. 271 err = s.machine.SetMachineBlockDevices(sda, sdb) 272 c.Assert(err, jc.ErrorIsNil) 273 assertOneChange("2") 274 275 // add sdc again: should get a new name. 276 err = s.machine.SetMachineBlockDevices(sda, sdb, sdc) 277 c.Assert(err, jc.ErrorIsNil) 278 assertOneChange("3") 279 }