github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/filesystem_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/charm/v12" 8 "github.com/juju/errors" 9 "github.com/juju/names/v5" 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 13 "github.com/juju/juju/caas/kubernetes/provider" 14 k8stesting "github.com/juju/juju/caas/kubernetes/provider/testing" 15 "github.com/juju/juju/core/status" 16 "github.com/juju/juju/state" 17 "github.com/juju/juju/state/testing" 18 ) 19 20 type FilesystemStateSuite struct { 21 StorageStateSuiteBase 22 } 23 24 type FilesystemIAASModelSuite struct { 25 FilesystemStateSuite 26 } 27 28 type FilesystemCAASModelSuite struct { 29 FilesystemStateSuite 30 } 31 32 var _ = gc.Suite(&FilesystemIAASModelSuite{}) 33 var _ = gc.Suite(&FilesystemCAASModelSuite{}) 34 35 func (s *FilesystemCAASModelSuite) SetUpTest(c *gc.C) { 36 s.series = "kubernetes" 37 s.FilesystemStateSuite.SetUpTest(c) 38 s.PatchValue(&provider.NewK8sClients, k8stesting.NoopFakeK8sClients) 39 } 40 41 func (s *FilesystemStateSuite) TestAddApplicationInvalidPool(c *gc.C) { 42 ch := s.AddTestingCharm(c, "storage-filesystem") 43 storage := map[string]state.StorageConstraints{ 44 "data": makeStorageCons("invalid-pool", 1024, 1), 45 } 46 _, err := s.st.AddApplication(state.AddApplicationArgs{ 47 Name: "storage-filesystem", Charm: ch, 48 CharmOrigin: &state.CharmOrigin{Platform: &state.Platform{ 49 OS: "ubuntu", 50 Channel: "20.04/stable", 51 }}, 52 Storage: storage, 53 }) 54 c.Assert(err, gc.ErrorMatches, `.* pool "invalid-pool" not found`) 55 } 56 57 func (s *FilesystemStateSuite) TestAddApplicationNoPoolNoDefault(c *gc.C) { 58 // no pool specified, no default configured: use default. 59 expected := "rootfs" 60 if s.series == "kubernetes" { 61 expected = "kubernetes" 62 } 63 s.testAddApplicationDefaultPool(c, expected, 0) 64 } 65 66 func (s *FilesystemStateSuite) TestAddApplicationNoPoolNoDefaultWithUnits(c *gc.C) { 67 // no pool specified, no default configured: use default, add a unit during 68 // app deploy. 69 expected := "rootfs" 70 if s.series == "kubernetes" { 71 expected = "kubernetes" 72 } 73 s.testAddApplicationDefaultPool(c, expected, 1) 74 } 75 76 func (s *FilesystemIAASModelSuite) TestAddApplicationNoPoolDefaultFilesystem(c *gc.C) { 77 // no pool specified, default filesystem configured: use default 78 // filesystem. 79 m, err := s.st.Model() 80 c.Assert(err, jc.ErrorIsNil) 81 err = m.UpdateModelConfig(map[string]interface{}{ 82 "storage-default-filesystem-source": "machinescoped", 83 }, nil) 84 c.Assert(err, jc.ErrorIsNil) 85 s.testAddApplicationDefaultPool(c, "machinescoped", 0) 86 } 87 88 func (s *FilesystemIAASModelSuite) TestAddApplicationNoPoolDefaultBlock(c *gc.C) { 89 // no pool specified, default block configured: use default 90 // block with managed fs on top. 91 m, err := s.st.Model() 92 c.Assert(err, jc.ErrorIsNil) 93 err = m.UpdateModelConfig(map[string]interface{}{ 94 "storage-default-block-source": "modelscoped-block", 95 }, nil) 96 c.Assert(err, jc.ErrorIsNil) 97 s.testAddApplicationDefaultPool(c, "modelscoped-block", 0) 98 } 99 100 func (s *FilesystemStateSuite) testAddApplicationDefaultPool(c *gc.C, expectedPool string, numUnits int) { 101 ch := s.AddTestingCharm(c, "storage-filesystem") 102 storage := map[string]state.StorageConstraints{ 103 "data": makeStorageCons("", 1024, 1), 104 } 105 106 args := state.AddApplicationArgs{ 107 Name: "storage-filesystem", 108 Charm: ch, 109 CharmOrigin: &state.CharmOrigin{Platform: &state.Platform{ 110 OS: "ubuntu", 111 Channel: "20.04/stable", 112 }}, 113 Storage: storage, 114 NumUnits: numUnits, 115 } 116 app, err := s.st.AddApplication(args) 117 c.Assert(err, jc.ErrorIsNil) 118 cons, err := app.StorageConstraints() 119 c.Assert(err, jc.ErrorIsNil) 120 expected := map[string]state.StorageConstraints{ 121 "data": { 122 Pool: expectedPool, 123 Size: 1024, 124 Count: 1, 125 }, 126 } 127 if s.series == "kubernetes" { 128 expected["cache"] = state.StorageConstraints{Count: 0, Size: 1024, Pool: expectedPool} 129 } 130 c.Assert(cons, jc.DeepEquals, expected) 131 132 app, err = s.st.Application(args.Name) 133 c.Assert(err, jc.ErrorIsNil) 134 135 units, err := app.AllUnits() 136 c.Assert(err, jc.ErrorIsNil) 137 c.Assert(units, gc.HasLen, numUnits) 138 139 for _, unit := range units { 140 scons, err := unit.StorageConstraints() 141 c.Assert(err, jc.ErrorIsNil) 142 c.Assert(scons, gc.DeepEquals, expected) 143 144 storageAttachments, err := s.storageBackend.UnitStorageAttachments(unit.UnitTag()) 145 c.Assert(err, jc.ErrorIsNil) 146 c.Assert(storageAttachments, gc.HasLen, 1) 147 storageInstance, err := s.storageBackend.StorageInstance(storageAttachments[0].StorageInstance()) 148 c.Assert(err, jc.ErrorIsNil) 149 c.Assert(storageInstance.Kind(), gc.Equals, state.StorageKindFilesystem) 150 } 151 } 152 153 func (s *FilesystemStateSuite) TestAddFilesystemWithoutBackingVolume(c *gc.C) { 154 s.addUnitWithFilesystem(c, "rootfs", false) 155 } 156 157 func (s *FilesystemIAASModelSuite) TestAddFilesystemWithBackingVolume(c *gc.C) { 158 s.addUnitWithFilesystem(c, "modelscoped-block", true) 159 } 160 161 func (s *FilesystemStateSuite) TestSetFilesystemInfoImmutable(c *gc.C) { 162 _, u, storageTag := s.setupSingleStorage(c, "filesystem", "rootfs") 163 hostTag := s.maybeAssignUnit(c, u) 164 filesystem := s.storageInstanceFilesystem(c, storageTag) 165 filesystemTag := filesystem.FilesystemTag() 166 167 if _, ok := hostTag.(names.MachineTag); ok { 168 machine := unitMachine(c, s.st, u) 169 err := machine.SetProvisioned("inst-id", "", "fake_nonce", nil) 170 c.Assert(err, jc.ErrorIsNil) 171 } 172 173 filesystemInfoSet := state.FilesystemInfo{Size: 123, FilesystemId: "fs-id"} 174 err := s.storageBackend.SetFilesystemInfo(filesystem.FilesystemTag(), filesystemInfoSet) 175 c.Assert(err, jc.ErrorIsNil) 176 177 // The first call to SetFilesystemInfo takes the pool name from 178 // the params; the second does not, but it must not change 179 // either. Callers are expected to get the existing info and 180 // update it, leaving immutable values intact. 181 err = s.storageBackend.SetFilesystemInfo(filesystem.FilesystemTag(), filesystemInfoSet) 182 c.Assert(err, gc.ErrorMatches, `cannot set info for filesystem ".*0/0": cannot change pool from "rootfs" to ""`) 183 184 filesystemInfoSet.Pool = "rootfs" 185 s.assertFilesystemInfo(c, filesystemTag, filesystemInfoSet) 186 } 187 188 func (s *FilesystemStateSuite) maybeAssignUnit(c *gc.C, u *state.Unit) names.Tag { 189 m, err := s.st.Model() 190 c.Assert(err, jc.ErrorIsNil) 191 if m.Type() == state.ModelTypeCAAS { 192 return u.UnitTag() 193 } 194 err = s.st.AssignUnit(u, state.AssignCleanEmpty) 195 c.Assert(err, jc.ErrorIsNil) 196 machineId, err := u.AssignedMachineId() 197 c.Assert(err, jc.ErrorIsNil) 198 return names.NewMachineTag(machineId) 199 } 200 201 func (s *FilesystemStateSuite) TestSetFilesystemInfoNoFilesystemId(c *gc.C) { 202 _, u, storageTag := s.setupSingleStorage(c, "filesystem", "tmpfs-pool") 203 s.maybeAssignUnit(c, u) 204 filesystem := s.storageInstanceFilesystem(c, storageTag) 205 filesystemTag := filesystem.FilesystemTag() 206 s.assertFilesystemUnprovisioned(c, filesystemTag) 207 208 filesystemInfoSet := state.FilesystemInfo{Size: 123} 209 err := s.storageBackend.SetFilesystemInfo(filesystem.FilesystemTag(), filesystemInfoSet) 210 c.Assert(err, gc.ErrorMatches, `cannot set info for filesystem ".*0/0": filesystem ID not set`) 211 } 212 213 func (s *FilesystemIAASModelSuite) TestVolumeFilesystem(c *gc.C) { 214 filesystem, _, _ := s.addUnitWithFilesystem(c, "modelscoped-block", true) 215 volumeTag, err := filesystem.Volume() 216 c.Assert(err, jc.ErrorIsNil) 217 218 volumeFilesystem := s.volumeFilesystem(c, volumeTag) 219 c.Assert(volumeFilesystem.FilesystemTag(), gc.Equals, filesystem.FilesystemTag()) 220 } 221 222 func (s *FilesystemStateSuite) addUnitWithFilesystem(c *gc.C, pool string, withVolume bool) ( 223 state.Filesystem, 224 state.FilesystemAttachment, 225 state.StorageAttachment, 226 ) { 227 filesystem, filesystemAttachment, storageAttachment := s.addUnitWithFilesystemUnprovisioned( 228 c, pool, withVolume, 229 ) 230 231 if machineTag, ok := filesystemAttachment.Host().(names.MachineTag); ok { 232 // Machine must be provisioned before either volume or 233 // filesystem can be attached. 234 machine, err := s.st.Machine(machineTag.Id()) 235 c.Assert(err, jc.ErrorIsNil) 236 err = machine.SetProvisioned("inst-id", "", "fake_nonce", nil) 237 c.Assert(err, jc.ErrorIsNil) 238 } 239 240 if withVolume { 241 // Volume must be provisioned before the filesystem. 242 volume := s.filesystemVolume(c, filesystem.FilesystemTag()) 243 err := s.storageBackend.SetVolumeInfo(volume.VolumeTag(), state.VolumeInfo{VolumeId: "vol-123"}) 244 c.Assert(err, jc.ErrorIsNil) 245 246 // Volume must be attached before the filesystem. 247 err = s.storageBackend.SetVolumeAttachmentInfo( 248 filesystemAttachment.Host(), 249 volume.VolumeTag(), 250 state.VolumeAttachmentInfo{DeviceName: "sdc"}, 251 ) 252 c.Assert(err, jc.ErrorIsNil) 253 } 254 255 // Filesystem must be provisioned before it can be attached. 256 err := s.storageBackend.SetFilesystemInfo( 257 filesystem.FilesystemTag(), 258 state.FilesystemInfo{FilesystemId: "fs-123"}, 259 ) 260 c.Assert(err, jc.ErrorIsNil) 261 262 err = s.storageBackend.SetFilesystemAttachmentInfo( 263 filesystemAttachment.Host(), 264 filesystem.FilesystemTag(), 265 state.FilesystemAttachmentInfo{MountPoint: "/srv"}, 266 ) 267 c.Assert(err, jc.ErrorIsNil) 268 269 return filesystem, filesystemAttachment, storageAttachment 270 } 271 272 func (s *FilesystemStateSuite) addUnitWithFilesystemUnprovisioned(c *gc.C, pool string, withVolume bool) ( 273 state.Filesystem, 274 state.FilesystemAttachment, 275 state.StorageAttachment, 276 ) { 277 ch := s.AddTestingCharm(c, "storage-filesystem") 278 storage := map[string]state.StorageConstraints{ 279 "data": makeStorageCons(pool, 1024, 1), 280 } 281 app := s.AddTestingApplicationWithStorage(c, "storage-filesystem", ch, storage) 282 unit, err := app.AddUnit(state.AddUnitParams{}) 283 c.Assert(err, jc.ErrorIsNil) 284 hostTag := s.maybeAssignUnit(c, unit) 285 286 storageAttachments, err := s.storageBackend.UnitStorageAttachments(unit.UnitTag()) 287 c.Assert(err, jc.ErrorIsNil) 288 c.Assert(storageAttachments, gc.HasLen, 1) 289 storageInstance, err := s.storageBackend.StorageInstance(storageAttachments[0].StorageInstance()) 290 c.Assert(err, jc.ErrorIsNil) 291 c.Assert(storageInstance.Kind(), gc.Equals, state.StorageKindFilesystem) 292 293 filesystem := s.storageInstanceFilesystem(c, storageInstance.StorageTag()) 294 filesystemStorageTag, err := filesystem.Storage() 295 c.Assert(err, jc.ErrorIsNil) 296 c.Assert(filesystemStorageTag, gc.Equals, storageInstance.StorageTag()) 297 _, err = filesystem.Info() 298 c.Assert(err, jc.Satisfies, errors.IsNotProvisioned) 299 _, ok := filesystem.Params() 300 c.Assert(ok, jc.IsTrue) 301 302 volume, err := s.storageBackend.StorageInstanceVolume(storageInstance.StorageTag()) 303 if withVolume { 304 c.Assert(err, jc.ErrorIsNil) 305 c.Assert(volume.VolumeTag(), gc.Equals, names.NewVolumeTag("0")) 306 volumeStorageTag, err := volume.StorageInstance() 307 c.Assert(err, jc.ErrorIsNil) 308 c.Assert(volumeStorageTag, gc.Equals, storageInstance.StorageTag()) 309 filesystemVolume, err := filesystem.Volume() 310 c.Assert(err, jc.ErrorIsNil) 311 c.Assert(filesystemVolume, gc.Equals, volume.VolumeTag()) 312 _, err = s.storageBackend.VolumeAttachment(hostTag, filesystemVolume) 313 c.Assert(err, jc.ErrorIsNil) 314 } else { 315 c.Assert(err, jc.Satisfies, errors.IsNotFound) 316 _, err = filesystem.Volume() 317 c.Assert(errors.Cause(err), gc.Equals, state.ErrNoBackingVolume) 318 } 319 320 if s.series != "kubernetes" { 321 machineTag := hostTag.(names.MachineTag) 322 filesystemAttachments, err := s.storageBackend.MachineFilesystemAttachments(machineTag) 323 c.Assert(err, jc.ErrorIsNil) 324 c.Assert(filesystemAttachments, gc.HasLen, 1) 325 c.Assert(filesystemAttachments[0].Filesystem(), gc.Equals, filesystem.FilesystemTag()) 326 c.Assert(filesystemAttachments[0].Host(), gc.Equals, hostTag) 327 _, err = filesystemAttachments[0].Info() 328 c.Assert(err, jc.Satisfies, errors.IsNotProvisioned) 329 _, ok = filesystemAttachments[0].Params() 330 c.Assert(ok, jc.IsTrue) 331 332 assertMachineStorageRefs(c, s.storageBackend, machineTag) 333 } 334 335 att, err := s.storageBackend.FilesystemAttachment(hostTag, filesystem.FilesystemTag()) 336 c.Assert(err, jc.ErrorIsNil) 337 return filesystem, att, storageAttachments[0] 338 } 339 340 func (s *FilesystemIAASModelSuite) TestWatchFilesystemAttachment(c *gc.C) { 341 _, u, storageTag := s.setupSingleStorage(c, "filesystem", "rootfs") 342 err := s.st.AssignUnit(u, state.AssignCleanEmpty) 343 c.Assert(err, jc.ErrorIsNil) 344 assignedMachineId, err := u.AssignedMachineId() 345 c.Assert(err, jc.ErrorIsNil) 346 machineTag := names.NewMachineTag(assignedMachineId) 347 348 filesystem := s.storageInstanceFilesystem(c, storageTag) 349 filesystemTag := filesystem.FilesystemTag() 350 // Ensure that all the creation events have flowed through the system. 351 s.WaitForModelWatchersIdle(c, s.Model.UUID()) 352 353 w := s.storageBackend.WatchFilesystemAttachment(machineTag, filesystemTag) 354 defer testing.AssertStop(c, w) 355 wc := testing.NewNotifyWatcherC(c, w) 356 wc.AssertOneChange() 357 358 machine, err := s.st.Machine(assignedMachineId) 359 c.Assert(err, jc.ErrorIsNil) 360 err = machine.SetProvisioned("inst-id", "", "fake_nonce", nil) 361 c.Assert(err, jc.ErrorIsNil) 362 363 // filesystem attachment will NOT react to filesystem changes 364 err = s.storageBackend.SetFilesystemInfo(filesystemTag, state.FilesystemInfo{ 365 FilesystemId: "fs-123", 366 }) 367 c.Assert(err, jc.ErrorIsNil) 368 wc.AssertNoChange() 369 370 err = s.storageBackend.SetFilesystemAttachmentInfo( 371 machineTag, filesystemTag, state.FilesystemAttachmentInfo{ 372 MountPoint: "/srv", 373 }, 374 ) 375 c.Assert(err, jc.ErrorIsNil) 376 wc.AssertOneChange() 377 } 378 379 func (s *FilesystemStateSuite) TestFilesystemInfo(c *gc.C) { 380 _, u, storageTag := s.setupSingleStorage(c, "filesystem", "rootfs") 381 hostTag := s.maybeAssignUnit(c, u) 382 383 filesystem := s.storageInstanceFilesystem(c, storageTag) 384 filesystemTag := filesystem.FilesystemTag() 385 386 s.assertFilesystemUnprovisioned(c, filesystemTag) 387 s.assertFilesystemAttachmentUnprovisioned(c, hostTag, filesystemTag) 388 389 if _, ok := hostTag.(names.MachineTag); ok { 390 machine, err := s.st.Machine(hostTag.Id()) 391 c.Assert(err, jc.ErrorIsNil) 392 err = machine.SetProvisioned("inst-id", "", "fake_nonce", nil) 393 c.Assert(err, jc.ErrorIsNil) 394 } 395 396 filesystemInfo := state.FilesystemInfo{FilesystemId: "fs-123", Size: 456} 397 err := s.storageBackend.SetFilesystemInfo(filesystemTag, filesystemInfo) 398 c.Assert(err, jc.ErrorIsNil) 399 filesystemInfo.Pool = "rootfs" // taken from params 400 s.assertFilesystemInfo(c, filesystemTag, filesystemInfo) 401 s.assertFilesystemAttachmentUnprovisioned(c, hostTag, filesystemTag) 402 403 filesystemAttachmentInfo := state.FilesystemAttachmentInfo{MountPoint: "/srv"} 404 err = s.storageBackend.SetFilesystemAttachmentInfo(hostTag, filesystemTag, filesystemAttachmentInfo) 405 c.Assert(err, jc.ErrorIsNil) 406 s.assertFilesystemAttachmentInfo(c, hostTag, filesystemTag, filesystemAttachmentInfo) 407 } 408 409 func (s *FilesystemIAASModelSuite) TestVolumeBackedFilesystemScope(c *gc.C) { 410 _, unit, storageTag := s.setupSingleStorage(c, "filesystem", "modelscoped-block") 411 err := s.st.AssignUnit(unit, state.AssignCleanEmpty) 412 c.Assert(err, jc.ErrorIsNil) 413 414 filesystem := s.storageInstanceFilesystem(c, storageTag) 415 c.Assert(filesystem.Tag(), gc.Equals, names.NewFilesystemTag("0")) 416 volumeTag, err := filesystem.Volume() 417 c.Assert(err, jc.ErrorIsNil) 418 c.Assert(volumeTag, gc.Equals, names.NewVolumeTag("0")) 419 } 420 421 func (s *FilesystemIAASModelSuite) TestWatchModelFilesystems(c *gc.C) { 422 app := s.setupMixedScopeStorageApplication(c, "filesystem") 423 addUnit := func() *state.Unit { 424 u, err := app.AddUnit(state.AddUnitParams{}) 425 c.Assert(err, jc.ErrorIsNil) 426 err = s.st.AssignUnit(u, state.AssignCleanEmpty) 427 c.Assert(err, jc.ErrorIsNil) 428 return u 429 } 430 u := addUnit() 431 // Ensure that all the creation events have flowed through the system. 432 s.WaitForModelWatchersIdle(c, s.Model.UUID()) 433 434 w := s.storageBackend.WatchModelFilesystems() 435 defer testing.AssertStop(c, w) 436 wc := testing.NewStringsWatcherC(c, w) 437 wc.AssertChange("0", "1") // initial 438 wc.AssertNoChange() 439 440 addUnit() 441 wc.AssertChange("4", "5") 442 wc.AssertNoChange() 443 444 err := u.Destroy() 445 c.Assert(err, jc.ErrorIsNil) 446 filesystemTag := names.NewFilesystemTag("0") 447 removeFilesystemStorageInstance(c, s.storageBackend, filesystemTag) 448 449 err = s.storageBackend.DestroyFilesystem(filesystemTag, false) 450 c.Assert(err, jc.ErrorIsNil) 451 wc.AssertChange("0") 452 wc.AssertNoChange() 453 454 machineTag := names.NewMachineTag("0") 455 err = s.storageBackend.DetachFilesystem(machineTag, filesystemTag) 456 c.Assert(err, jc.ErrorIsNil) 457 wc.AssertNoChange() 458 459 err = s.storageBackend.RemoveFilesystemAttachment(machineTag, filesystemTag, false) 460 c.Assert(err, jc.ErrorIsNil) 461 wc.AssertChange("0") // last attachment removed 462 wc.AssertNoChange() 463 } 464 465 func (s *FilesystemIAASModelSuite) TestWatchModelFilesystemAttachments(c *gc.C) { 466 app := s.setupMixedScopeStorageApplication(c, "filesystem") 467 addUnit := func() *state.Unit { 468 u, err := app.AddUnit(state.AddUnitParams{}) 469 c.Assert(err, jc.ErrorIsNil) 470 err = s.st.AssignUnit(u, state.AssignCleanEmpty) 471 c.Assert(err, jc.ErrorIsNil) 472 return u 473 } 474 u := addUnit() 475 // Ensure that all the creation events have flowed through the system. 476 s.WaitForModelWatchersIdle(c, s.Model.UUID()) 477 478 w := s.storageBackend.WatchModelFilesystemAttachments() 479 defer testing.AssertStop(c, w) 480 wc := testing.NewStringsWatcherC(c, w) 481 wc.AssertChange("0:0", "0:1") // initial 482 wc.AssertNoChange() 483 484 addUnit() 485 wc.AssertChange("1:4", "1:5") 486 wc.AssertNoChange() 487 488 err := u.Destroy() 489 c.Assert(err, jc.ErrorIsNil) 490 filesystemTag := names.NewFilesystemTag("0") 491 removeFilesystemStorageInstance(c, s.storageBackend, filesystemTag) 492 493 err = s.storageBackend.DestroyFilesystem(filesystemTag, false) 494 c.Assert(err, jc.ErrorIsNil) 495 wc.AssertNoChange() 496 497 machineTag := names.NewMachineTag("0") 498 err = s.storageBackend.DetachFilesystem(machineTag, filesystemTag) 499 c.Assert(err, jc.ErrorIsNil) 500 wc.AssertChange("0:0") 501 wc.AssertNoChange() 502 503 err = s.storageBackend.RemoveFilesystemAttachment(machineTag, filesystemTag, false) 504 c.Assert(err, jc.ErrorIsNil) 505 wc.AssertChange("0:0") 506 wc.AssertNoChange() 507 } 508 509 func (s *FilesystemIAASModelSuite) TestWatchMachineFilesystems(c *gc.C) { 510 app := s.setupMixedScopeStorageApplication(c, "filesystem") 511 addUnit := func() *state.Unit { 512 u, err := app.AddUnit(state.AddUnitParams{}) 513 c.Assert(err, jc.ErrorIsNil) 514 err = s.st.AssignUnit(u, state.AssignCleanEmpty) 515 c.Assert(err, jc.ErrorIsNil) 516 return u 517 } 518 u := addUnit() 519 // Ensure that all the creation events have flowed through the system. 520 s.WaitForModelWatchersIdle(c, s.Model.UUID()) 521 522 w := s.storageBackend.WatchMachineFilesystems(names.NewMachineTag("0")) 523 defer testing.AssertStop(c, w) 524 wc := testing.NewStringsWatcherC(c, w) 525 wc.AssertChange("0/2", "0/3") // initial 526 wc.AssertNoChange() 527 528 addUnit() 529 // no change, since we're only interested in the one machine. 530 wc.AssertNoChange() 531 532 err := u.Destroy() 533 c.Assert(err, jc.ErrorIsNil) 534 filesystemTag := names.NewFilesystemTag("0/2") 535 removeFilesystemStorageInstance(c, s.storageBackend, filesystemTag) 536 537 err = s.storageBackend.DestroyFilesystem(filesystemTag, false) 538 c.Assert(err, jc.ErrorIsNil) 539 wc.AssertChange("0/2") 540 wc.AssertNoChange() 541 542 attachments, err := s.storageBackend.FilesystemAttachments(filesystemTag) 543 c.Assert(err, jc.ErrorIsNil) 544 for _, a := range attachments { 545 err := s.storageBackend.DetachFilesystem(a.Host(), filesystemTag) 546 c.Assert(err, jc.ErrorIsNil) 547 err = s.storageBackend.RemoveFilesystemAttachment(a.Host(), filesystemTag, false) 548 c.Assert(err, jc.ErrorIsNil) 549 } 550 wc.AssertChange("0/2") // Dying -> Dead 551 wc.AssertNoChange() 552 553 err = s.storageBackend.RemoveFilesystem(filesystemTag) 554 c.Assert(err, jc.ErrorIsNil) 555 // no more changes after seeing Dead 556 wc.AssertNoChange() 557 } 558 559 func (s *FilesystemIAASModelSuite) TestWatchMachineFilesystemAttachments(c *gc.C) { 560 app := s.setupMixedScopeStorageApplication(c, "filesystem", "machinescoped", "modelscoped") 561 addUnit := func(to *state.Machine) (u *state.Unit, m *state.Machine) { 562 var err error 563 u, err = app.AddUnit(state.AddUnitParams{}) 564 c.Assert(err, jc.ErrorIsNil) 565 if to != nil { 566 err = u.AssignToMachine(to) 567 c.Assert(err, jc.ErrorIsNil) 568 return u, to 569 } 570 err = s.st.AssignUnit(u, state.AssignCleanEmpty) 571 c.Assert(err, jc.ErrorIsNil) 572 m = unitMachine(c, s.st, u) 573 return u, m 574 } 575 _, m0 := addUnit(nil) 576 // Ensure that all the creation events have flowed through the system. 577 s.WaitForModelWatchersIdle(c, s.Model.UUID()) 578 579 w := s.storageBackend.WatchMachineFilesystemAttachments(names.NewMachineTag("0")) 580 defer testing.AssertStop(c, w) 581 wc := testing.NewStringsWatcherC(c, w) 582 wc.AssertChange("0:0/0", "0:0/1") // initial 583 wc.AssertNoChange() 584 585 addUnit(nil) 586 // no change, since we're only interested in the one machine. 587 wc.AssertNoChange() 588 589 err := s.storageBackend.DetachFilesystem(names.NewMachineTag("0"), names.NewFilesystemTag("2")) 590 c.Assert(err, jc.ErrorIsNil) 591 // no change, since we're only interested in attachments of 592 // machine-scoped volumes. 593 wc.AssertNoChange() 594 595 removeFilesystemStorageInstance(c, s.storageBackend, names.NewFilesystemTag("0/0")) 596 err = s.storageBackend.DestroyFilesystem(names.NewFilesystemTag("0/0"), false) 597 c.Assert(err, jc.ErrorIsNil) 598 wc.AssertChange("0:0/0") // dying 599 wc.AssertNoChange() 600 601 err = s.storageBackend.RemoveFilesystemAttachment(names.NewMachineTag("0"), names.NewFilesystemTag("0/0"), false) 602 c.Assert(err, jc.ErrorIsNil) 603 wc.AssertChange("0:0/0") // removed 604 wc.AssertNoChange() 605 606 addUnit(m0) 607 wc.AssertChange("0:0/8", "0:0/9") 608 wc.AssertNoChange() 609 } 610 611 func (s *FilesystemCAASModelSuite) TestWatchUnitFilesystems(c *gc.C) { 612 ch := s.AddTestingCharm(c, "storage-filesystem") 613 storage := map[string]state.StorageConstraints{ 614 "data": {Count: 1, Size: 1024, Pool: "kubernetes"}, 615 "cache": {Count: 1, Size: 1024, Pool: "rootfs"}, 616 } 617 app, err := s.st.AddApplication(state.AddApplicationArgs{ 618 Name: "mariadb", Charm: ch, 619 CharmOrigin: &state.CharmOrigin{Platform: &state.Platform{ 620 OS: "ubuntu", 621 Channel: "20.04/stable", 622 }}, 623 Storage: storage, 624 }) 625 c.Assert(err, jc.ErrorIsNil) 626 627 addUnit := func(app *state.Application) *state.Unit { 628 var err error 629 u, err := app.AddUnit(state.AddUnitParams{}) 630 c.Assert(err, jc.ErrorIsNil) 631 return u 632 } 633 u := addUnit(app) 634 // Ensure that all the creation events have flowed through the system. 635 s.WaitForModelWatchersIdle(c, s.Model.UUID()) 636 637 w := s.storageBackend.WatchUnitFilesystems(app.ApplicationTag()) 638 defer testing.AssertStop(c, w) 639 wc := testing.NewStringsWatcherC(c, w) 640 wc.AssertChange("mariadb/0/0") // initial 641 wc.AssertNoChange() 642 643 app2, err := s.st.AddApplication(state.AddApplicationArgs{ 644 Name: "another", Charm: ch, 645 CharmOrigin: &state.CharmOrigin{Platform: &state.Platform{ 646 OS: "ubuntu", 647 Channel: "20.04/stable", 648 }}, 649 Storage: storage, 650 }) 651 c.Assert(err, jc.ErrorIsNil) 652 addUnit(app2) 653 // no change, since we're only interested in the one application. 654 wc.AssertNoChange() 655 656 err = u.Destroy() 657 c.Assert(err, jc.ErrorIsNil) 658 filesystemTag := names.NewFilesystemTag("mariadb/0/0") 659 removeFilesystemStorageInstance(c, s.storageBackend, filesystemTag) 660 661 err = s.storageBackend.DestroyFilesystem(filesystemTag, false) 662 c.Assert(err, jc.ErrorIsNil) 663 wc.AssertChange("mariadb/0/0") 664 wc.AssertNoChange() 665 666 attachments, err := s.storageBackend.FilesystemAttachments(filesystemTag) 667 c.Assert(err, jc.ErrorIsNil) 668 for _, a := range attachments { 669 err := s.storageBackend.DetachFilesystem(a.Host(), filesystemTag) 670 c.Assert(err, jc.ErrorIsNil) 671 err = s.storageBackend.RemoveFilesystemAttachment(a.Host(), filesystemTag, false) 672 c.Assert(err, jc.ErrorIsNil) 673 } 674 wc.AssertChange("mariadb/0/0") // Dying -> Dead 675 wc.AssertNoChange() 676 677 err = s.storageBackend.RemoveFilesystem(filesystemTag) 678 c.Assert(err, jc.ErrorIsNil) 679 // no more changes after seeing Dead 680 wc.AssertNoChange() 681 } 682 683 func (s *FilesystemCAASModelSuite) TestWatchUnitFilesystemAttachments(c *gc.C) { 684 ch := s.AddTestingCharm(c, "storage-filesystem") 685 storage := map[string]state.StorageConstraints{ 686 "data": {Count: 1, Size: 1024, Pool: "kubernetes"}, 687 "cache": {Count: 1, Size: 1024, Pool: "rootfs"}, 688 } 689 app, err := s.st.AddApplication(state.AddApplicationArgs{ 690 Name: "mariadb", Charm: ch, 691 CharmOrigin: &state.CharmOrigin{Platform: &state.Platform{ 692 OS: "ubuntu", 693 Channel: "20.04/stable", 694 }}, 695 Storage: storage, 696 }) 697 c.Assert(err, jc.ErrorIsNil) 698 699 addUnit := func(app *state.Application) *state.Unit { 700 var err error 701 u, err := app.AddUnit(state.AddUnitParams{}) 702 c.Assert(err, jc.ErrorIsNil) 703 return u 704 } 705 addUnit(app) 706 // Ensure that all the creation events have flowed through the system. 707 s.WaitForModelWatchersIdle(c, s.Model.UUID()) 708 709 w := s.storageBackend.WatchUnitFilesystemAttachments(app.ApplicationTag()) 710 defer testing.AssertStop(c, w) 711 wc := testing.NewStringsWatcherC(c, w) 712 713 wc.AssertChange("mariadb/0:mariadb/0/0") // initial 714 wc.AssertNoChange() 715 716 app2, err := s.st.AddApplication(state.AddApplicationArgs{ 717 Name: "another", Charm: ch, 718 CharmOrigin: &state.CharmOrigin{Platform: &state.Platform{ 719 OS: "ubuntu", 720 Channel: "20.04/stable", 721 }}, 722 Storage: storage, 723 }) 724 c.Assert(err, jc.ErrorIsNil) 725 addUnit(app2) 726 // no change, since we're only interested in the one application. 727 wc.AssertNoChange() 728 729 err = s.storageBackend.DetachFilesystem(names.NewUnitTag("mariadb/0"), names.NewFilesystemTag("1")) 730 c.Assert(err, jc.ErrorIsNil) 731 // no change, since we're only interested in attachments of 732 // unit-scoped volumes. 733 wc.AssertNoChange() 734 735 removeFilesystemStorageInstance(c, s.storageBackend, names.NewFilesystemTag("mariadb/0/0")) 736 err = s.storageBackend.DestroyFilesystem(names.NewFilesystemTag("mariadb/0/0"), false) 737 c.Assert(err, jc.ErrorIsNil) 738 wc.AssertChange("mariadb/0:mariadb/0/0") // dying 739 wc.AssertNoChange() 740 741 err = s.storageBackend.RemoveFilesystemAttachment(names.NewUnitTag("mariadb/0"), names.NewFilesystemTag("mariadb/0/0"), false) 742 c.Assert(err, jc.ErrorIsNil) 743 wc.AssertChange("mariadb/0:mariadb/0/0") // removed 744 wc.AssertNoChange() 745 } 746 747 func (s *FilesystemStateSuite) TestParseFilesystemAttachmentId(c *gc.C) { 748 assertValid := func(id string, m names.Tag, v names.FilesystemTag) { 749 machineTag, filesystemTag, err := state.ParseFilesystemAttachmentId(id) 750 c.Assert(err, jc.ErrorIsNil) 751 c.Assert(machineTag, gc.Equals, m) 752 c.Assert(filesystemTag, gc.Equals, v) 753 } 754 assertValid("0:0", names.NewMachineTag("0"), names.NewFilesystemTag("0")) 755 assertValid("0:0/1", names.NewMachineTag("0"), names.NewFilesystemTag("0/1")) 756 assertValid("0/lxd/0:1", names.NewMachineTag("0/lxd/0"), names.NewFilesystemTag("1")) 757 assertValid("some-unit/0:1", names.NewUnitTag("some-unit/0"), names.NewFilesystemTag("1")) 758 } 759 760 func (s *FilesystemStateSuite) TestParseFilesystemAttachmentIdError(c *gc.C) { 761 assertError := func(id, expect string) { 762 _, _, err := state.ParseFilesystemAttachmentId(id) 763 c.Assert(err, gc.ErrorMatches, expect) 764 } 765 assertError("", `invalid filesystem attachment ID ""`) 766 assertError("0", `invalid filesystem attachment ID "0"`) 767 assertError("0:foo", `invalid filesystem attachment ID "0:foo"`) 768 assertError("bar:0", `invalid filesystem attachment ID "bar:0"`) 769 } 770 771 func (s *FilesystemIAASModelSuite) TestRemoveStorageInstanceDestroysAndUnassignsFilesystem(c *gc.C) { 772 filesystem, filesystemAttachment, storageAttachment := s.addUnitWithFilesystem(c, "modelscoped-block", true) 773 volume := s.filesystemVolume(c, filesystemAttachment.Filesystem()) 774 storageTag := storageAttachment.StorageInstance() 775 unitTag := storageAttachment.Unit() 776 777 err := s.storageBackend.SetFilesystemAttachmentInfo( 778 filesystemAttachment.Host().(names.MachineTag), 779 filesystem.FilesystemTag(), 780 state.FilesystemAttachmentInfo{}, 781 ) 782 c.Assert(err, jc.ErrorIsNil) 783 784 u, err := s.st.Unit(unitTag.Id()) 785 c.Assert(err, jc.ErrorIsNil) 786 err = u.Destroy() 787 c.Assert(err, jc.ErrorIsNil) 788 err = s.storageBackend.DestroyStorageInstance(storageTag, true, false, dontWait) 789 c.Assert(err, jc.ErrorIsNil) 790 err = s.storageBackend.DetachStorage(storageTag, unitTag, false, dontWait) 791 c.Assert(err, jc.ErrorIsNil) 792 793 // The storage instance and attachment are dying, but not yet 794 // removed from state. The filesystem should still be assigned. 795 s.storageInstanceFilesystem(c, storageTag) 796 s.storageInstanceVolume(c, storageTag) 797 798 err = s.storageBackend.RemoveStorageAttachment(storageTag, unitTag, false) 799 c.Assert(err, jc.ErrorIsNil) 800 801 // The storage instance is now gone; the filesystem should no longer 802 // be assigned to the storage. 803 _, err = s.storageBackend.StorageInstanceFilesystem(storageTag) 804 c.Assert(err, gc.ErrorMatches, `filesystem for storage instance "data/0" not found`) 805 _, err = s.storageBackend.StorageInstanceVolume(storageTag) 806 c.Assert(err, gc.ErrorMatches, `volume for storage instance "data/0" not found`) 807 808 // The filesystem and volume should still exist. The filesystem 809 // should be dying; the volume will be destroyed only once the 810 // filesystem is removed. 811 f := s.filesystem(c, filesystem.FilesystemTag()) 812 c.Assert(f.Life(), gc.Equals, state.Dying) 813 v := s.volume(c, volume.VolumeTag()) 814 c.Assert(v.Life(), gc.Equals, state.Alive) 815 } 816 817 func (s *FilesystemIAASModelSuite) TestReleaseStorageInstanceFilesystemReleasing(c *gc.C) { 818 _, u, storageTag := s.setupSingleStorage(c, "filesystem", "modelscoped") 819 s.maybeAssignUnit(c, u) 820 filesystem := s.storageInstanceFilesystem(c, storageTag) 821 c.Assert(filesystem.Releasing(), jc.IsFalse) 822 err := s.storageBackend.SetFilesystemInfo(filesystem.FilesystemTag(), state.FilesystemInfo{FilesystemId: "vol-123"}) 823 c.Assert(err, jc.ErrorIsNil) 824 825 err = u.Destroy() 826 c.Assert(err, jc.ErrorIsNil) 827 err = s.storageBackend.ReleaseStorageInstance(storageTag, true, false, dontWait) 828 c.Assert(err, jc.ErrorIsNil) 829 err = s.storageBackend.DetachStorage(storageTag, u.UnitTag(), false, dontWait) 830 c.Assert(err, jc.ErrorIsNil) 831 832 // The filesystem should should be dying, and releasing. 833 filesystem = s.filesystem(c, filesystem.FilesystemTag()) 834 c.Assert(filesystem.Life(), gc.Equals, state.Dying) 835 c.Assert(filesystem.Releasing(), jc.IsTrue) 836 } 837 838 func (s *FilesystemIAASModelSuite) TestReleaseStorageInstanceFilesystemUnreleasable(c *gc.C) { 839 _, u, storageTag := s.setupSingleStorage(c, "filesystem", "modelscoped-unreleasable") 840 s.maybeAssignUnit(c, u) 841 filesystem := s.storageInstanceFilesystem(c, storageTag) 842 c.Assert(filesystem.Releasing(), jc.IsFalse) 843 err := s.storageBackend.SetFilesystemInfo(filesystem.FilesystemTag(), state.FilesystemInfo{FilesystemId: "vol-123"}) 844 c.Assert(err, jc.ErrorIsNil) 845 846 err = u.Destroy() 847 c.Assert(err, jc.ErrorIsNil) 848 err = s.storageBackend.ReleaseStorageInstance(storageTag, true, false, dontWait) 849 c.Assert(err, gc.ErrorMatches, 850 `cannot release storage "data/0": storage provider "modelscoped-unreleasable" does not support releasing storage`) 851 err = s.storageBackend.DetachStorage(storageTag, u.UnitTag(), false, dontWait) 852 c.Assert(err, jc.ErrorIsNil) 853 854 // The filesystem should should be dying, and releasing. 855 filesystem = s.filesystem(c, filesystem.FilesystemTag()) 856 c.Assert(filesystem.Life(), gc.Equals, state.Alive) 857 c.Assert(filesystem.Releasing(), jc.IsFalse) 858 } 859 860 func (s *FilesystemIAASModelSuite) TestSetFilesystemAttachmentInfoFilesystemNotProvisioned(c *gc.C) { 861 _, filesystemAttachment, _ := s.addUnitWithFilesystemUnprovisioned(c, "rootfs", false) 862 err := s.storageBackend.SetFilesystemAttachmentInfo( 863 filesystemAttachment.Host().(names.MachineTag), 864 filesystemAttachment.Filesystem(), 865 state.FilesystemAttachmentInfo{}, 866 ) 867 c.Assert(err, gc.ErrorMatches, `cannot set info for filesystem attachment 0/0:0: filesystem "0/0" not provisioned`) 868 } 869 870 func (s *FilesystemIAASModelSuite) TestSetFilesystemAttachmentInfoMachineNotProvisioned(c *gc.C) { 871 _, filesystemAttachment, _ := s.addUnitWithFilesystemUnprovisioned(c, "rootfs", false) 872 err := s.storageBackend.SetFilesystemInfo( 873 filesystemAttachment.Filesystem(), 874 state.FilesystemInfo{Size: 123, FilesystemId: "fs-id"}, 875 ) 876 c.Assert(err, jc.ErrorIsNil) 877 err = s.storageBackend.SetFilesystemAttachmentInfo( 878 filesystemAttachment.Host(), 879 filesystemAttachment.Filesystem(), 880 state.FilesystemAttachmentInfo{}, 881 ) 882 c.Assert(err, gc.ErrorMatches, `cannot set info for filesystem attachment 0/0:0: machine 0 not provisioned`) 883 } 884 885 func (s *FilesystemIAASModelSuite) TestSetFilesystemInfoVolumeAttachmentNotProvisioned(c *gc.C) { 886 filesystem, _, _ := s.addUnitWithFilesystemUnprovisioned(c, "modelscoped-block", true) 887 err := s.storageBackend.SetFilesystemInfo( 888 filesystem.FilesystemTag(), 889 state.FilesystemInfo{Size: 123, FilesystemId: "fs-id"}, 890 ) 891 c.Assert(err, gc.ErrorMatches, `cannot set info for filesystem "0": backing volume "0" is not attached`) 892 } 893 894 func (s *FilesystemIAASModelSuite) TestDestroyFilesystem(c *gc.C) { 895 filesystem, _ := s.setupFilesystemAttachment(c, "rootfs") 896 assertDestroy := func() { 897 s.assertDestroyFilesystem(c, filesystem.FilesystemTag(), state.Dying) 898 } 899 defer state.SetBeforeHooks(c, s.st, assertDestroy).Check() 900 assertDestroy() 901 } 902 903 func (s *FilesystemStateSuite) TestDestroyFilesystemNotFound(c *gc.C) { 904 err := s.storageBackend.DestroyFilesystem(names.NewFilesystemTag("0"), false) 905 c.Assert(err, gc.ErrorMatches, `destroying filesystem 0: filesystem "0" not found`) 906 c.Assert(err, jc.Satisfies, errors.IsNotFound) 907 } 908 909 func (s *FilesystemStateSuite) TestDestroyFilesystemStorageAssignedNoForce(c *gc.C) { 910 // Create a filesystem-type storage instance, and show that we 911 // cannot destroy the filesystem while there is storage assigned. 912 _, u, storageTag := s.setupSingleStorage(c, "filesystem", "rootfs") 913 s.maybeAssignUnit(c, u) 914 filesystem := s.storageInstanceFilesystem(c, storageTag) 915 916 err := s.storageBackend.DestroyFilesystem(filesystem.FilesystemTag(), false) 917 c.Assert(err, gc.ErrorMatches, "destroying filesystem .*0/0: filesystem is assigned to storage data/0") 918 919 // We must destroy the unit before we can remove the storage. 920 err = u.Destroy() 921 c.Assert(err, jc.ErrorIsNil) 922 removeStorageInstance(c, s.storageBackend, storageTag) 923 s.assertDestroyFilesystem(c, filesystem.FilesystemTag(), state.Dying) 924 } 925 926 func (s *FilesystemStateSuite) TestDestroyFilesystemStorageAssignedWithForce(c *gc.C) { 927 _, u, storageTag := s.setupSingleStorage(c, "filesystem", "rootfs") 928 s.maybeAssignUnit(c, u) 929 filesystem := s.storageInstanceFilesystem(c, storageTag) 930 931 err := s.storageBackend.DestroyFilesystem(filesystem.FilesystemTag(), true) 932 c.Assert(err, jc.ErrorIsNil) 933 filesystem = s.filesystem(c, filesystem.FilesystemTag()) 934 c.Assert(filesystem.Life(), gc.Equals, state.Dying) 935 } 936 937 func (s *FilesystemIAASModelSuite) TestDestroyFilesystemNoAttachments(c *gc.C) { 938 filesystem, machine := s.setupFilesystemAttachment(c, "modelscoped") 939 940 err := s.storageBackend.DetachFilesystem(machine.MachineTag(), filesystem.FilesystemTag()) 941 c.Assert(err, jc.ErrorIsNil) 942 943 defer state.SetBeforeHooks(c, s.st, func() { 944 err := s.storageBackend.RemoveFilesystemAttachment(machine.MachineTag(), filesystem.FilesystemTag(), false) 945 c.Assert(err, jc.ErrorIsNil) 946 assertMachineStorageRefs(c, s.storageBackend, machine.MachineTag()) 947 }).Check() 948 949 // There are no more attachments, so the filesystem should 950 // be progressed directly to Dead. 951 s.assertDestroyFilesystem(c, filesystem.FilesystemTag(), state.Dead) 952 } 953 954 func (s *FilesystemIAASModelSuite) TestRemoveFilesystem(c *gc.C) { 955 filesystem, machine := s.setupFilesystemAttachment(c, "rootfs") 956 s.assertDestroyFilesystem(c, filesystem.FilesystemTag(), state.Dying) 957 err := s.storageBackend.DetachFilesystem(machine.MachineTag(), filesystem.FilesystemTag()) 958 c.Assert(err, jc.ErrorIsNil) 959 err = s.storageBackend.RemoveFilesystemAttachment(machine.MachineTag(), filesystem.FilesystemTag(), false) 960 c.Assert(err, jc.ErrorIsNil) 961 assertRemove := func() { 962 err = s.storageBackend.RemoveFilesystem(filesystem.FilesystemTag()) 963 c.Assert(err, jc.ErrorIsNil) 964 _, err = s.storageBackend.Filesystem(filesystem.FilesystemTag()) 965 c.Assert(err, jc.Satisfies, errors.IsNotFound) 966 } 967 defer state.SetBeforeHooks(c, s.st, assertRemove).Check() 968 assertRemove() 969 } 970 971 func (s *FilesystemIAASModelSuite) TestRemoveFilesystemVolumeBacked(c *gc.C) { 972 filesystem, machine := s.setupFilesystemAttachment(c, "modelscoped-block") 973 volume := s.filesystemVolume(c, filesystem.FilesystemTag()) 974 assertVolumeLife := func(life state.Life) { 975 volume := s.volume(c, volume.VolumeTag()) 976 c.Assert(volume.Life(), gc.Equals, life) 977 } 978 assertVolumeAttachmentLife := func(life state.Life) { 979 attachment := s.volumeAttachment(c, machine.MachineTag(), volume.VolumeTag()) 980 c.Assert(attachment.Life(), gc.Equals, life) 981 } 982 983 s.assertDestroyFilesystem(c, filesystem.FilesystemTag(), state.Dying) 984 // Destroying the filesystem does not trigger destruction 985 // of the volume. It cannot be destroyed until all remnants 986 // of the filesystem are gone. 987 assertVolumeLife(state.Alive) 988 989 err := s.storageBackend.DetachFilesystem(machine.MachineTag(), filesystem.FilesystemTag()) 990 c.Assert(err, jc.ErrorIsNil) 991 // Likewise for the volume attachment. 992 assertVolumeAttachmentLife(state.Alive) 993 994 err = s.storageBackend.RemoveFilesystemAttachment(machine.MachineTag(), filesystem.FilesystemTag(), false) 995 c.Assert(err, jc.ErrorIsNil) 996 // Removing the filesystem attachment causes the backing-volume 997 // to be detached. 998 assertVolumeAttachmentLife(state.Dying) 999 1000 // Removing the last attachment should cause the filesystem 1001 // to be removed, since it is volume-backed and dying. 1002 _, err = s.storageBackend.Filesystem(filesystem.FilesystemTag()) 1003 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1004 // Removing the filesystem causes the backing-volume to be 1005 // destroyed. 1006 assertVolumeLife(state.Dying) 1007 1008 assertMachineStorageRefs(c, s.storageBackend, machine.MachineTag()) 1009 } 1010 1011 func (s *FilesystemIAASModelSuite) TestFilesystemVolumeBackedDestroyDetachVolumeFail(c *gc.C) { 1012 filesystem, machine := s.setupFilesystemAttachment(c, "modelscoped-block") 1013 volume := s.filesystemVolume(c, filesystem.FilesystemTag()) 1014 1015 s.assertDestroyFilesystem(c, filesystem.FilesystemTag(), state.Dying) 1016 err := s.storageBackend.DetachFilesystem(machine.MachineTag(), filesystem.FilesystemTag()) 1017 c.Assert(err, jc.ErrorIsNil) 1018 1019 // Can't destroy (detach) volume until the filesystem (attachment) is removed. 1020 err = s.storageBackend.DetachVolume(machine.MachineTag(), volume.VolumeTag(), false) 1021 c.Assert(err, gc.ErrorMatches, "detaching volume 0 from machine 0: volume contains attached filesystem") 1022 c.Assert(err, jc.Satisfies, state.IsContainsFilesystem) 1023 err = s.storageBackend.DestroyVolume(volume.VolumeTag(), false) 1024 c.Assert(err, gc.ErrorMatches, "destroying volume 0: volume contains filesystem") 1025 c.Assert(err, jc.Satisfies, state.IsContainsFilesystem) 1026 assertMachineStorageRefs(c, s.storageBackend, machine.MachineTag()) 1027 1028 err = s.storageBackend.RemoveFilesystemAttachment(machine.MachineTag(), filesystem.FilesystemTag(), false) 1029 c.Assert(err, jc.ErrorIsNil) 1030 err = s.storageBackend.RemoveFilesystem(filesystem.FilesystemTag()) 1031 c.Assert(err, jc.ErrorIsNil) 1032 1033 err = s.storageBackend.DetachVolume(machine.MachineTag(), volume.VolumeTag(), false) 1034 c.Assert(err, jc.ErrorIsNil) 1035 err = s.storageBackend.DestroyVolume(volume.VolumeTag(), false) 1036 c.Assert(err, jc.ErrorIsNil) 1037 } 1038 1039 func (s *FilesystemStateSuite) TestRemoveFilesystemNotFound(c *gc.C) { 1040 err := s.storageBackend.RemoveFilesystem(names.NewFilesystemTag("42")) 1041 c.Assert(err, jc.ErrorIsNil) 1042 } 1043 1044 func (s *FilesystemIAASModelSuite) TestRemoveFilesystemNotDead(c *gc.C) { 1045 filesystem, _ := s.setupFilesystemAttachment(c, "rootfs") 1046 err := s.storageBackend.RemoveFilesystem(filesystem.FilesystemTag()) 1047 c.Assert(err, gc.ErrorMatches, "removing filesystem 0/0: filesystem is not dead") 1048 s.assertDestroyFilesystem(c, filesystem.FilesystemTag(), state.Dying) 1049 err = s.storageBackend.RemoveFilesystem(filesystem.FilesystemTag()) 1050 c.Assert(err, gc.ErrorMatches, "removing filesystem 0/0: filesystem is not dead") 1051 } 1052 1053 func (s *FilesystemIAASModelSuite) TestDetachFilesystem(c *gc.C) { 1054 filesystem, machine := s.setupFilesystemAttachment(c, "modelscoped") 1055 assertDetach := func() { 1056 err := s.storageBackend.DetachFilesystem(machine.MachineTag(), filesystem.FilesystemTag()) 1057 c.Assert(err, jc.ErrorIsNil) 1058 attachment := s.filesystemAttachment(c, machine.MachineTag(), filesystem.FilesystemTag()) 1059 c.Assert(attachment.Life(), gc.Equals, state.Dying) 1060 } 1061 defer state.SetBeforeHooks(c, s.st, assertDetach).Check() 1062 assertDetach() 1063 } 1064 1065 func (s *FilesystemIAASModelSuite) TestRemoveLastFilesystemAttachment(c *gc.C) { 1066 filesystem, machine := s.setupFilesystemAttachment(c, "modelscoped") 1067 1068 err := s.storageBackend.DetachFilesystem(machine.MachineTag(), filesystem.FilesystemTag()) 1069 c.Assert(err, jc.ErrorIsNil) 1070 1071 err = s.storageBackend.RemoveFilesystemAttachment(machine.MachineTag(), filesystem.FilesystemTag(), false) 1072 c.Assert(err, jc.ErrorIsNil) 1073 1074 // The filesystem has no attachments, so it should go straight to Dead. 1075 s.assertDestroyFilesystem(c, filesystem.FilesystemTag(), state.Dead) 1076 assertMachineStorageRefs(c, s.storageBackend, machine.MachineTag()) 1077 } 1078 1079 func (s *FilesystemIAASModelSuite) TestRemoveLastFilesystemAttachmentConcurrently(c *gc.C) { 1080 filesystem, machine := s.setupFilesystemAttachment(c, "modelscoped") 1081 1082 err := s.storageBackend.DetachFilesystem(machine.MachineTag(), filesystem.FilesystemTag()) 1083 c.Assert(err, jc.ErrorIsNil) 1084 1085 defer state.SetBeforeHooks(c, s.st, func() { 1086 s.assertDestroyFilesystem(c, filesystem.FilesystemTag(), state.Dying) 1087 }).Check() 1088 1089 err = s.storageBackend.RemoveFilesystemAttachment(machine.MachineTag(), filesystem.FilesystemTag(), false) 1090 c.Assert(err, jc.ErrorIsNil) 1091 1092 // Last attachment was removed, and the filesystem was (concurrently) 1093 // destroyed, so the filesystem should be Dead. 1094 filesystem = s.filesystem(c, filesystem.FilesystemTag()) 1095 c.Assert(filesystem.Life(), gc.Equals, state.Dead) 1096 assertMachineStorageRefs(c, s.storageBackend, machine.MachineTag()) 1097 } 1098 1099 func (s *FilesystemStateSuite) TestRemoveFilesystemAttachmentNotFound(c *gc.C) { 1100 err := s.storageBackend.RemoveFilesystemAttachment(names.NewMachineTag("42"), names.NewFilesystemTag("42"), false) 1101 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1102 c.Assert(err, gc.ErrorMatches, `removing attachment of filesystem 42 from machine 42: filesystem "42" on "machine 42" not found`) 1103 } 1104 1105 func (s *FilesystemIAASModelSuite) TestRemoveFilesystemAttachmentConcurrently(c *gc.C) { 1106 filesystem, machine := s.setupFilesystemAttachment(c, "modelscoped") 1107 err := s.storageBackend.DetachFilesystem(machine.MachineTag(), filesystem.FilesystemTag()) 1108 c.Assert(err, jc.ErrorIsNil) 1109 remove := func() { 1110 err := s.storageBackend.RemoveFilesystemAttachment(machine.MachineTag(), filesystem.FilesystemTag(), false) 1111 c.Assert(err, jc.ErrorIsNil) 1112 assertMachineStorageRefs(c, s.storageBackend, machine.MachineTag()) 1113 } 1114 defer state.SetBeforeHooks(c, s.st, remove).Check() 1115 remove() 1116 } 1117 1118 func (s *FilesystemIAASModelSuite) TestRemoveFilesystemAttachmentAlive(c *gc.C) { 1119 filesystem, machine := s.setupFilesystemAttachment(c, "rootfs") 1120 err := s.storageBackend.RemoveFilesystemAttachment(machine.MachineTag(), filesystem.FilesystemTag(), false) 1121 c.Assert(err, gc.ErrorMatches, "removing attachment of filesystem 0/0 from machine 0: filesystem attachment is not dying") 1122 } 1123 1124 func (s *FilesystemIAASModelSuite) TestRemoveMachineRemovesFilesystems(c *gc.C) { 1125 filesystem, machine := s.setupFilesystemAttachment(c, "rootfs") 1126 1127 c.Assert(machine.Destroy(), jc.ErrorIsNil) 1128 c.Assert(machine.EnsureDead(), jc.ErrorIsNil) 1129 c.Assert(machine.Remove(), jc.ErrorIsNil) 1130 1131 // Machine is gone: filesystem should be gone too. 1132 _, err := s.storageBackend.Filesystem(filesystem.FilesystemTag()) 1133 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1134 1135 attachments, err := s.storageBackend.MachineFilesystemAttachments(machine.MachineTag()) 1136 c.Assert(err, jc.ErrorIsNil) 1137 c.Assert(attachments, gc.HasLen, 0) 1138 } 1139 1140 func (s *FilesystemIAASModelSuite) TestDestroyMachineRemovesNonDetachableFilesystems(c *gc.C) { 1141 filesystem, machine := s.setupFilesystemAttachment(c, "loop") 1142 1143 // Destroy the machine and run cleanups, which should cause the 1144 // non-detachable filesystems to be destroyed, detached, and 1145 // finally removed. 1146 c.Assert(machine.Destroy(), jc.ErrorIsNil) 1147 assertCleanupRuns(c, s.st) 1148 1149 _, err := s.storageBackend.Filesystem(filesystem.FilesystemTag()) 1150 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1151 } 1152 1153 func (s *FilesystemIAASModelSuite) TestDestroyMachineDetachesDetachableFilesystems(c *gc.C) { 1154 filesystem, machine := s.setupFilesystemAttachment(c, "modelscoped-block") 1155 1156 // Destroy the machine and run cleanups, which should cause the 1157 // detachable filesystems to be detached, but not destroyed. 1158 c.Assert(machine.Destroy(), jc.ErrorIsNil) 1159 assertCleanupRuns(c, s.st) 1160 s.testfilesystemDetached( 1161 c, machine.MachineTag(), filesystem.FilesystemTag(), 1162 ) 1163 } 1164 1165 // TODO(caas) - destroy caas storage when unit dies 1166 func (s *FilesystemIAASModelSuite) TestDestroyHostDetachesDetachableFilesystems(c *gc.C) { 1167 _, u, storageTag := s.setupSingleStorage(c, "filesystem", "modelscoped-block") 1168 hostTag := s.maybeAssignUnit(c, u) 1169 filesystem := s.storageInstanceFilesystem(c, storageTag) 1170 1171 // Destroying the unit should, if necessary, destroy its host machine, which 1172 // triggers the detachment of storage. 1173 s.obliterateUnit(c, u.UnitTag()) 1174 assertCleanupRuns(c, s.st) 1175 1176 s.testfilesystemDetached( 1177 c, hostTag, filesystem.FilesystemTag(), 1178 ) 1179 } 1180 1181 func (s *FilesystemStateSuite) testfilesystemDetached( 1182 c *gc.C, 1183 hostTag names.Tag, 1184 filesystemTag names.FilesystemTag, 1185 ) { 1186 // Filesystem is still alive... 1187 filesystem, err := s.storageBackend.Filesystem(filesystemTag) 1188 c.Assert(err, jc.ErrorIsNil) 1189 c.Assert(filesystem.Life(), gc.Equals, state.Alive) 1190 1191 // ... but it has been detached. 1192 _, err = s.storageBackend.FilesystemAttachment(hostTag, filesystemTag) 1193 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1194 1195 filesystemStatus, err := filesystem.Status() 1196 c.Assert(err, jc.ErrorIsNil) 1197 c.Assert(filesystemStatus.Status, gc.Equals, status.Detached) 1198 c.Assert(filesystemStatus.Message, gc.Equals, "") 1199 } 1200 1201 func (s *FilesystemIAASModelSuite) TestDestroyManualMachineDoesntRemoveNonDetachableFilesystems(c *gc.C) { 1202 filesystem, machine := s.setupFilesystemAttachment(c, "loop") 1203 1204 // Make this a manual machine, so the cleanup. 1205 err := machine.SetProvisioned("inst-id", "", "manual:machine", nil) 1206 c.Assert(err, jc.ErrorIsNil) 1207 1208 // Destroy the machine and run cleanups, which should cause the 1209 // non-detachable filesystems and attachments to be set to Dying, 1210 // but not completely removed. 1211 c.Assert(machine.Destroy(), jc.ErrorIsNil) 1212 assertCleanupRuns(c, s.st) 1213 1214 filesystem, err = s.storageBackend.Filesystem(filesystem.FilesystemTag()) 1215 c.Assert(err, jc.ErrorIsNil) 1216 c.Assert(filesystem.Life(), gc.Equals, state.Dying) 1217 attachment, err := s.storageBackend.FilesystemAttachment( 1218 machine.MachineTag(), 1219 filesystem.FilesystemTag(), 1220 ) 1221 c.Assert(err, jc.ErrorIsNil) 1222 c.Assert(attachment.Life(), gc.Equals, state.Dying) 1223 } 1224 1225 func (s *FilesystemIAASModelSuite) TestDestroyManualMachineDoesntDetachDetachableFilesystems(c *gc.C) { 1226 filesystem, machine := s.setupFilesystemAttachment(c, "modelscoped-block") 1227 1228 // Make this a manual machine, so the cleanup. 1229 err := machine.SetProvisioned("inst-id", "", "manual:machine", nil) 1230 c.Assert(err, jc.ErrorIsNil) 1231 1232 // Destroy the machine and run cleanups, which should cause the 1233 // detachable filesystem attachments to be set to Dying, but not 1234 // completely removed. The filesystem itself should be left Alive. 1235 c.Assert(machine.Destroy(), jc.ErrorIsNil) 1236 assertCleanupRuns(c, s.st) 1237 1238 filesystem, err = s.storageBackend.Filesystem(filesystem.FilesystemTag()) 1239 c.Assert(err, jc.ErrorIsNil) 1240 c.Assert(filesystem.Life(), gc.Equals, state.Alive) 1241 attachment, err := s.storageBackend.FilesystemAttachment( 1242 machine.MachineTag(), 1243 filesystem.FilesystemTag(), 1244 ) 1245 c.Assert(err, jc.ErrorIsNil) 1246 c.Assert(attachment.Life(), gc.Equals, state.Dying) 1247 } 1248 1249 func (s *FilesystemIAASModelSuite) TestFilesystemMachineScoped(c *gc.C) { 1250 // Machine-scoped filesystems created unassigned to a storage 1251 // instance are bound to the machine. 1252 filesystem, machine := s.setupFilesystemAttachment(c, "rootfs") 1253 1254 err := s.storageBackend.DetachFilesystem(machine.MachineTag(), filesystem.FilesystemTag()) 1255 c.Assert(err, gc.ErrorMatches, "detaching filesystem 0/0 from machine 0: filesystem is not detachable") 1256 err = machine.Destroy() 1257 c.Assert(err, jc.ErrorIsNil) 1258 err = machine.EnsureDead() 1259 c.Assert(err, jc.ErrorIsNil) 1260 err = machine.Remove() 1261 c.Assert(err, jc.ErrorIsNil) 1262 1263 _, err = s.storageBackend.Filesystem(filesystem.FilesystemTag()) 1264 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1265 _, err = s.storageBackend.FilesystemAttachment( 1266 machine.MachineTag(), 1267 filesystem.FilesystemTag(), 1268 ) 1269 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1270 } 1271 1272 func (s *FilesystemStateSuite) TestFilesystemRemoveStorageDestroysFilesystem(c *gc.C) { 1273 // Filesystems created assigned to a storage instance are bound 1274 // to the machine/model, and not the storage. i.e. storage is 1275 // persistent by default. 1276 _, u, storageTag := s.setupSingleStorage(c, "filesystem", "rootfs") 1277 s.maybeAssignUnit(c, u) 1278 filesystem := s.storageInstanceFilesystem(c, storageTag) 1279 1280 // The filesystem should transition to Dying when the storage is removed. 1281 // We must destroy the unit before we can remove the storage. 1282 err := u.Destroy() 1283 c.Assert(err, jc.ErrorIsNil) 1284 removeStorageInstance(c, s.storageBackend, storageTag) 1285 filesystem = s.filesystem(c, filesystem.FilesystemTag()) 1286 c.Assert(filesystem.Life(), gc.Equals, state.Dying) 1287 } 1288 1289 func (s *FilesystemIAASModelSuite) TestEnsureMachineDeadAddFilesystemConcurrently(c *gc.C) { 1290 _, machine := s.setupFilesystemAttachment(c, "rootfs") 1291 addFilesystem := func() { 1292 _, u, _ := s.setupSingleStorage(c, "filesystem", "rootfs") 1293 err := u.AssignToMachine(machine) 1294 c.Assert(err, jc.ErrorIsNil) 1295 s.obliterateUnit(c, u.UnitTag()) 1296 } 1297 defer state.SetBeforeHooks(c, s.st, addFilesystem).Check() 1298 1299 // Adding another filesystem to the machine will cause EnsureDead to 1300 // retry, but it will succeed because both filesystems are inherently 1301 // machine-bound. 1302 err := machine.EnsureDead() 1303 c.Assert(err, jc.ErrorIsNil) 1304 } 1305 1306 func (s *FilesystemIAASModelSuite) TestEnsureMachineDeadRemoveFilesystemConcurrently(c *gc.C) { 1307 filesystem, machine := s.setupFilesystemAttachment(c, "rootfs") 1308 removeFilesystem := func() { 1309 s.obliterateFilesystem(c, filesystem.FilesystemTag()) 1310 } 1311 defer state.SetBeforeHooks(c, s.st, removeFilesystem).Check() 1312 1313 // Removing a filesystem concurrently does not cause a transaction failure. 1314 err := machine.EnsureDead() 1315 c.Assert(err, jc.ErrorIsNil) 1316 } 1317 1318 func (s *FilesystemStateSuite) TestFilesystemAttachmentParamsSingletonNoLocation(c *gc.C) { 1319 s.testFilesystemAttachmentParams(c, 0, 1, "", state.FilesystemAttachmentParams{ 1320 Location: "/var/lib/juju/storage/data/0", 1321 }) 1322 } 1323 1324 func (s *FilesystemStateSuite) TestFilesystemAttachmentParamsMultipleNoLocation(c *gc.C) { 1325 s.testFilesystemAttachmentParams(c, 0, -1, "", state.FilesystemAttachmentParams{ 1326 Location: "/var/lib/juju/storage/data/0", 1327 }) 1328 } 1329 1330 func (s *FilesystemStateSuite) TestFilesystemAttachmentParamsSingletonLocation(c *gc.C) { 1331 s.testFilesystemAttachmentParams(c, 0, 1, "/srv", state.FilesystemAttachmentParams{ 1332 Location: "/srv", 1333 }) 1334 } 1335 1336 func (s *FilesystemStateSuite) TestFilesystemAttachmentParamsMultipleLocation(c *gc.C) { 1337 s.testFilesystemAttachmentParams(c, 0, -1, "/srv", state.FilesystemAttachmentParams{ 1338 Location: "/srv/data/0", 1339 }) 1340 } 1341 1342 func (s *FilesystemStateSuite) testFilesystemAttachmentParams( 1343 c *gc.C, countMin, countMax int, location string, 1344 expect state.FilesystemAttachmentParams, 1345 ) { 1346 ch := s.createStorageCharmWithSeries(c, "storage-filesystem", charm.Storage{ 1347 Name: "data", 1348 Type: charm.StorageFilesystem, 1349 CountMin: countMin, 1350 CountMax: countMax, 1351 Location: location, 1352 }, s.series) 1353 storage := map[string]state.StorageConstraints{ 1354 "data": makeStorageCons("rootfs", 1024, 1), 1355 } 1356 1357 app := s.AddTestingApplicationWithStorage(c, "storage-filesystem", ch, storage) 1358 unit, err := app.AddUnit(state.AddUnitParams{}) 1359 c.Assert(err, jc.ErrorIsNil) 1360 hostTag := s.maybeAssignUnit(c, unit) 1361 1362 storageTag := names.NewStorageTag("data/0") 1363 filesystem := s.storageInstanceFilesystem(c, storageTag) 1364 filesystemAttachment := s.filesystemAttachment( 1365 c, hostTag, filesystem.FilesystemTag(), 1366 ) 1367 params, ok := filesystemAttachment.Params() 1368 c.Assert(ok, jc.IsTrue) 1369 c.Assert(params, jc.DeepEquals, expect) 1370 } 1371 1372 func (s *FilesystemIAASModelSuite) TestFilesystemAttachmentParamsLocationConflictConcurrent(c *gc.C) { 1373 s.testFilesystemAttachmentParamsConcurrent( 1374 c, "/srv", "/srv", 1375 `cannot assign unit "storage-filesystem-after/0" to machine 0: `+ 1376 `validating filesystem mount points: `+ 1377 `mount point "/srv" for "data" storage contains mount point "/srv" for "data" storage`) 1378 } 1379 1380 func (s *FilesystemIAASModelSuite) TestFilesystemAttachmentParamsLocationAutoConcurrent(c *gc.C) { 1381 s.testFilesystemAttachmentParamsConcurrent(c, "", "", "") 1382 } 1383 1384 func (s *FilesystemIAASModelSuite) TestFilesystemAttachmentParamsLocationAutoAndManualConcurrent(c *gc.C) { 1385 s.testFilesystemAttachmentParamsConcurrent(c, "", "/srv", "") 1386 } 1387 1388 func (s *FilesystemStateSuite) testFilesystemAttachmentParamsConcurrent(c *gc.C, locBefore, locAfter, expectErr string) { 1389 machine, err := s.State.AddMachine(state.UbuntuBase("12.10"), state.JobHostUnits) 1390 c.Assert(err, jc.ErrorIsNil) 1391 1392 storage := map[string]state.StorageConstraints{ 1393 "data": makeStorageCons("rootfs", 1024, 1), 1394 } 1395 1396 deploy := func(rev int, location, applicationname string) error { 1397 ch := s.createStorageCharmRev(c, "storage-filesystem", charm.Storage{ 1398 Name: "data", 1399 Type: charm.StorageFilesystem, 1400 CountMin: 1, 1401 CountMax: 1, 1402 Location: location, 1403 }, rev) 1404 app := s.AddTestingApplicationWithStorage(c, applicationname, ch, storage) 1405 unit, err := app.AddUnit(state.AddUnitParams{}) 1406 c.Assert(err, jc.ErrorIsNil) 1407 return unit.AssignToMachine(machine) 1408 } 1409 1410 defer state.SetBeforeHooks(c, s.st, func() { 1411 err := deploy(1, locBefore, "storage-filesystem-before") 1412 c.Assert(err, jc.ErrorIsNil) 1413 }).Check() 1414 1415 err = deploy(2, locAfter, "storage-filesystem-after") 1416 if expectErr != "" { 1417 c.Assert(err, gc.ErrorMatches, expectErr) 1418 } else { 1419 c.Assert(err, jc.ErrorIsNil) 1420 } 1421 } 1422 1423 func (s *FilesystemIAASModelSuite) TestFilesystemAttachmentParamsConcurrentRemove(c *gc.C) { 1424 // this creates a filesystem mounted at "/srv". 1425 filesystem, machine := s.setupFilesystemAttachment(c, "modelscoped") 1426 1427 ch := s.createStorageCharm(c, "storage-filesystem", charm.Storage{ 1428 Name: "data", 1429 Type: charm.StorageFilesystem, 1430 CountMin: 1, 1431 CountMax: 1, 1432 Location: "/not/in/srv", 1433 }) 1434 app := s.AddTestingApplication(c, "storage-filesystem", ch) 1435 unit, err := app.AddUnit(state.AddUnitParams{}) 1436 c.Assert(err, jc.ErrorIsNil) 1437 1438 defer state.SetBeforeHooks(c, s.st, func() { 1439 err := s.storageBackend.DetachFilesystem(machine.MachineTag(), filesystem.FilesystemTag()) 1440 c.Assert(err, jc.ErrorIsNil) 1441 err = s.storageBackend.RemoveFilesystemAttachment( 1442 machine.MachineTag(), filesystem.FilesystemTag(), false, 1443 ) 1444 c.Assert(err, jc.ErrorIsNil) 1445 }).Check() 1446 1447 err = unit.AssignToMachine(machine) 1448 c.Assert(err, jc.ErrorIsNil) 1449 } 1450 1451 func (s *FilesystemStateSuite) TestFilesystemAttachmentParamsLocationStorageDir(c *gc.C) { 1452 ch := s.createStorageCharmWithSeries(c, "storage-filesystem", charm.Storage{ 1453 Name: "data", 1454 Type: charm.StorageFilesystem, 1455 CountMin: 1, 1456 CountMax: 1, 1457 Location: "/var/lib/juju/storage", 1458 }, s.series) 1459 app := s.AddTestingApplication(c, "storage-filesystem", ch) 1460 unit, err := app.AddUnit(state.AddUnitParams{}) 1461 if s.series != "kubernetes" { 1462 c.Assert(err, jc.ErrorIsNil) 1463 err = s.State.AssignUnit(unit, state.AssignCleanEmpty) 1464 } 1465 c.Assert(err, gc.ErrorMatches, `.*`+ 1466 `getting filesystem mount point for storage data: `+ 1467 `invalid location "/var/lib/juju/storage": `+ 1468 `must not fall within "/var/lib/juju/storage"`) 1469 } 1470 1471 func (s *FilesystemIAASModelSuite) TestFilesystemAttachmentLocationConflict(c *gc.C) { 1472 // this creates a filesystem mounted at "/srv". 1473 _, machine := s.setupFilesystemAttachment(c, "rootfs") 1474 1475 ch := s.createStorageCharm(c, "storage-filesystem", charm.Storage{ 1476 Name: "data", 1477 Type: charm.StorageFilesystem, 1478 CountMin: 1, 1479 CountMax: 1, 1480 Location: "/srv/within", 1481 }) 1482 app := s.AddTestingApplication(c, "storage-filesystem", ch) 1483 1484 u, err := app.AddUnit(state.AddUnitParams{}) 1485 c.Assert(err, jc.ErrorIsNil) 1486 err = u.AssignToMachine(machine) 1487 c.Assert(err, gc.ErrorMatches, 1488 `cannot assign unit "storage-filesystem/0" to machine 0: `+ 1489 `validating filesystem mount points: `+ 1490 `mount point "/srv" for filesystem 0/0 contains `+ 1491 `mount point "/srv/within" for "data" storage`) 1492 } 1493 1494 func (s *FilesystemIAASModelSuite) TestAddExistingFilesystem(c *gc.C) { 1495 fsInfoIn := state.FilesystemInfo{ 1496 Pool: "modelscoped", 1497 Size: 123, 1498 FilesystemId: "foo", 1499 } 1500 storageTag, err := s.storageBackend.AddExistingFilesystem(fsInfoIn, nil, "pgdata") 1501 c.Assert(err, jc.ErrorIsNil) 1502 c.Assert(storageTag, gc.Equals, names.NewStorageTag("pgdata/0")) 1503 1504 filesystem, err := s.storageBackend.StorageInstanceFilesystem(storageTag) 1505 c.Assert(err, jc.ErrorIsNil) 1506 fsInfoOut, err := filesystem.Info() 1507 c.Assert(err, jc.ErrorIsNil) 1508 c.Assert(fsInfoOut, jc.DeepEquals, fsInfoIn) 1509 1510 fsStatus, err := filesystem.Status() 1511 c.Assert(err, jc.ErrorIsNil) 1512 c.Assert(fsStatus.Status, gc.Equals, status.Detached) 1513 } 1514 1515 func (s *FilesystemIAASModelSuite) TestAddExistingFilesystemEmptyFilesystemId(c *gc.C) { 1516 fsInfoIn := state.FilesystemInfo{ 1517 Pool: "modelscoped", 1518 Size: 123, 1519 } 1520 _, err := s.storageBackend.AddExistingFilesystem(fsInfoIn, nil, "pgdata") 1521 c.Assert(err, gc.ErrorMatches, "cannot add existing filesystem: empty filesystem ID not valid") 1522 } 1523 1524 func (s *FilesystemIAASModelSuite) TestAddExistingFilesystemVolumeBacked(c *gc.C) { 1525 fsInfoIn := state.FilesystemInfo{ 1526 Pool: "modelscoped-block", 1527 Size: 123, 1528 } 1529 volInfoIn := state.VolumeInfo{ 1530 Pool: "modelscoped-block", 1531 Size: 123, 1532 VolumeId: "foo", 1533 } 1534 storageTag, err := s.storageBackend.AddExistingFilesystem(fsInfoIn, &volInfoIn, "pgdata") 1535 c.Assert(err, jc.ErrorIsNil) 1536 c.Assert(storageTag, gc.Equals, names.NewStorageTag("pgdata/0")) 1537 1538 filesystem, err := s.storageBackend.StorageInstanceFilesystem(storageTag) 1539 c.Assert(err, jc.ErrorIsNil) 1540 fsInfoOut, err := filesystem.Info() 1541 c.Assert(err, jc.ErrorIsNil) 1542 fsInfoIn.FilesystemId = "filesystem-0" // set by AddExistingFilesystem 1543 c.Assert(fsInfoOut, jc.DeepEquals, fsInfoIn) 1544 1545 fsStatus, err := filesystem.Status() 1546 c.Assert(err, jc.ErrorIsNil) 1547 c.Assert(fsStatus.Status, gc.Equals, status.Detached) 1548 1549 volume, err := s.storageBackend.StorageInstanceVolume(storageTag) 1550 c.Assert(err, jc.ErrorIsNil) 1551 volInfoOut, err := volume.Info() 1552 c.Assert(err, jc.ErrorIsNil) 1553 c.Assert(volInfoOut, jc.DeepEquals, volInfoIn) 1554 1555 volStatus, err := volume.Status() 1556 c.Assert(err, jc.ErrorIsNil) 1557 c.Assert(volStatus.Status, gc.Equals, status.Detached) 1558 } 1559 1560 func (s *FilesystemIAASModelSuite) TestAddExistingFilesystemVolumeBackedVolumeInfoMissing(c *gc.C) { 1561 fsInfo := state.FilesystemInfo{ 1562 Pool: "modelscoped-block", 1563 Size: 123, 1564 FilesystemId: "foo", 1565 } 1566 _, err := s.storageBackend.AddExistingFilesystem(fsInfo, nil, "pgdata") 1567 c.Assert(err, gc.ErrorMatches, "cannot add existing filesystem: backing volume info missing") 1568 } 1569 1570 func (s *FilesystemStateSuite) TestAddExistingFilesystemVolumeBackedFilesystemIdSupplied(c *gc.C) { 1571 fsInfo := state.FilesystemInfo{ 1572 Pool: "modelscoped-block", 1573 Size: 123, 1574 FilesystemId: "foo", 1575 } 1576 volInfo := state.VolumeInfo{ 1577 Pool: "modelscoped-block", 1578 Size: 123, 1579 VolumeId: "foo", 1580 } 1581 _, err := s.storageBackend.AddExistingFilesystem(fsInfo, &volInfo, "pgdata") 1582 c.Assert(err, gc.ErrorMatches, "cannot add existing filesystem: non-empty filesystem ID with backing volume not valid") 1583 } 1584 1585 func (s *FilesystemStateSuite) TestAddExistingFilesystemVolumeBackedEmptyVolumeId(c *gc.C) { 1586 fsInfo := state.FilesystemInfo{ 1587 Pool: "modelscoped-block", 1588 Size: 123, 1589 } 1590 volInfo := state.VolumeInfo{ 1591 Pool: "modelscoped-block", 1592 Size: 123, 1593 } 1594 _, err := s.storageBackend.AddExistingFilesystem(fsInfo, &volInfo, "pgdata") 1595 c.Assert(err, gc.ErrorMatches, "cannot add existing filesystem: empty backing volume ID not valid") 1596 } 1597 1598 func (s *FilesystemStateSuite) setupFilesystemAttachment(c *gc.C, pool string) (state.Filesystem, *state.Machine) { 1599 machine, err := s.st.AddOneMachine(state.MachineTemplate{ 1600 Base: state.UbuntuBase("12.10"), 1601 Jobs: []state.MachineJob{state.JobHostUnits}, 1602 Filesystems: []state.HostFilesystemParams{{ 1603 Filesystem: state.FilesystemParams{Pool: pool, Size: 1024}, 1604 Attachment: state.FilesystemAttachmentParams{ 1605 Location: "/srv", 1606 }, 1607 }}, 1608 }) 1609 c.Assert(err, jc.ErrorIsNil) 1610 sb, err := state.NewStorageBackend(s.st) 1611 c.Assert(err, jc.ErrorIsNil) 1612 attachments, err := sb.MachineFilesystemAttachments(machine.MachineTag()) 1613 c.Assert(err, jc.ErrorIsNil) 1614 c.Assert(attachments, gc.HasLen, 1) 1615 c.Assert(err, jc.ErrorIsNil) 1616 assertMachineStorageRefs(c, s.storageBackend, machine.MachineTag()) 1617 return s.filesystem(c, attachments[0].Filesystem()), machine 1618 } 1619 1620 func removeFilesystemStorageInstance(c *gc.C, sb *state.StorageBackend, filesystemTag names.FilesystemTag) { 1621 filesystem, err := sb.Filesystem(filesystemTag) 1622 c.Assert(err, jc.ErrorIsNil) 1623 storageTag, err := filesystem.Storage() 1624 c.Assert(err, jc.ErrorIsNil) 1625 removeStorageInstance(c, sb, storageTag) 1626 } 1627 1628 func (s *FilesystemStateSuite) assertDestroyFilesystem(c *gc.C, tag names.FilesystemTag, life state.Life) { 1629 err := s.storageBackend.DestroyFilesystem(tag, false) 1630 c.Assert(err, jc.ErrorIsNil) 1631 filesystem := s.filesystem(c, tag) 1632 c.Assert(filesystem.Life(), gc.Equals, life) 1633 }