github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/storage_dynamicadd_test.go (about) 1 // Copyright 2015 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/juju/names.v2" 11 12 "github.com/juju/juju/state" 13 ) 14 15 type storageAddSuite struct { 16 StorageStateSuiteBase 17 18 unitTag names.UnitTag 19 machineTag names.MachineTag 20 21 originalStorageCount int 22 originalVolumeCount int 23 originalFilesystemCount int 24 } 25 26 var _ = gc.Suite(&storageAddSuite{}) 27 28 func (s *storageAddSuite) setupMultipleStoragesForAdd(c *gc.C) *state.Unit { 29 storageCons := map[string]state.StorageConstraints{ 30 "multi1to10": makeStorageCons("loop", 0, 3), 31 } 32 charm := s.AddTestingCharm(c, "storage-block2") 33 service, err := s.State.AddApplication(state.AddApplicationArgs{Name: "storage-block2", Charm: charm, Storage: storageCons}) 34 c.Assert(err, jc.ErrorIsNil) 35 u, err := service.AddUnit() 36 c.Assert(err, jc.ErrorIsNil) 37 s.unitTag = u.UnitTag() 38 all, err := s.State.AllStorageInstances() 39 c.Assert(err, jc.ErrorIsNil) 40 s.originalStorageCount = len(all) 41 return u 42 } 43 44 func (s *storageAddSuite) assignUnit(c *gc.C, u *state.Unit) { 45 // Assign unit to machine to get volumes and filesystems 46 err := s.State.AssignUnit(u, state.AssignCleanEmpty) 47 c.Assert(err, jc.ErrorIsNil) 48 machineId, err := u.AssignedMachineId() 49 c.Assert(err, jc.ErrorIsNil) 50 51 m, err := s.State.Machine(machineId) 52 c.Assert(err, jc.ErrorIsNil) 53 s.machineTag = m.MachineTag() 54 55 volumes, err := s.State.AllVolumes() 56 c.Assert(err, jc.ErrorIsNil) 57 s.originalVolumeCount = len(volumes) 58 59 filesystems, err := s.State.MachineFilesystemAttachments(s.machineTag) 60 c.Assert(err, jc.ErrorIsNil) 61 s.originalFilesystemCount = len(filesystems) 62 } 63 64 func (s *storageAddSuite) assertStorageCount(c *gc.C, count int) { 65 all, err := s.State.AllStorageInstances() 66 c.Assert(err, jc.ErrorIsNil) 67 c.Assert(all, gc.HasLen, count) 68 } 69 70 func (s *storageAddSuite) assertVolumeCount(c *gc.C, count int) { 71 all, err := s.State.AllVolumes() 72 c.Assert(err, jc.ErrorIsNil) 73 c.Assert(all, gc.HasLen, count) 74 } 75 76 func (s *storageAddSuite) assertFileSystemCount(c *gc.C, count int) { 77 all, err := s.State.MachineFilesystemAttachments(s.machineTag) 78 c.Assert(err, jc.ErrorIsNil) 79 c.Assert(all, gc.HasLen, count) 80 } 81 82 func (s *storageAddSuite) TestAddStorageToUnit(c *gc.C) { 83 u := s.setupMultipleStoragesForAdd(c) 84 s.assignUnit(c, u) 85 86 err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", makeStorageCons("loop-pool", 1024, 1)) 87 c.Assert(err, jc.ErrorIsNil) 88 s.assertStorageCount(c, s.originalStorageCount+1) 89 s.assertVolumeCount(c, s.originalVolumeCount+1) 90 s.assertFileSystemCount(c, s.originalFilesystemCount) 91 assertMachineStorageRefs(c, s.State, s.machineTag) 92 } 93 94 func (s *storageAddSuite) TestAddStorageToUnitNotAssigned(c *gc.C) { 95 u := s.setupMultipleStoragesForAdd(c) 96 // don't assign unit 97 98 err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", makeStorageCons("loop-pool", 1024, 1)) 99 c.Assert(err, jc.ErrorIsNil) 100 s.assertStorageCount(c, s.originalStorageCount+1) 101 s.assertVolumeCount(c, 0) 102 s.assertFileSystemCount(c, 0) 103 104 s.assignUnit(c, u) 105 s.assertVolumeCount(c, 6) 106 s.assertFileSystemCount(c, 0) 107 } 108 109 func (s *storageAddSuite) TestAddStorageWithCount(c *gc.C) { 110 u := s.setupMultipleStoragesForAdd(c) 111 s.assignUnit(c, u) 112 err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", makeStorageCons("loop-pool", 1024, 2)) 113 c.Assert(err, jc.ErrorIsNil) 114 s.assertStorageCount(c, s.originalStorageCount+2) 115 s.assertVolumeCount(c, s.originalVolumeCount+2) 116 s.assertFileSystemCount(c, s.originalFilesystemCount) 117 assertMachineStorageRefs(c, s.State, s.machineTag) 118 } 119 120 func (s *storageAddSuite) TestAddStorageMultipleCalls(c *gc.C) { 121 u := s.setupMultipleStoragesForAdd(c) 122 s.assignUnit(c, u) 123 124 err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", makeStorageCons("loop-pool", 1024, 2)) 125 c.Assert(err, jc.ErrorIsNil) 126 s.assertStorageCount(c, s.originalStorageCount+2) 127 128 // Should not succeed as the number of storages after 129 // this call would be 11 whereas our upper limit is 10 here. 130 err = s.State.AddStorageForUnit(s.unitTag, "multi1to10", makeStorageCons("loop-pool", 1024, 6)) 131 c.Assert(err, gc.ErrorMatches, `.*charm "storage-block2" store "multi1to10": at most 10 instances supported, 11 specified.*`) 132 s.assertStorageCount(c, s.originalStorageCount+2) 133 s.assertVolumeCount(c, s.originalVolumeCount+2) 134 s.assertFileSystemCount(c, s.originalFilesystemCount) 135 assertMachineStorageRefs(c, s.State, s.machineTag) 136 } 137 138 func (s *storageAddSuite) TestAddStorageToDyingUnitFails(c *gc.C) { 139 s.setupMultipleStoragesForAdd(c) 140 141 defer state.SetBeforeHooks(c, s.State, func() { 142 u, err := s.State.Unit(s.unitTag.Id()) 143 c.Assert(err, jc.ErrorIsNil) 144 err = u.Destroy() 145 c.Assert(err, jc.ErrorIsNil) 146 }).Check() 147 148 err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", makeStorageCons("loop-pool", 1024, 1)) 149 c.Assert(err, gc.ErrorMatches, `adding storage to unit storage-block2/0: unit is not alive`) 150 151 s.assertStorageCount(c, s.originalStorageCount) 152 } 153 154 func (s *storageAddSuite) TestAddStorageExceedCount(c *gc.C) { 155 _, u, _ := s.setupSingleStorage(c, "block", "loop-pool") 156 s.assertStorageCount(c, 1) 157 158 err := s.State.AddStorageForUnit(u.UnitTag(), "data", makeStorageCons("loop-pool", 1024, 1)) 159 c.Assert(err, gc.ErrorMatches, `.*charm "storage-block" store "data": at most 1 instances supported, 2 specified.*`) 160 s.assertStorageCount(c, 1) 161 s.assertVolumeCount(c, 0) 162 s.assertFileSystemCount(c, 0) 163 } 164 165 func (s *storageAddSuite) createAndAssignUnitWithSingleStorage(c *gc.C) names.UnitTag { 166 _, u, _ := s.setupSingleStorage(c, "block", "loop-pool") 167 s.assertStorageCount(c, 1) 168 169 // Assign unit to machine to get volumes and filesystems 170 err := s.State.AssignUnit(u, state.AssignCleanEmpty) 171 c.Assert(err, jc.ErrorIsNil) 172 173 volumes, err := s.State.AllVolumes() 174 c.Assert(err, jc.ErrorIsNil) 175 s.originalVolumeCount = len(volumes) 176 177 filesystems, err := s.State.MachineFilesystemAttachments(s.machineTag) 178 c.Assert(err, jc.ErrorIsNil) 179 s.originalFilesystemCount = len(filesystems) 180 181 return u.UnitTag() 182 } 183 184 func (s *storageAddSuite) TestAddStorageMinCount(c *gc.C) { 185 unit := s.createAndAssignUnitWithSingleStorage(c) 186 err := s.State.AddStorageForUnit(unit, "allecto", makeStorageCons("loop-pool", 1024, 1)) 187 c.Assert(err, jc.ErrorIsNil) 188 s.assertStorageCount(c, 2) 189 s.assertVolumeCount(c, 2) 190 s.assertFileSystemCount(c, 0) 191 assertMachineStorageRefs(c, s.State, s.machineTag) 192 } 193 194 func (s *storageAddSuite) TestAddStorageZeroCount(c *gc.C) { 195 unit := s.createAndAssignUnitWithSingleStorage(c) 196 err := s.State.AddStorageForUnit(unit, "allecto", state.StorageConstraints{Pool: "loop-pool", Size: 1024}) 197 c.Assert(errors.Cause(err), gc.ErrorMatches, "adding storage where instance count is 0 not valid") 198 s.assertStorageCount(c, 1) 199 s.assertVolumeCount(c, 1) 200 s.assertFileSystemCount(c, 0) 201 assertMachineStorageRefs(c, s.State, s.machineTag) 202 } 203 204 func (s *storageAddSuite) TestAddStorageTriggerDefaultPopulated(c *gc.C) { 205 u := s.setupMultipleStoragesForAdd(c) 206 s.assignUnit(c, u) 207 208 err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", state.StorageConstraints{Count: 1}) 209 c.Assert(err, jc.ErrorIsNil) 210 s.assertStorageCount(c, s.originalStorageCount+1) 211 s.assertVolumeCount(c, s.originalVolumeCount+1) 212 s.assertFileSystemCount(c, s.originalFilesystemCount) 213 assertMachineStorageRefs(c, s.State, s.machineTag) 214 } 215 216 func (s *storageAddSuite) TestAddStorageDiffPool(c *gc.C) { 217 u := s.setupMultipleStoragesForAdd(c) 218 s.assignUnit(c, u) 219 220 err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", state.StorageConstraints{Pool: "loop-pool", Count: 1}) 221 c.Assert(err, jc.ErrorIsNil) 222 s.assertStorageCount(c, s.originalStorageCount+1) 223 s.assertVolumeCount(c, s.originalVolumeCount+1) 224 s.assertFileSystemCount(c, s.originalFilesystemCount) 225 assertMachineStorageRefs(c, s.State, s.machineTag) 226 } 227 228 func (s *storageAddSuite) TestAddStorageDiffSize(c *gc.C) { 229 u := s.setupMultipleStoragesForAdd(c) 230 s.assignUnit(c, u) 231 232 err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", state.StorageConstraints{Size: 2048, Count: 1}) 233 c.Assert(err, jc.ErrorIsNil) 234 s.assertStorageCount(c, s.originalStorageCount+1) 235 s.assertVolumeCount(c, s.originalVolumeCount+1) 236 s.assertFileSystemCount(c, s.originalFilesystemCount) 237 assertMachineStorageRefs(c, s.State, s.machineTag) 238 } 239 240 func (s *storageAddSuite) TestAddStorageLessMinSize(c *gc.C) { 241 u := s.setupMultipleStoragesForAdd(c) 242 s.assignUnit(c, u) 243 244 err := s.State.AddStorageForUnit(s.unitTag, "multi2up", state.StorageConstraints{Size: 2, Count: 1}) 245 c.Assert(err, gc.ErrorMatches, `.*charm "storage-block2" store "multi2up": minimum storage size is 2.0GB, 2.0MB specified.*`) 246 s.assertStorageCount(c, s.originalStorageCount) 247 s.assertVolumeCount(c, s.originalVolumeCount) 248 s.assertFileSystemCount(c, s.originalFilesystemCount) 249 assertMachineStorageRefs(c, s.State, s.machineTag) 250 } 251 252 func (s *storageAddSuite) TestAddStorageWrongName(c *gc.C) { 253 u := s.setupMultipleStoragesForAdd(c) 254 s.assignUnit(c, u) 255 256 err := s.State.AddStorageForUnit(s.unitTag, "furball", state.StorageConstraints{Size: 2}) 257 c.Assert(err, gc.ErrorMatches, `.*charm storage "furball" not found.*`) 258 s.assertStorageCount(c, s.originalStorageCount) 259 s.assertVolumeCount(c, s.originalVolumeCount) 260 s.assertFileSystemCount(c, s.originalFilesystemCount) 261 } 262 263 func (s *storageAddSuite) TestAddStorageConcurrently(c *gc.C) { 264 u := s.setupMultipleStoragesForAdd(c) 265 s.assignUnit(c, u) 266 267 addStorage := func() { 268 err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", state.StorageConstraints{Count: 1}) 269 c.Assert(err, jc.ErrorIsNil) 270 } 271 defer state.SetBeforeHooks(c, s.State, addStorage).Check() 272 addStorage() 273 s.assertStorageCount(c, s.originalStorageCount+2) 274 s.assertVolumeCount(c, s.originalVolumeCount+2) 275 s.assertFileSystemCount(c, s.originalFilesystemCount) 276 assertMachineStorageRefs(c, s.State, s.machineTag) 277 } 278 279 func (s *storageAddSuite) TestAddStorageConcurrentlyExceedCount(c *gc.C) { 280 u := s.setupMultipleStoragesForAdd(c) 281 s.assignUnit(c, u) 282 283 count := 6 284 addStorage := func() { 285 err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", state.StorageConstraints{Count: uint64(count)}) 286 c.Assert(err, jc.ErrorIsNil) 287 } 288 defer state.SetBeforeHooks(c, s.State, addStorage).Check() 289 err := s.State.AddStorageForUnit(s.unitTag, "multi1to10", state.StorageConstraints{Count: uint64(count)}) 290 c.Assert(err, gc.ErrorMatches, `.*charm "storage-block2" store "multi1to10": at most 10 instances supported, 15 specified.*`) 291 292 // Only "count" number of instances should have been added. 293 s.assertStorageCount(c, s.originalStorageCount+count) 294 s.assertVolumeCount(c, s.originalVolumeCount+count) 295 s.assertFileSystemCount(c, s.originalFilesystemCount) 296 assertMachineStorageRefs(c, s.State, s.machineTag) 297 } 298 299 func (s *storageAddSuite) TestAddStorageFilesystem(c *gc.C) { 300 _, u, _ := s.setupSingleStorage(c, "filesystem", "loop-pool") 301 302 // Assign unit to machine to get volumes and filesystems 303 err := s.State.AssignUnit(u, state.AssignCleanEmpty) 304 c.Assert(err, jc.ErrorIsNil) 305 machineId, err := u.AssignedMachineId() 306 c.Assert(err, jc.ErrorIsNil) 307 s.machineTag = names.NewMachineTag(machineId) 308 s.assertFileSystemCount(c, 1) 309 310 s.assertStorageCount(c, 1) 311 s.assertVolumeCount(c, 1) 312 s.assertFileSystemCount(c, 1) 313 314 err = s.State.AddStorageForUnit(u.UnitTag(), "data", makeStorageCons("loop-pool", 1024, 1)) 315 c.Assert(err, jc.ErrorIsNil) 316 s.assertStorageCount(c, 2) 317 s.assertVolumeCount(c, 2) 318 s.assertFileSystemCount(c, 2) 319 assertMachineStorageRefs(c, s.State, s.machineTag) 320 } 321 322 func (s *storageAddSuite) TestAddStorageStatic(c *gc.C) { 323 // Create a unit with static storage; ensure that storage-add 324 // fails to add more of this kind of storage. 325 _, u, _ := s.setupSingleStorage(c, "filesystem", "static") 326 s.assertStorageCount(c, 1) 327 328 // Assign unit to machine to get volumes and filesystems 329 err := s.State.AssignUnit(u, state.AssignCleanEmpty) 330 c.Assert(err, jc.ErrorIsNil) 331 machineId, err := u.AssignedMachineId() 332 c.Assert(err, jc.ErrorIsNil) 333 s.machineTag = names.NewMachineTag(machineId) 334 s.assertFileSystemCount(c, 1) 335 336 err = s.State.AddStorageForUnit( 337 u.UnitTag(), "data", 338 makeStorageCons("static", 1024, 1), 339 ) 340 c.Assert(err, gc.ErrorMatches, "adding storage to unit storage-filesystem/0: "+ 341 "creating machine storage for storage data/1: "+ 342 `"static" storage provider does not support dynamic storage`) 343 s.assertStorageCount(c, 1) // no change 344 s.assertFileSystemCount(c, 1) // no change 345 assertMachineStorageRefs(c, s.State, s.machineTag) 346 }