github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/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 "github.com/juju/names/v5" 9 jc "github.com/juju/testing/checkers" 10 gc "gopkg.in/check.v1" 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("persistent-block", 0, 3), 31 } 32 charm := s.AddTestingCharm(c, "storage-block2") 33 application, err := s.State.AddApplication(state.AddApplicationArgs{ 34 Name: "storage-block2", Charm: charm, Storage: storageCons, 35 CharmOrigin: &state.CharmOrigin{Platform: &state.Platform{ 36 OS: "ubuntu", 37 Channel: "22.04/stable", 38 }}, 39 }) 40 c.Assert(err, jc.ErrorIsNil) 41 u, err := application.AddUnit(state.AddUnitParams{}) 42 c.Assert(err, jc.ErrorIsNil) 43 s.unitTag = u.UnitTag() 44 all, err := s.storageBackend.AllStorageInstances() 45 c.Assert(err, jc.ErrorIsNil) 46 s.originalStorageCount = len(all) 47 return u 48 } 49 50 func (s *storageAddSuite) assignUnit(c *gc.C, u *state.Unit) { 51 // Assign unit to machine to get volumes and filesystems 52 err := s.State.AssignUnit(u, state.AssignCleanEmpty) 53 c.Assert(err, jc.ErrorIsNil) 54 machineId, err := u.AssignedMachineId() 55 c.Assert(err, jc.ErrorIsNil) 56 57 m, err := s.State.Machine(machineId) 58 c.Assert(err, jc.ErrorIsNil) 59 s.machineTag = m.MachineTag() 60 61 volumes, err := s.storageBackend.AllVolumes() 62 c.Assert(err, jc.ErrorIsNil) 63 s.originalVolumeCount = len(volumes) 64 65 filesystems, err := s.storageBackend.MachineFilesystemAttachments(s.machineTag) 66 c.Assert(err, jc.ErrorIsNil) 67 s.originalFilesystemCount = len(filesystems) 68 } 69 70 func (s *storageAddSuite) assertStorageCount(c *gc.C, count int) { 71 all, err := s.storageBackend.AllStorageInstances() 72 c.Assert(err, jc.ErrorIsNil) 73 c.Assert(all, gc.HasLen, count) 74 } 75 76 func (s *storageAddSuite) assertVolumeCount(c *gc.C, count int) { 77 all, err := s.storageBackend.AllVolumes() 78 c.Assert(err, jc.ErrorIsNil) 79 c.Assert(all, gc.HasLen, count) 80 } 81 82 func (s *storageAddSuite) assertFileSystemCount(c *gc.C, count int) { 83 all, err := s.storageBackend.MachineFilesystemAttachments(s.machineTag) 84 c.Assert(err, jc.ErrorIsNil) 85 c.Assert(all, gc.HasLen, count) 86 } 87 88 func (s *storageAddSuite) TestAddStorageToUnit(c *gc.C) { 89 u := s.setupMultipleStoragesForAdd(c) 90 s.assignUnit(c, u) 91 92 tags, err := s.storageBackend.AddStorageForUnit(s.unitTag, "multi1to10", makeStorageCons("loop-pool", 4096, 1)) 93 c.Assert(err, jc.ErrorIsNil) 94 c.Assert(tags, jc.DeepEquals, []names.StorageTag{ 95 names.NewStorageTag("multi1to10/5"), 96 }) 97 98 s.assertStorageCount(c, s.originalStorageCount+1) 99 s.assertVolumeCount(c, s.originalVolumeCount+1) 100 s.assertFileSystemCount(c, s.originalFilesystemCount) 101 assertMachineStorageRefs(c, s.storageBackend, s.machineTag) 102 103 allVolumeParams := allMachineVolumeParams(c, s.storageBackend, s.machineTag) 104 c.Assert(allVolumeParams, jc.SameContents, []state.VolumeParams{ 105 {Pool: "persistent-block", Size: 1024}, // multi1to10 106 {Pool: "persistent-block", Size: 1024}, // multi1to10 107 {Pool: "persistent-block", Size: 1024}, // multi1to10 108 {Pool: "loop", Size: 2048}, // multi2up 109 {Pool: "loop", Size: 2048}, // multi2up 110 {Pool: "loop-pool", Size: 4096}, // added above 111 }) 112 } 113 114 func (s *storageAddSuite) TestAddStorageToUnitInheritPoolAndSize(c *gc.C) { 115 u := s.setupMultipleStoragesForAdd(c) 116 s.assignUnit(c, u) 117 118 _, err := s.storageBackend.AddStorageForUnit(s.unitTag, "multi1to10", state.StorageConstraints{Count: 1}) 119 c.Assert(err, jc.ErrorIsNil) 120 121 allVolumeParams := allMachineVolumeParams(c, s.storageBackend, s.machineTag) 122 c.Assert(allVolumeParams, jc.SameContents, []state.VolumeParams{ 123 {Pool: "persistent-block", Size: 1024}, 124 {Pool: "persistent-block", Size: 1024}, 125 {Pool: "persistent-block", Size: 1024}, 126 {Pool: "persistent-block", Size: 1024}, 127 {Pool: "loop", Size: 2048}, 128 {Pool: "loop", Size: 2048}, 129 }) 130 } 131 132 func (s *storageAddSuite) TestAddStorageToUnitNotAssigned(c *gc.C) { 133 u := s.setupMultipleStoragesForAdd(c) 134 // don't assign unit 135 136 _, err := s.storageBackend.AddStorageForUnit(s.unitTag, "multi1to10", makeStorageCons("loop-pool", 4096, 1)) 137 c.Assert(err, jc.ErrorIsNil) 138 s.assertStorageCount(c, s.originalStorageCount+1) 139 s.assertVolumeCount(c, 0) 140 s.assertFileSystemCount(c, 0) 141 142 s.assignUnit(c, u) 143 s.assertVolumeCount(c, 6) 144 s.assertFileSystemCount(c, 0) 145 146 allVolumeParams := allMachineVolumeParams(c, s.storageBackend, s.machineTag) 147 c.Assert(allVolumeParams, jc.SameContents, []state.VolumeParams{ 148 {Pool: "persistent-block", Size: 1024}, 149 {Pool: "persistent-block", Size: 1024}, 150 {Pool: "persistent-block", Size: 1024}, 151 {Pool: "loop", Size: 2048}, 152 {Pool: "loop", Size: 2048}, 153 {Pool: "loop-pool", Size: 4096}, 154 }) 155 } 156 157 func allMachineVolumeParams(c *gc.C, sb *state.StorageBackend, m names.MachineTag) []state.VolumeParams { 158 var allVolumeParams []state.VolumeParams 159 volumeAttachments, err := sb.MachineVolumeAttachments(m) 160 c.Assert(err, jc.ErrorIsNil) 161 for _, a := range volumeAttachments { 162 volume, err := sb.Volume(a.Volume()) 163 c.Assert(err, jc.ErrorIsNil) 164 volumeParams, ok := volume.Params() 165 c.Assert(ok, jc.IsTrue) 166 allVolumeParams = append(allVolumeParams, volumeParams) 167 } 168 return allVolumeParams 169 } 170 171 func (s *storageAddSuite) TestAddStorageWithCount(c *gc.C) { 172 u := s.setupMultipleStoragesForAdd(c) 173 s.assignUnit(c, u) 174 tags, err := s.storageBackend.AddStorageForUnit(s.unitTag, "multi1to10", makeStorageCons("loop-pool", 1024, 2)) 175 c.Assert(err, jc.ErrorIsNil) 176 c.Assert(tags, jc.DeepEquals, []names.StorageTag{ 177 names.NewStorageTag("multi1to10/5"), 178 names.NewStorageTag("multi1to10/6"), 179 }) 180 s.assertStorageCount(c, s.originalStorageCount+2) 181 s.assertVolumeCount(c, s.originalVolumeCount+2) 182 s.assertFileSystemCount(c, s.originalFilesystemCount) 183 assertMachineStorageRefs(c, s.storageBackend, s.machineTag) 184 } 185 186 func (s *storageAddSuite) TestAddStorageMultipleCalls(c *gc.C) { 187 u := s.setupMultipleStoragesForAdd(c) 188 s.assignUnit(c, u) 189 190 _, err := s.storageBackend.AddStorageForUnit(s.unitTag, "multi1to10", makeStorageCons("loop-pool", 1024, 2)) 191 c.Assert(err, jc.ErrorIsNil) 192 s.assertStorageCount(c, s.originalStorageCount+2) 193 194 // Should not succeed as the number of storages after 195 // this call would be 11 whereas our upper limit is 10 here. 196 _, err = s.storageBackend.AddStorageForUnit(s.unitTag, "multi1to10", makeStorageCons("loop-pool", 1024, 6)) 197 c.Assert(err, gc.ErrorMatches, 198 `adding "multi1to10" storage to storage-block2/0: `+ 199 `attaching 6 storage instances brings the total to 11, exceeding the maximum of 10`) 200 s.assertStorageCount(c, s.originalStorageCount+2) 201 s.assertVolumeCount(c, s.originalVolumeCount+2) 202 s.assertFileSystemCount(c, s.originalFilesystemCount) 203 assertMachineStorageRefs(c, s.storageBackend, s.machineTag) 204 } 205 206 func (s *storageAddSuite) TestAddStorageToDyingUnitFails(c *gc.C) { 207 s.setupMultipleStoragesForAdd(c) 208 209 defer state.SetBeforeHooks(c, s.State, func() { 210 u, err := s.State.Unit(s.unitTag.Id()) 211 c.Assert(err, jc.ErrorIsNil) 212 err = u.Destroy() 213 c.Assert(err, jc.ErrorIsNil) 214 }).Check() 215 216 _, err := s.storageBackend.AddStorageForUnit(s.unitTag, "multi1to10", makeStorageCons("loop-pool", 1024, 1)) 217 c.Assert(err, gc.ErrorMatches, `adding "multi1to10" storage to storage-block2/0: unit is not found or not alive`) 218 219 s.assertStorageCount(c, s.originalStorageCount) 220 } 221 222 func (s *storageAddSuite) TestAddStorageExceedCount(c *gc.C) { 223 _, u, _ := s.setupSingleStorage(c, "block", "loop-pool") 224 s.assertStorageCount(c, 1) 225 226 _, err := s.storageBackend.AddStorageForUnit(u.UnitTag(), "data", makeStorageCons("loop-pool", 1024, 1)) 227 c.Assert(err, gc.ErrorMatches, `adding "data" storage to storage-block/0: cannot attach, storage is singular`) 228 s.assertStorageCount(c, 1) 229 s.assertVolumeCount(c, 0) 230 s.assertFileSystemCount(c, 0) 231 } 232 233 func (s *storageAddSuite) createAndAssignUnitWithSingleStorage(c *gc.C) names.UnitTag { 234 _, u, _ := s.setupSingleStorage(c, "block", "loop-pool") 235 s.assertStorageCount(c, 1) 236 237 // Assign unit to machine to get volumes and filesystems 238 err := s.State.AssignUnit(u, state.AssignCleanEmpty) 239 c.Assert(err, jc.ErrorIsNil) 240 241 volumes, err := s.storageBackend.AllVolumes() 242 c.Assert(err, jc.ErrorIsNil) 243 s.originalVolumeCount = len(volumes) 244 245 filesystems, err := s.storageBackend.MachineFilesystemAttachments(s.machineTag) 246 c.Assert(err, jc.ErrorIsNil) 247 s.originalFilesystemCount = len(filesystems) 248 249 return u.UnitTag() 250 } 251 252 func (s *storageAddSuite) TestAddStorageMinCount(c *gc.C) { 253 unit := s.createAndAssignUnitWithSingleStorage(c) 254 _, err := s.storageBackend.AddStorageForUnit(unit, "allecto", makeStorageCons("loop-pool", 1024, 1)) 255 c.Assert(err, jc.ErrorIsNil) 256 s.assertStorageCount(c, 2) 257 s.assertVolumeCount(c, 2) 258 s.assertFileSystemCount(c, 0) 259 assertMachineStorageRefs(c, s.storageBackend, s.machineTag) 260 } 261 262 func (s *storageAddSuite) TestAddStorageZeroCount(c *gc.C) { 263 unit := s.createAndAssignUnitWithSingleStorage(c) 264 _, err := s.storageBackend.AddStorageForUnit(unit, "allecto", state.StorageConstraints{Pool: "loop-pool", Size: 1024}) 265 c.Assert(errors.Cause(err), gc.ErrorMatches, "adding storage where instance count is 0 not valid") 266 s.assertStorageCount(c, 1) 267 s.assertVolumeCount(c, 1) 268 s.assertFileSystemCount(c, 0) 269 assertMachineStorageRefs(c, s.storageBackend, s.machineTag) 270 } 271 272 func (s *storageAddSuite) TestAddStorageTriggerDefaultPopulated(c *gc.C) { 273 u := s.setupMultipleStoragesForAdd(c) 274 s.assignUnit(c, u) 275 276 _, err := s.storageBackend.AddStorageForUnit(s.unitTag, "multi1to10", state.StorageConstraints{Count: 1}) 277 c.Assert(err, jc.ErrorIsNil) 278 s.assertStorageCount(c, s.originalStorageCount+1) 279 s.assertVolumeCount(c, s.originalVolumeCount+1) 280 s.assertFileSystemCount(c, s.originalFilesystemCount) 281 assertMachineStorageRefs(c, s.storageBackend, s.machineTag) 282 } 283 284 func (s *storageAddSuite) TestAddStorageDiffPool(c *gc.C) { 285 u := s.setupMultipleStoragesForAdd(c) 286 s.assignUnit(c, u) 287 288 _, err := s.storageBackend.AddStorageForUnit(s.unitTag, "multi1to10", state.StorageConstraints{Pool: "loop-pool", Count: 1}) 289 c.Assert(err, jc.ErrorIsNil) 290 s.assertStorageCount(c, s.originalStorageCount+1) 291 s.assertVolumeCount(c, s.originalVolumeCount+1) 292 s.assertFileSystemCount(c, s.originalFilesystemCount) 293 assertMachineStorageRefs(c, s.storageBackend, s.machineTag) 294 } 295 296 func (s *storageAddSuite) TestAddStorageDiffSize(c *gc.C) { 297 u := s.setupMultipleStoragesForAdd(c) 298 s.assignUnit(c, u) 299 300 _, err := s.storageBackend.AddStorageForUnit(s.unitTag, "multi1to10", state.StorageConstraints{Size: 2048, Count: 1}) 301 c.Assert(err, jc.ErrorIsNil) 302 s.assertStorageCount(c, s.originalStorageCount+1) 303 s.assertVolumeCount(c, s.originalVolumeCount+1) 304 s.assertFileSystemCount(c, s.originalFilesystemCount) 305 assertMachineStorageRefs(c, s.storageBackend, s.machineTag) 306 } 307 308 func (s *storageAddSuite) TestAddStorageLessMinSize(c *gc.C) { 309 u := s.setupMultipleStoragesForAdd(c) 310 s.assignUnit(c, u) 311 312 _, err := s.storageBackend.AddStorageForUnit(s.unitTag, "multi2up", state.StorageConstraints{Size: 2, Count: 1}) 313 c.Assert(err, gc.ErrorMatches, `.*charm "storage-block2" store "multi2up": minimum storage size is 2.0 GB, 2.0 MB specified.*`) 314 s.assertStorageCount(c, s.originalStorageCount) 315 s.assertVolumeCount(c, s.originalVolumeCount) 316 s.assertFileSystemCount(c, s.originalFilesystemCount) 317 assertMachineStorageRefs(c, s.storageBackend, s.machineTag) 318 } 319 320 func (s *storageAddSuite) TestAddStorageWrongName(c *gc.C) { 321 u := s.setupMultipleStoragesForAdd(c) 322 s.assignUnit(c, u) 323 324 _, err := s.storageBackend.AddStorageForUnit(s.unitTag, "furball", state.StorageConstraints{Size: 2}) 325 c.Assert(err, gc.ErrorMatches, `.*charm storage "furball" not found.*`) 326 s.assertStorageCount(c, s.originalStorageCount) 327 s.assertVolumeCount(c, s.originalVolumeCount) 328 s.assertFileSystemCount(c, s.originalFilesystemCount) 329 } 330 331 func (s *storageAddSuite) TestAddStorageConcurrently(c *gc.C) { 332 u := s.setupMultipleStoragesForAdd(c) 333 s.assignUnit(c, u) 334 335 addStorage := func() { 336 _, err := s.storageBackend.AddStorageForUnit(s.unitTag, "multi1to10", state.StorageConstraints{Count: 1}) 337 c.Assert(err, jc.ErrorIsNil) 338 } 339 defer state.SetBeforeHooks(c, s.State, addStorage).Check() 340 addStorage() 341 s.assertStorageCount(c, s.originalStorageCount+2) 342 s.assertVolumeCount(c, s.originalVolumeCount+2) 343 s.assertFileSystemCount(c, s.originalFilesystemCount) 344 assertMachineStorageRefs(c, s.storageBackend, s.machineTag) 345 } 346 347 func (s *storageAddSuite) TestAddStorageConcurrentlyExceedCount(c *gc.C) { 348 u := s.setupMultipleStoragesForAdd(c) 349 s.assignUnit(c, u) 350 351 count := 6 352 addStorage := func() { 353 _, err := s.storageBackend.AddStorageForUnit(s.unitTag, "multi1to10", state.StorageConstraints{Count: uint64(count)}) 354 c.Assert(err, jc.ErrorIsNil) 355 } 356 defer state.SetBeforeHooks(c, s.State, addStorage).Check() 357 _, err := s.storageBackend.AddStorageForUnit(s.unitTag, "multi1to10", state.StorageConstraints{Count: uint64(count)}) 358 c.Assert(err, gc.ErrorMatches, 359 `adding "multi1to10" storage to storage-block2/0: `+ 360 `attaching 6 storage instances brings the total to 15, exceeding the maximum of 10`) 361 362 // Only "count" number of instances should have been added. 363 s.assertStorageCount(c, s.originalStorageCount+count) 364 s.assertVolumeCount(c, s.originalVolumeCount+count) 365 s.assertFileSystemCount(c, s.originalFilesystemCount) 366 assertMachineStorageRefs(c, s.storageBackend, s.machineTag) 367 } 368 369 func (s *storageAddSuite) TestAddStorageFilesystem(c *gc.C) { 370 _, u, _ := s.setupSingleStorage(c, "filesystem", "loop-pool") 371 372 // Assign unit to machine to get volumes and filesystems 373 err := s.State.AssignUnit(u, state.AssignCleanEmpty) 374 c.Assert(err, jc.ErrorIsNil) 375 machineId, err := u.AssignedMachineId() 376 c.Assert(err, jc.ErrorIsNil) 377 s.machineTag = names.NewMachineTag(machineId) 378 s.assertFileSystemCount(c, 1) 379 380 s.assertStorageCount(c, 1) 381 s.assertVolumeCount(c, 1) 382 s.assertFileSystemCount(c, 1) 383 384 _, err = s.storageBackend.AddStorageForUnit(u.UnitTag(), "data", makeStorageCons("loop-pool", 1024, 1)) 385 c.Assert(err, jc.ErrorIsNil) 386 s.assertStorageCount(c, 2) 387 s.assertVolumeCount(c, 2) 388 s.assertFileSystemCount(c, 2) 389 assertMachineStorageRefs(c, s.storageBackend, s.machineTag) 390 } 391 392 func (s *storageAddSuite) TestAddStorageStatic(c *gc.C) { 393 // Create a unit with static storage; ensure that storage-add 394 // fails to add more of this kind of storage. 395 _, u, _ := s.setupSingleStorage(c, "filesystem", "static") 396 s.assertStorageCount(c, 1) 397 398 // Assign unit to machine to get volumes and filesystems 399 err := s.State.AssignUnit(u, state.AssignCleanEmpty) 400 c.Assert(err, jc.ErrorIsNil) 401 machineId, err := u.AssignedMachineId() 402 c.Assert(err, jc.ErrorIsNil) 403 s.machineTag = names.NewMachineTag(machineId) 404 s.assertFileSystemCount(c, 1) 405 406 _, err = s.storageBackend.AddStorageForUnit( 407 u.UnitTag(), "data", 408 makeStorageCons("static", 1024, 1), 409 ) 410 c.Assert(err, gc.ErrorMatches, `adding "data" storage to storage-filesystem/0: `+ 411 "creating machine storage for storage data/1: "+ 412 `"static" storage provider does not support dynamic storage`) 413 s.assertStorageCount(c, 1) // no change 414 s.assertFileSystemCount(c, 1) // no change 415 assertMachineStorageRefs(c, s.storageBackend, s.machineTag) 416 }