github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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/errors" 8 jc "github.com/juju/testing/checkers" 9 gc "gopkg.in/check.v1" 10 "gopkg.in/juju/charm.v6-unstable" 11 "gopkg.in/juju/names.v2" 12 13 "github.com/juju/juju/state" 14 "github.com/juju/juju/state/testing" 15 ) 16 17 type FilesystemStateSuite struct { 18 StorageStateSuiteBase 19 } 20 21 var _ = gc.Suite(&FilesystemStateSuite{}) 22 23 func (s *FilesystemStateSuite) TestAddServiceInvalidPool(c *gc.C) { 24 ch := s.AddTestingCharm(c, "storage-filesystem") 25 storage := map[string]state.StorageConstraints{ 26 "data": makeStorageCons("invalid-pool", 1024, 1), 27 } 28 _, err := s.State.AddApplication(state.AddApplicationArgs{Name: "storage-filesystem", Charm: ch, Storage: storage}) 29 c.Assert(err, gc.ErrorMatches, `.* pool "invalid-pool" not found`) 30 } 31 32 func (s *FilesystemStateSuite) TestAddServiceNoPoolNoDefault(c *gc.C) { 33 // no pool specified, no default configured: use rootfs. 34 s.testAddServiceDefaultPool(c, "rootfs", 0) 35 } 36 37 func (s *FilesystemStateSuite) TestAddServiceNoPoolNoDefaultWithUnits(c *gc.C) { 38 // no pool specified, no default configured: use rootfs, add a unit during 39 // service deploy. 40 s.testAddServiceDefaultPool(c, "rootfs", 1) 41 } 42 43 func (s *FilesystemStateSuite) TestAddServiceNoPoolDefaultBlock(c *gc.C) { 44 // no pool specified, default block configured: use default 45 // block with managed fs on top. 46 err := s.State.UpdateModelConfig(map[string]interface{}{ 47 "storage-default-block-source": "machinescoped", 48 }, nil, nil) 49 c.Assert(err, jc.ErrorIsNil) 50 s.testAddServiceDefaultPool(c, "machinescoped", 0) 51 } 52 53 func (s *FilesystemStateSuite) testAddServiceDefaultPool(c *gc.C, expectedPool string, numUnits int) { 54 ch := s.AddTestingCharm(c, "storage-filesystem") 55 storage := map[string]state.StorageConstraints{ 56 "data": makeStorageCons("", 1024, 1), 57 } 58 59 args := state.AddApplicationArgs{ 60 Name: "storage-filesystem", 61 Charm: ch, 62 Storage: storage, 63 NumUnits: numUnits, 64 } 65 svc, err := s.State.AddApplication(args) 66 c.Assert(err, jc.ErrorIsNil) 67 cons, err := svc.StorageConstraints() 68 c.Assert(err, jc.ErrorIsNil) 69 expected := map[string]state.StorageConstraints{ 70 "data": state.StorageConstraints{ 71 Pool: expectedPool, 72 Size: 1024, 73 Count: 1, 74 }, 75 } 76 c.Assert(cons, jc.DeepEquals, expected) 77 78 svc, err = s.State.Application(args.Name) 79 c.Assert(err, jc.ErrorIsNil) 80 81 units, err := svc.AllUnits() 82 c.Assert(err, jc.ErrorIsNil) 83 c.Assert(units, gc.HasLen, numUnits) 84 85 for _, unit := range units { 86 scons, err := unit.StorageConstraints() 87 c.Assert(err, jc.ErrorIsNil) 88 c.Assert(scons, gc.DeepEquals, expected) 89 90 storageAttachments, err := s.State.UnitStorageAttachments(unit.UnitTag()) 91 c.Assert(err, jc.ErrorIsNil) 92 c.Assert(storageAttachments, gc.HasLen, 1) 93 storageInstance, err := s.State.StorageInstance(storageAttachments[0].StorageInstance()) 94 c.Assert(err, jc.ErrorIsNil) 95 c.Assert(storageInstance.Kind(), gc.Equals, state.StorageKindFilesystem) 96 } 97 } 98 99 func (s *FilesystemStateSuite) TestAddFilesystemWithoutBackingVolume(c *gc.C) { 100 s.addUnitWithFilesystem(c, "rootfs", false) 101 } 102 103 func (s *FilesystemStateSuite) TestAddFilesystemWithBackingVolume(c *gc.C) { 104 s.addUnitWithFilesystem(c, "loop", true) 105 } 106 107 func (s *FilesystemStateSuite) TestSetFilesystemInfoImmutable(c *gc.C) { 108 _, u, storageTag := s.setupSingleStorage(c, "filesystem", "rootfs") 109 err := s.State.AssignUnit(u, state.AssignCleanEmpty) 110 c.Assert(err, jc.ErrorIsNil) 111 filesystem := s.storageInstanceFilesystem(c, storageTag) 112 filesystemTag := filesystem.FilesystemTag() 113 114 assignedMachineId, err := u.AssignedMachineId() 115 c.Assert(err, jc.ErrorIsNil) 116 machine, err := s.State.Machine(assignedMachineId) 117 c.Assert(err, jc.ErrorIsNil) 118 err = machine.SetProvisioned("inst-id", "fake_nonce", nil) 119 c.Assert(err, jc.ErrorIsNil) 120 121 filesystemInfoSet := state.FilesystemInfo{Size: 123, FilesystemId: "fs-id"} 122 err = s.State.SetFilesystemInfo(filesystem.FilesystemTag(), filesystemInfoSet) 123 c.Assert(err, jc.ErrorIsNil) 124 125 // The first call to SetFilesystemInfo takes the pool name from 126 // the params; the second does not, but it must not change 127 // either. Callers are expected to get the existing info and 128 // update it, leaving immutable values intact. 129 err = s.State.SetFilesystemInfo(filesystem.FilesystemTag(), filesystemInfoSet) 130 c.Assert(err, gc.ErrorMatches, `cannot set info for filesystem "0/0": cannot change pool from "rootfs" to ""`) 131 132 filesystemInfoSet.Pool = "rootfs" 133 s.assertFilesystemInfo(c, filesystemTag, filesystemInfoSet) 134 } 135 136 func (s *FilesystemStateSuite) TestSetFilesystemInfoNoFilesystemId(c *gc.C) { 137 _, u, storageTag := s.setupSingleStorage(c, "filesystem", "loop-pool") 138 err := s.State.AssignUnit(u, state.AssignCleanEmpty) 139 c.Assert(err, jc.ErrorIsNil) 140 141 filesystem := s.storageInstanceFilesystem(c, storageTag) 142 filesystemTag := filesystem.FilesystemTag() 143 s.assertFilesystemUnprovisioned(c, filesystemTag) 144 145 filesystemInfoSet := state.FilesystemInfo{Size: 123} 146 err = s.State.SetFilesystemInfo(filesystem.FilesystemTag(), filesystemInfoSet) 147 c.Assert(err, gc.ErrorMatches, `cannot set info for filesystem "0/0": filesystem ID not set`) 148 } 149 150 func (s *FilesystemStateSuite) TestVolumeFilesystem(c *gc.C) { 151 filesystemAttachment, _ := s.addUnitWithFilesystem(c, "loop", true) 152 filesystem := s.filesystem(c, filesystemAttachment.Filesystem()) 153 _, err := filesystem.Info() 154 c.Assert(err, jc.Satisfies, errors.IsNotProvisioned) 155 156 volumeTag, err := filesystem.Volume() 157 c.Assert(err, jc.ErrorIsNil) 158 filesystem = s.volumeFilesystem(c, volumeTag) 159 c.Assert(filesystem.FilesystemTag(), gc.Equals, filesystemAttachment.Filesystem()) 160 } 161 162 func (s *FilesystemStateSuite) addUnitWithFilesystem(c *gc.C, pool string, withVolume bool) (state.FilesystemAttachment, state.StorageAttachment) { 163 ch := s.AddTestingCharm(c, "storage-filesystem") 164 storage := map[string]state.StorageConstraints{ 165 "data": makeStorageCons(pool, 1024, 1), 166 } 167 service := s.AddTestingServiceWithStorage(c, "storage-filesystem", ch, storage) 168 unit, err := service.AddUnit() 169 c.Assert(err, jc.ErrorIsNil) 170 err = s.State.AssignUnit(unit, state.AssignCleanEmpty) 171 c.Assert(err, jc.ErrorIsNil) 172 assignedMachineId, err := unit.AssignedMachineId() 173 c.Assert(err, jc.ErrorIsNil) 174 assignedMachineTag := names.NewMachineTag(assignedMachineId) 175 176 storageAttachments, err := s.State.UnitStorageAttachments(unit.UnitTag()) 177 c.Assert(err, jc.ErrorIsNil) 178 c.Assert(storageAttachments, gc.HasLen, 1) 179 storageInstance, err := s.State.StorageInstance(storageAttachments[0].StorageInstance()) 180 c.Assert(err, jc.ErrorIsNil) 181 c.Assert(storageInstance.Kind(), gc.Equals, state.StorageKindFilesystem) 182 183 filesystem := s.storageInstanceFilesystem(c, storageInstance.StorageTag()) 184 c.Assert(filesystem.FilesystemTag(), gc.Equals, names.NewFilesystemTag("0/0")) 185 filesystemStorageTag, err := filesystem.Storage() 186 c.Assert(err, jc.ErrorIsNil) 187 c.Assert(filesystemStorageTag, gc.Equals, storageInstance.StorageTag()) 188 _, err = filesystem.Info() 189 c.Assert(err, jc.Satisfies, errors.IsNotProvisioned) 190 _, ok := filesystem.Params() 191 c.Assert(ok, jc.IsTrue) 192 193 volume, err := s.State.StorageInstanceVolume(storageInstance.StorageTag()) 194 if withVolume { 195 c.Assert(err, jc.ErrorIsNil) 196 c.Assert(volume.VolumeTag(), gc.Equals, names.NewVolumeTag("0/0")) 197 volumeStorageTag, err := volume.StorageInstance() 198 c.Assert(err, jc.ErrorIsNil) 199 c.Assert(volumeStorageTag, gc.Equals, storageInstance.StorageTag()) 200 filesystemVolume, err := filesystem.Volume() 201 c.Assert(err, jc.ErrorIsNil) 202 c.Assert(filesystemVolume, gc.Equals, volume.VolumeTag()) 203 _, err = s.State.VolumeAttachment(assignedMachineTag, filesystemVolume) 204 c.Assert(err, jc.ErrorIsNil) 205 } else { 206 c.Assert(err, jc.Satisfies, errors.IsNotFound) 207 _, err = filesystem.Volume() 208 c.Assert(errors.Cause(err), gc.Equals, state.ErrNoBackingVolume) 209 } 210 211 machine, err := s.State.Machine(assignedMachineId) 212 c.Assert(err, jc.ErrorIsNil) 213 filesystemAttachments, err := s.State.MachineFilesystemAttachments(assignedMachineTag) 214 c.Assert(err, jc.ErrorIsNil) 215 c.Assert(filesystemAttachments, gc.HasLen, 1) 216 c.Assert(filesystemAttachments[0].Filesystem(), gc.Equals, filesystem.FilesystemTag()) 217 c.Assert(filesystemAttachments[0].Machine(), gc.Equals, machine.MachineTag()) 218 _, err = filesystemAttachments[0].Info() 219 c.Assert(err, jc.Satisfies, errors.IsNotProvisioned) 220 _, ok = filesystemAttachments[0].Params() 221 c.Assert(ok, jc.IsTrue) 222 223 assertMachineStorageRefs(c, s.State, machine.MachineTag()) 224 225 att, err := s.State.FilesystemAttachment(machine.MachineTag(), filesystem.FilesystemTag()) 226 c.Assert(err, jc.ErrorIsNil) 227 return att, storageAttachments[0] 228 } 229 230 func (s *FilesystemStateSuite) TestWatchFilesystemAttachment(c *gc.C) { 231 _, u, storageTag := s.setupSingleStorage(c, "filesystem", "rootfs") 232 err := s.State.AssignUnit(u, state.AssignCleanEmpty) 233 c.Assert(err, jc.ErrorIsNil) 234 assignedMachineId, err := u.AssignedMachineId() 235 c.Assert(err, jc.ErrorIsNil) 236 machineTag := names.NewMachineTag(assignedMachineId) 237 238 filesystem := s.storageInstanceFilesystem(c, storageTag) 239 filesystemTag := filesystem.FilesystemTag() 240 241 w := s.State.WatchFilesystemAttachment(machineTag, filesystemTag) 242 defer testing.AssertStop(c, w) 243 wc := testing.NewNotifyWatcherC(c, s.State, w) 244 wc.AssertOneChange() 245 246 machine, err := s.State.Machine(assignedMachineId) 247 c.Assert(err, jc.ErrorIsNil) 248 err = machine.SetProvisioned("inst-id", "fake_nonce", nil) 249 c.Assert(err, jc.ErrorIsNil) 250 251 // filesystem attachment will NOT react to filesystem changes 252 err = s.State.SetFilesystemInfo(filesystemTag, state.FilesystemInfo{ 253 FilesystemId: "fs-123", 254 }) 255 c.Assert(err, jc.ErrorIsNil) 256 wc.AssertNoChange() 257 258 err = s.State.SetFilesystemAttachmentInfo( 259 machineTag, filesystemTag, state.FilesystemAttachmentInfo{ 260 MountPoint: "/srv", 261 }, 262 ) 263 c.Assert(err, jc.ErrorIsNil) 264 wc.AssertOneChange() 265 } 266 267 func (s *FilesystemStateSuite) TestFilesystemInfo(c *gc.C) { 268 _, u, storageTag := s.setupSingleStorage(c, "filesystem", "rootfs") 269 err := s.State.AssignUnit(u, state.AssignCleanEmpty) 270 c.Assert(err, jc.ErrorIsNil) 271 assignedMachineId, err := u.AssignedMachineId() 272 c.Assert(err, jc.ErrorIsNil) 273 machineTag := names.NewMachineTag(assignedMachineId) 274 275 filesystem := s.storageInstanceFilesystem(c, storageTag) 276 filesystemTag := filesystem.FilesystemTag() 277 278 s.assertFilesystemUnprovisioned(c, filesystemTag) 279 s.assertFilesystemAttachmentUnprovisioned(c, machineTag, filesystemTag) 280 281 machine, err := s.State.Machine(assignedMachineId) 282 c.Assert(err, jc.ErrorIsNil) 283 err = machine.SetProvisioned("inst-id", "fake_nonce", nil) 284 c.Assert(err, jc.ErrorIsNil) 285 286 filesystemInfo := state.FilesystemInfo{FilesystemId: "fs-123", Size: 456} 287 err = s.State.SetFilesystemInfo(filesystemTag, filesystemInfo) 288 c.Assert(err, jc.ErrorIsNil) 289 filesystemInfo.Pool = "rootfs" // taken from params 290 s.assertFilesystemInfo(c, filesystemTag, filesystemInfo) 291 s.assertFilesystemAttachmentUnprovisioned(c, machineTag, filesystemTag) 292 293 filesystemAttachmentInfo := state.FilesystemAttachmentInfo{MountPoint: "/srv"} 294 err = s.State.SetFilesystemAttachmentInfo(machineTag, filesystemTag, filesystemAttachmentInfo) 295 c.Assert(err, jc.ErrorIsNil) 296 s.assertFilesystemAttachmentInfo(c, machineTag, filesystemTag, filesystemAttachmentInfo) 297 } 298 299 func (s *FilesystemStateSuite) TestVolumeBackedFilesystemScope(c *gc.C) { 300 _, unit, storageTag := s.setupSingleStorage(c, "filesystem", "environscoped-block") 301 err := s.State.AssignUnit(unit, state.AssignCleanEmpty) 302 c.Assert(err, jc.ErrorIsNil) 303 304 filesystem := s.storageInstanceFilesystem(c, storageTag) 305 c.Assert(filesystem.Tag(), gc.Equals, names.NewFilesystemTag("0/0")) 306 volumeTag, err := filesystem.Volume() 307 c.Assert(err, jc.ErrorIsNil) 308 c.Assert(volumeTag, gc.Equals, names.NewVolumeTag("0")) 309 } 310 311 func (s *FilesystemStateSuite) TestWatchModelFilesystems(c *gc.C) { 312 service := s.setupMixedScopeStorageService(c, "filesystem") 313 addUnit := func() { 314 u, err := service.AddUnit() 315 c.Assert(err, jc.ErrorIsNil) 316 err = s.State.AssignUnit(u, state.AssignCleanEmpty) 317 c.Assert(err, jc.ErrorIsNil) 318 } 319 addUnit() 320 321 w := s.State.WatchModelFilesystems() 322 defer testing.AssertStop(c, w) 323 wc := testing.NewStringsWatcherC(c, s.State, w) 324 wc.AssertChangeInSingleEvent("0") // initial 325 wc.AssertNoChange() 326 327 addUnit() 328 wc.AssertChangeInSingleEvent("3") 329 wc.AssertNoChange() 330 331 // TODO(axw) respond to Dying/Dead when we have 332 // the means to progress Filesystem lifecycle. 333 } 334 335 func (s *FilesystemStateSuite) TestWatchEnvironFilesystemAttachments(c *gc.C) { 336 service := s.setupMixedScopeStorageService(c, "filesystem") 337 addUnit := func() { 338 u, err := service.AddUnit() 339 c.Assert(err, jc.ErrorIsNil) 340 err = s.State.AssignUnit(u, state.AssignCleanEmpty) 341 c.Assert(err, jc.ErrorIsNil) 342 } 343 addUnit() 344 345 w := s.State.WatchEnvironFilesystemAttachments() 346 defer testing.AssertStop(c, w) 347 wc := testing.NewStringsWatcherC(c, s.State, w) 348 wc.AssertChangeInSingleEvent("0:0") // initial 349 wc.AssertNoChange() 350 351 addUnit() 352 wc.AssertChangeInSingleEvent("1:3") 353 wc.AssertNoChange() 354 355 // TODO(axw) respond to Dying/Dead when we have 356 // the means to progress Volume lifecycle. 357 } 358 359 func (s *FilesystemStateSuite) TestWatchMachineFilesystems(c *gc.C) { 360 service := s.setupMixedScopeStorageService(c, "filesystem") 361 addUnit := func() { 362 u, err := service.AddUnit() 363 c.Assert(err, jc.ErrorIsNil) 364 err = s.State.AssignUnit(u, state.AssignCleanEmpty) 365 c.Assert(err, jc.ErrorIsNil) 366 } 367 addUnit() 368 369 w := s.State.WatchMachineFilesystems(names.NewMachineTag("0")) 370 defer testing.AssertStop(c, w) 371 wc := testing.NewStringsWatcherC(c, s.State, w) 372 wc.AssertChangeInSingleEvent("0/1", "0/2") // initial 373 wc.AssertNoChange() 374 375 addUnit() 376 // no change, since we're only interested in the one machine. 377 wc.AssertNoChange() 378 379 // TODO(axw) respond to Dying/Dead when we have 380 // the means to progress Filesystem lifecycle. 381 } 382 383 func (s *FilesystemStateSuite) TestWatchMachineFilesystemAttachments(c *gc.C) { 384 service := s.setupMixedScopeStorageService(c, "filesystem") 385 addUnit := func(to *state.Machine) (u *state.Unit, m *state.Machine) { 386 var err error 387 u, err = service.AddUnit() 388 c.Assert(err, jc.ErrorIsNil) 389 if to != nil { 390 err = u.AssignToMachine(to) 391 c.Assert(err, jc.ErrorIsNil) 392 return u, to 393 } 394 err = s.State.AssignUnit(u, state.AssignCleanEmpty) 395 c.Assert(err, jc.ErrorIsNil) 396 mid, err := u.AssignedMachineId() 397 c.Assert(err, jc.ErrorIsNil) 398 m, err = s.State.Machine(mid) 399 c.Assert(err, jc.ErrorIsNil) 400 return u, m 401 } 402 _, m0 := addUnit(nil) 403 404 w := s.State.WatchMachineFilesystemAttachments(names.NewMachineTag("0")) 405 defer testing.AssertStop(c, w) 406 wc := testing.NewStringsWatcherC(c, s.State, w) 407 wc.AssertChangeInSingleEvent("0:0/1", "0:0/2") // initial 408 wc.AssertNoChange() 409 410 addUnit(nil) 411 // no change, since we're only interested in the one machine. 412 wc.AssertNoChange() 413 414 err := s.State.DetachFilesystem(names.NewMachineTag("0"), names.NewFilesystemTag("0")) 415 c.Assert(err, jc.ErrorIsNil) 416 // no change, since we're only interested in attachments of 417 // machine-scoped volumes. 418 wc.AssertNoChange() 419 420 err = s.State.DetachFilesystem(names.NewMachineTag("0"), names.NewFilesystemTag("0/1")) 421 c.Assert(err, jc.ErrorIsNil) 422 wc.AssertChangeInSingleEvent("0:0/1") // dying 423 wc.AssertNoChange() 424 425 err = s.State.RemoveFilesystemAttachment(names.NewMachineTag("0"), names.NewFilesystemTag("0/1")) 426 c.Assert(err, jc.ErrorIsNil) 427 wc.AssertChangeInSingleEvent("0:0/1") // removed 428 wc.AssertNoChange() 429 430 addUnit(m0) 431 wc.AssertChangeInSingleEvent("0:0/7", "0:0/8") 432 wc.AssertNoChange() 433 } 434 435 func (s *FilesystemStateSuite) TestParseFilesystemAttachmentId(c *gc.C) { 436 assertValid := func(id string, m names.MachineTag, v names.FilesystemTag) { 437 machineTag, filesystemTag, err := state.ParseFilesystemAttachmentId(id) 438 c.Assert(err, jc.ErrorIsNil) 439 c.Assert(machineTag, gc.Equals, m) 440 c.Assert(filesystemTag, gc.Equals, v) 441 } 442 assertValid("0:0", names.NewMachineTag("0"), names.NewFilesystemTag("0")) 443 assertValid("0:0/1", names.NewMachineTag("0"), names.NewFilesystemTag("0/1")) 444 assertValid("0/lxd/0:1", names.NewMachineTag("0/lxd/0"), names.NewFilesystemTag("1")) 445 } 446 447 func (s *FilesystemStateSuite) TestParseFilesystemAttachmentIdError(c *gc.C) { 448 assertError := func(id, expect string) { 449 _, _, err := state.ParseFilesystemAttachmentId(id) 450 c.Assert(err, gc.ErrorMatches, expect) 451 } 452 assertError("", `invalid filesystem attachment ID ""`) 453 assertError("0", `invalid filesystem attachment ID "0"`) 454 assertError("0:foo", `invalid filesystem attachment ID "0:foo"`) 455 assertError("bar:0", `invalid filesystem attachment ID "bar:0"`) 456 } 457 458 func (s *FilesystemStateSuite) TestRemoveStorageInstanceUnassignsFilesystem(c *gc.C) { 459 filesystemAttachment, storageAttachment := s.addUnitWithFilesystem(c, "loop", true) 460 filesystem := s.filesystem(c, filesystemAttachment.Filesystem()) 461 volume := s.filesystemVolume(c, filesystemAttachment.Filesystem()) 462 storageTag := storageAttachment.StorageInstance() 463 unitTag := storageAttachment.Unit() 464 465 err := s.State.DestroyStorageInstance(storageTag) 466 c.Assert(err, jc.ErrorIsNil) 467 err = s.State.DestroyStorageAttachment(storageTag, unitTag) 468 c.Assert(err, jc.ErrorIsNil) 469 470 // The storage instance and attachment are dying, but not yet 471 // removed from state. The filesystem should still be assigned. 472 s.storageInstanceFilesystem(c, storageTag) 473 s.storageInstanceVolume(c, storageTag) 474 475 err = s.State.RemoveStorageAttachment(storageTag, unitTag) 476 c.Assert(err, jc.ErrorIsNil) 477 478 // The storage instance is now gone; the filesystem should no longer 479 // be assigned to the storage. 480 _, err = s.State.StorageInstanceFilesystem(storageTag) 481 c.Assert(err, gc.ErrorMatches, `filesystem for storage instance "data/0" not found`) 482 _, err = s.State.StorageInstanceVolume(storageTag) 483 c.Assert(err, gc.ErrorMatches, `volume for storage instance "data/0" not found`) 484 485 // The filesystem and volume should not have been destroyed, though. 486 s.filesystem(c, filesystem.FilesystemTag()) 487 s.volume(c, volume.VolumeTag()) 488 } 489 490 func (s *FilesystemStateSuite) TestSetFilesystemAttachmentInfoFilesystemNotProvisioned(c *gc.C) { 491 filesystemAttachment, _ := s.addUnitWithFilesystem(c, "rootfs", false) 492 err := s.State.SetFilesystemAttachmentInfo( 493 filesystemAttachment.Machine(), 494 filesystemAttachment.Filesystem(), 495 state.FilesystemAttachmentInfo{}, 496 ) 497 c.Assert(err, gc.ErrorMatches, `cannot set info for filesystem attachment 0/0:0: filesystem "0/0" not provisioned`) 498 } 499 500 func (s *FilesystemStateSuite) TestSetFilesystemAttachmentInfoMachineNotProvisioned(c *gc.C) { 501 filesystemAttachment, _ := s.addUnitWithFilesystem(c, "rootfs", false) 502 err := s.State.SetFilesystemInfo( 503 filesystemAttachment.Filesystem(), 504 state.FilesystemInfo{Size: 123, FilesystemId: "fs-id"}, 505 ) 506 c.Assert(err, jc.ErrorIsNil) 507 err = s.State.SetFilesystemAttachmentInfo( 508 filesystemAttachment.Machine(), 509 filesystemAttachment.Filesystem(), 510 state.FilesystemAttachmentInfo{}, 511 ) 512 c.Assert(err, gc.ErrorMatches, `cannot set info for filesystem attachment 0/0:0: machine 0 not provisioned`) 513 } 514 515 func (s *FilesystemStateSuite) TestSetFilesystemInfoVolumeAttachmentNotProvisioned(c *gc.C) { 516 filesystemAttachment, _ := s.addUnitWithFilesystem(c, "loop", true) 517 err := s.State.SetFilesystemInfo( 518 filesystemAttachment.Filesystem(), 519 state.FilesystemInfo{Size: 123, FilesystemId: "fs-id"}, 520 ) 521 c.Assert(err, gc.ErrorMatches, `cannot set info for filesystem "0/0": volume attachment "0/0" on "0" not provisioned`) 522 } 523 524 func (s *FilesystemStateSuite) TestDestroyFilesystem(c *gc.C) { 525 filesystem, _ := s.setupFilesystemAttachment(c, "rootfs") 526 assertDestroy := func() { 527 err := s.State.DestroyFilesystem(filesystem.FilesystemTag()) 528 c.Assert(err, jc.ErrorIsNil) 529 filesystem = s.filesystem(c, filesystem.FilesystemTag()) 530 c.Assert(filesystem.Life(), gc.Equals, state.Dying) 531 } 532 defer state.SetBeforeHooks(c, s.State, assertDestroy).Check() 533 assertDestroy() 534 } 535 536 func (s *FilesystemStateSuite) TestDestroyFilesystemNoAttachments(c *gc.C) { 537 filesystem, machine := s.setupFilesystemAttachment(c, "rootfs") 538 539 err := s.State.DetachFilesystem(machine.MachineTag(), filesystem.FilesystemTag()) 540 c.Assert(err, jc.ErrorIsNil) 541 542 defer state.SetBeforeHooks(c, s.State, func() { 543 err := s.State.RemoveFilesystemAttachment(machine.MachineTag(), filesystem.FilesystemTag()) 544 c.Assert(err, jc.ErrorIsNil) 545 assertMachineStorageRefs(c, s.State, machine.MachineTag()) 546 }).Check() 547 548 err = s.State.DestroyFilesystem(filesystem.FilesystemTag()) 549 c.Assert(err, jc.ErrorIsNil) 550 filesystem = s.filesystem(c, filesystem.FilesystemTag()) 551 552 // There are no more attachments, so the filesystem should 553 // have been progressed directly to Dead. 554 c.Assert(filesystem.Life(), gc.Equals, state.Dead) 555 } 556 557 func (s *FilesystemStateSuite) TestRemoveFilesystem(c *gc.C) { 558 filesystem, machine := s.setupFilesystemAttachment(c, "rootfs") 559 err := s.State.DestroyFilesystem(filesystem.FilesystemTag()) 560 c.Assert(err, jc.ErrorIsNil) 561 err = s.State.DetachFilesystem(machine.MachineTag(), filesystem.FilesystemTag()) 562 c.Assert(err, jc.ErrorIsNil) 563 err = s.State.RemoveFilesystemAttachment(machine.MachineTag(), filesystem.FilesystemTag()) 564 c.Assert(err, jc.ErrorIsNil) 565 assertRemove := func() { 566 err = s.State.RemoveFilesystem(filesystem.FilesystemTag()) 567 c.Assert(err, jc.ErrorIsNil) 568 _, err = s.State.Filesystem(filesystem.FilesystemTag()) 569 c.Assert(err, jc.Satisfies, errors.IsNotFound) 570 } 571 defer state.SetBeforeHooks(c, s.State, assertRemove).Check() 572 assertRemove() 573 } 574 575 func (s *FilesystemStateSuite) TestRemoveFilesystemVolumeBacked(c *gc.C) { 576 filesystem, machine := s.setupFilesystemAttachment(c, "loop") 577 volume := s.filesystemVolume(c, filesystem.FilesystemTag()) 578 assertVolumeLife := func(life state.Life) { 579 volume := s.volume(c, volume.VolumeTag()) 580 c.Assert(volume.Life(), gc.Equals, life) 581 } 582 assertVolumeAttachmentLife := func(life state.Life) { 583 attachment := s.volumeAttachment(c, machine.MachineTag(), volume.VolumeTag()) 584 c.Assert(attachment.Life(), gc.Equals, life) 585 } 586 587 err := s.State.DestroyFilesystem(filesystem.FilesystemTag()) 588 c.Assert(err, jc.ErrorIsNil) 589 // Destroying the filesystem does not trigger destruction 590 // of the volume. It cannot be destroyed until all remnants 591 // of the filesystem are gone. 592 assertVolumeLife(state.Alive) 593 594 err = s.State.DetachFilesystem(machine.MachineTag(), filesystem.FilesystemTag()) 595 c.Assert(err, jc.ErrorIsNil) 596 // Likewise for the volume attachment. 597 assertVolumeAttachmentLife(state.Alive) 598 599 err = s.State.RemoveFilesystemAttachment(machine.MachineTag(), filesystem.FilesystemTag()) 600 c.Assert(err, jc.ErrorIsNil) 601 // Removing the filesystem attachment causes the backing-volume 602 // to be detached. 603 assertVolumeAttachmentLife(state.Dying) 604 605 err = s.State.RemoveFilesystem(filesystem.FilesystemTag()) 606 c.Assert(err, jc.ErrorIsNil) 607 // Removing the filesystem causes the backing-volume to be 608 // destroyed. 609 assertVolumeLife(state.Dying) 610 611 assertMachineStorageRefs(c, s.State, machine.MachineTag()) 612 } 613 614 func (s *FilesystemStateSuite) TestFilesystemVolumeBackedDestroyDetachVolumeFail(c *gc.C) { 615 filesystem, machine := s.setupFilesystemAttachment(c, "loop") 616 volume := s.filesystemVolume(c, filesystem.FilesystemTag()) 617 618 err := s.State.DestroyFilesystem(filesystem.FilesystemTag()) 619 c.Assert(err, jc.ErrorIsNil) 620 err = s.State.DetachFilesystem(machine.MachineTag(), filesystem.FilesystemTag()) 621 c.Assert(err, jc.ErrorIsNil) 622 623 // Can't destroy (detach) volume until the filesystem (attachment) is removed. 624 err = s.State.DetachVolume(machine.MachineTag(), volume.VolumeTag()) 625 c.Assert(err, gc.ErrorMatches, "detaching volume 0/0 from machine 0: volume contains attached filesystem") 626 c.Assert(err, jc.Satisfies, state.IsContainsFilesystem) 627 err = s.State.DestroyVolume(volume.VolumeTag()) 628 c.Assert(err, gc.ErrorMatches, "destroying volume 0/0: volume contains filesystem") 629 c.Assert(err, jc.Satisfies, state.IsContainsFilesystem) 630 assertMachineStorageRefs(c, s.State, machine.MachineTag()) 631 632 err = s.State.RemoveFilesystemAttachment(machine.MachineTag(), filesystem.FilesystemTag()) 633 c.Assert(err, jc.ErrorIsNil) 634 err = s.State.RemoveFilesystem(filesystem.FilesystemTag()) 635 c.Assert(err, jc.ErrorIsNil) 636 637 err = s.State.DetachVolume(machine.MachineTag(), volume.VolumeTag()) 638 c.Assert(err, jc.ErrorIsNil) 639 err = s.State.DestroyVolume(volume.VolumeTag()) 640 c.Assert(err, jc.ErrorIsNil) 641 } 642 643 func (s *FilesystemStateSuite) TestRemoveFilesystemNotFound(c *gc.C) { 644 err := s.State.RemoveFilesystem(names.NewFilesystemTag("42")) 645 c.Assert(err, jc.ErrorIsNil) 646 } 647 648 func (s *FilesystemStateSuite) TestRemoveFilesystemNotDead(c *gc.C) { 649 filesystem, _ := s.setupFilesystemAttachment(c, "rootfs") 650 err := s.State.RemoveFilesystem(filesystem.FilesystemTag()) 651 c.Assert(err, gc.ErrorMatches, "removing filesystem 0/0: filesystem is not dead") 652 err = s.State.DestroyFilesystem(filesystem.FilesystemTag()) 653 c.Assert(err, jc.ErrorIsNil) 654 err = s.State.RemoveFilesystem(filesystem.FilesystemTag()) 655 c.Assert(err, gc.ErrorMatches, "removing filesystem 0/0: filesystem is not dead") 656 } 657 658 func (s *FilesystemStateSuite) TestDetachFilesystem(c *gc.C) { 659 filesystem, machine := s.setupFilesystemAttachment(c, "rootfs") 660 assertDetach := func() { 661 err := s.State.DetachFilesystem(machine.MachineTag(), filesystem.FilesystemTag()) 662 c.Assert(err, jc.ErrorIsNil) 663 attachment := s.filesystemAttachment(c, machine.MachineTag(), filesystem.FilesystemTag()) 664 c.Assert(attachment.Life(), gc.Equals, state.Dying) 665 } 666 defer state.SetBeforeHooks(c, s.State, assertDetach).Check() 667 assertDetach() 668 } 669 670 func (s *FilesystemStateSuite) TestRemoveLastFilesystemAttachment(c *gc.C) { 671 filesystem, machine := s.setupFilesystemAttachment(c, "rootfs") 672 673 err := s.State.DetachFilesystem(machine.MachineTag(), filesystem.FilesystemTag()) 674 c.Assert(err, jc.ErrorIsNil) 675 676 err = s.State.RemoveFilesystemAttachment(machine.MachineTag(), filesystem.FilesystemTag()) 677 c.Assert(err, jc.ErrorIsNil) 678 679 err = s.State.DestroyFilesystem(filesystem.FilesystemTag()) 680 c.Assert(err, jc.ErrorIsNil) 681 filesystem = s.filesystem(c, filesystem.FilesystemTag()) 682 // The filesystem had no attachments when it was destroyed, 683 // so it should be Dead. 684 c.Assert(filesystem.Life(), gc.Equals, state.Dead) 685 assertMachineStorageRefs(c, s.State, machine.MachineTag()) 686 } 687 688 func (s *FilesystemStateSuite) TestRemoveLastFilesystemAttachmentConcurrently(c *gc.C) { 689 filesystem, machine := s.setupFilesystemAttachment(c, "rootfs") 690 691 err := s.State.DetachFilesystem(machine.MachineTag(), filesystem.FilesystemTag()) 692 c.Assert(err, jc.ErrorIsNil) 693 694 defer state.SetBeforeHooks(c, s.State, func() { 695 err := s.State.DestroyFilesystem(filesystem.FilesystemTag()) 696 c.Assert(err, jc.ErrorIsNil) 697 filesystem := s.filesystem(c, filesystem.FilesystemTag()) 698 c.Assert(filesystem.Life(), gc.Equals, state.Dying) 699 }).Check() 700 701 err = s.State.RemoveFilesystemAttachment(machine.MachineTag(), filesystem.FilesystemTag()) 702 c.Assert(err, jc.ErrorIsNil) 703 704 // Last attachment was removed, and the filesystem was (concurrently) 705 // destroyed, so the filesystem should be Dead. 706 filesystem = s.filesystem(c, filesystem.FilesystemTag()) 707 c.Assert(filesystem.Life(), gc.Equals, state.Dead) 708 assertMachineStorageRefs(c, s.State, machine.MachineTag()) 709 } 710 711 func (s *FilesystemStateSuite) TestRemoveFilesystemAttachmentNotFound(c *gc.C) { 712 err := s.State.RemoveFilesystemAttachment(names.NewMachineTag("42"), names.NewFilesystemTag("42")) 713 c.Assert(err, jc.Satisfies, errors.IsNotFound) 714 c.Assert(err, gc.ErrorMatches, `removing attachment of filesystem 42 from machine 42: filesystem "42" on machine "42" not found`) 715 } 716 717 func (s *FilesystemStateSuite) TestRemoveFilesystemAttachmentConcurrently(c *gc.C) { 718 filesystem, machine := s.setupFilesystemAttachment(c, "rootfs") 719 err := s.State.DetachFilesystem(machine.MachineTag(), filesystem.FilesystemTag()) 720 c.Assert(err, jc.ErrorIsNil) 721 remove := func() { 722 err := s.State.RemoveFilesystemAttachment(machine.MachineTag(), filesystem.FilesystemTag()) 723 c.Assert(err, jc.ErrorIsNil) 724 assertMachineStorageRefs(c, s.State, machine.MachineTag()) 725 } 726 defer state.SetBeforeHooks(c, s.State, remove).Check() 727 remove() 728 } 729 730 func (s *FilesystemStateSuite) TestRemoveFilesystemAttachmentAlive(c *gc.C) { 731 filesystem, machine := s.setupFilesystemAttachment(c, "rootfs") 732 err := s.State.RemoveFilesystemAttachment(machine.MachineTag(), filesystem.FilesystemTag()) 733 c.Assert(err, gc.ErrorMatches, "removing attachment of filesystem 0/0 from machine 0: filesystem attachment is not dying") 734 } 735 736 func (s *FilesystemStateSuite) TestRemoveMachineRemovesFilesystems(c *gc.C) { 737 filesystem, machine := s.setupFilesystemAttachment(c, "rootfs") 738 739 c.Assert(machine.Destroy(), jc.ErrorIsNil) 740 c.Assert(machine.EnsureDead(), jc.ErrorIsNil) 741 c.Assert(machine.Remove(), jc.ErrorIsNil) 742 743 // Machine is gone: filesystem should be gone too. 744 _, err := s.State.Filesystem(filesystem.FilesystemTag()) 745 c.Assert(err, jc.Satisfies, errors.IsNotFound) 746 747 attachments, err := s.State.MachineFilesystemAttachments(machine.MachineTag()) 748 c.Assert(err, jc.ErrorIsNil) 749 c.Assert(attachments, gc.HasLen, 0) 750 } 751 752 func (s *FilesystemStateSuite) TestFilesystemBindingMachine(c *gc.C) { 753 // Filesystems created unassigned to a storage instance are 754 // bound to the initially attached machine. 755 filesystem, machine := s.setupFilesystemAttachment(c, "rootfs") 756 c.Assert(filesystem.LifeBinding(), gc.Equals, machine.Tag()) 757 758 err := s.State.DetachFilesystem(machine.MachineTag(), filesystem.FilesystemTag()) 759 c.Assert(err, jc.ErrorIsNil) 760 err = s.State.RemoveFilesystemAttachment(machine.MachineTag(), filesystem.FilesystemTag()) 761 c.Assert(err, jc.ErrorIsNil) 762 filesystem = s.filesystem(c, filesystem.FilesystemTag()) 763 c.Assert(filesystem.Life(), gc.Equals, state.Dead) 764 765 // TODO(axw) when we can assign storage to an existing filesystem, we 766 // should test that a machine-bound filesystem is not destroyed when 767 // its assigned storage instance is removed. 768 } 769 770 func (s *FilesystemStateSuite) TestFilesystemBindingStorage(c *gc.C) { 771 // Filesystems created assigned to a storage instance are bound 772 // to the storage instance. 773 _, u, storageTag := s.setupSingleStorage(c, "filesystem", "rootfs") 774 err := s.State.AssignUnit(u, state.AssignCleanEmpty) 775 c.Assert(err, jc.ErrorIsNil) 776 filesystem := s.storageInstanceFilesystem(c, storageTag) 777 c.Assert(filesystem.LifeBinding(), gc.Equals, storageTag) 778 779 err = s.State.DestroyStorageInstance(storageTag) 780 c.Assert(err, jc.ErrorIsNil) 781 attachments, err := s.State.StorageAttachments(storageTag) 782 c.Assert(err, jc.ErrorIsNil) 783 for _, a := range attachments { 784 err = s.State.DestroyStorageAttachment(storageTag, a.Unit()) 785 c.Assert(err, jc.ErrorIsNil) 786 err = s.State.RemoveStorageAttachment(storageTag, a.Unit()) 787 c.Assert(err, jc.ErrorIsNil) 788 } 789 790 // The storage instance should be removed, 791 // and the filesystem should be Dying. 792 _, err = s.State.StorageInstance(storageTag) 793 c.Assert(err, jc.Satisfies, errors.IsNotFound) 794 filesystem = s.filesystem(c, filesystem.FilesystemTag()) 795 c.Assert(filesystem.Life(), gc.Equals, state.Dying) 796 } 797 798 func (s *FilesystemStateSuite) TestFilesystemVolumeBinding(c *gc.C) { 799 // A volume backing a filesystem is bound to the filesystem. 800 filesystem, _ := s.setupFilesystemAttachment(c, "loop") 801 volume := s.filesystemVolume(c, filesystem.FilesystemTag()) 802 c.Assert(volume.LifeBinding(), gc.Equals, filesystem.Tag()) 803 804 // TestRemoveFilesystemVolumeBacked tests that removal of 805 // filesystem destroys volume. 806 } 807 808 func (s *FilesystemStateSuite) TestEnsureMachineDeadAddFilesystemConcurrently(c *gc.C) { 809 _, machine := s.setupFilesystemAttachment(c, "rootfs") 810 addFilesystem := func() { 811 _, u, _ := s.setupSingleStorage(c, "filesystem", "rootfs") 812 err := u.AssignToMachine(machine) 813 c.Assert(err, jc.ErrorIsNil) 814 s.obliterateUnit(c, u.UnitTag()) 815 } 816 defer state.SetBeforeHooks(c, s.State, addFilesystem).Check() 817 818 // Adding another filesystem to the machine will cause EnsureDead to 819 // retry, but it will succeed because both filesystems are inherently 820 // machine-bound. 821 err := machine.EnsureDead() 822 c.Assert(err, jc.ErrorIsNil) 823 } 824 825 func (s *FilesystemStateSuite) TestEnsureMachineDeadRemoveFilesystemConcurrently(c *gc.C) { 826 filesystem, machine := s.setupFilesystemAttachment(c, "rootfs") 827 removeFilesystem := func() { 828 s.obliterateFilesystem(c, filesystem.FilesystemTag()) 829 } 830 defer state.SetBeforeHooks(c, s.State, removeFilesystem).Check() 831 832 // Removing a filesystem concurrently does not cause a transaction failure. 833 err := machine.EnsureDead() 834 c.Assert(err, jc.ErrorIsNil) 835 } 836 837 func (s *FilesystemStateSuite) TestFilesystemAttachmentParamsSingletonNoLocation(c *gc.C) { 838 s.testFilesystemAttachmentParams(c, 0, 1, "", state.FilesystemAttachmentParams{ 839 Location: "/var/lib/juju/storage/data/0", 840 }) 841 } 842 843 func (s *FilesystemStateSuite) TestFilesystemAttachmentParamsMultipleNoLocation(c *gc.C) { 844 s.testFilesystemAttachmentParams(c, 0, -1, "", state.FilesystemAttachmentParams{ 845 Location: "/var/lib/juju/storage/data/0", 846 }) 847 } 848 849 func (s *FilesystemStateSuite) TestFilesystemAttachmentParamsSingletonLocation(c *gc.C) { 850 s.testFilesystemAttachmentParams(c, 0, 1, "/srv", state.FilesystemAttachmentParams{ 851 Location: "/srv", 852 }) 853 } 854 855 func (s *FilesystemStateSuite) TestFilesystemAttachmentParamsMultipleLocation(c *gc.C) { 856 s.testFilesystemAttachmentParams(c, 0, -1, "/srv", state.FilesystemAttachmentParams{ 857 Location: "/srv/data/0", 858 }) 859 } 860 861 func (s *FilesystemStateSuite) testFilesystemAttachmentParams( 862 c *gc.C, countMin, countMax int, location string, 863 expect state.FilesystemAttachmentParams, 864 ) { 865 ch := s.createStorageCharm(c, "storage-filesystem", charm.Storage{ 866 Name: "data", 867 Type: charm.StorageFilesystem, 868 CountMin: countMin, 869 CountMax: countMax, 870 Location: location, 871 }) 872 storage := map[string]state.StorageConstraints{ 873 "data": makeStorageCons("rootfs", 1024, 1), 874 } 875 876 service := s.AddTestingServiceWithStorage(c, "storage-filesystem", ch, storage) 877 unit, err := service.AddUnit() 878 c.Assert(err, jc.ErrorIsNil) 879 err = s.State.AssignUnit(unit, state.AssignCleanEmpty) 880 c.Assert(err, jc.ErrorIsNil) 881 machineId, err := unit.AssignedMachineId() 882 c.Assert(err, jc.ErrorIsNil) 883 884 storageTag := names.NewStorageTag("data/0") 885 filesystem := s.storageInstanceFilesystem(c, storageTag) 886 filesystemAttachment := s.filesystemAttachment( 887 c, names.NewMachineTag(machineId), filesystem.FilesystemTag(), 888 ) 889 params, ok := filesystemAttachment.Params() 890 c.Assert(ok, jc.IsTrue) 891 c.Assert(params, jc.DeepEquals, expect) 892 } 893 894 func (s *FilesystemStateSuite) TestFilesystemAttachmentParamsLocationConflictConcurrent(c *gc.C) { 895 s.testFilesystemAttachmentParamsConcurrent( 896 c, "/srv", "/srv", 897 `cannot assign unit "storage-filesystem-after/0" to machine 0: `+ 898 `validating filesystem mount points: `+ 899 `mount point "/srv" for "data" storage contains mount point "/srv" for "data" storage`) 900 } 901 902 func (s *FilesystemStateSuite) TestFilesystemAttachmentParamsLocationAutoConcurrent(c *gc.C) { 903 s.testFilesystemAttachmentParamsConcurrent(c, "", "", "") 904 } 905 906 func (s *FilesystemStateSuite) TestFilesystemAttachmentParamsLocationAutoAndManualConcurrent(c *gc.C) { 907 s.testFilesystemAttachmentParamsConcurrent(c, "", "/srv", "") 908 } 909 910 func (s *FilesystemStateSuite) testFilesystemAttachmentParamsConcurrent(c *gc.C, locBefore, locAfter, expectErr string) { 911 machine, err := s.State.AddMachine("quantal", state.JobHostUnits) 912 c.Assert(err, jc.ErrorIsNil) 913 914 storage := map[string]state.StorageConstraints{ 915 "data": makeStorageCons("rootfs", 1024, 1), 916 } 917 918 deploy := func(rev int, location, applicationname string) error { 919 ch := s.createStorageCharmRev(c, "storage-filesystem", charm.Storage{ 920 Name: "data", 921 Type: charm.StorageFilesystem, 922 CountMin: 1, 923 CountMax: 1, 924 Location: location, 925 }, rev) 926 service := s.AddTestingServiceWithStorage(c, applicationname, ch, storage) 927 unit, err := service.AddUnit() 928 c.Assert(err, jc.ErrorIsNil) 929 return unit.AssignToMachine(machine) 930 } 931 932 defer state.SetBeforeHooks(c, s.State, func() { 933 err := deploy(1, locBefore, "storage-filesystem-before") 934 c.Assert(err, jc.ErrorIsNil) 935 }).Check() 936 937 err = deploy(2, locAfter, "storage-filesystem-after") 938 if expectErr != "" { 939 c.Assert(err, gc.ErrorMatches, expectErr) 940 } else { 941 c.Assert(err, jc.ErrorIsNil) 942 } 943 } 944 945 func (s *FilesystemStateSuite) TestFilesystemAttachmentParamsConcurrentRemove(c *gc.C) { 946 // this creates a filesystem mounted at "/srv". 947 filesystem, machine := s.setupFilesystemAttachment(c, "rootfs") 948 949 ch := s.createStorageCharm(c, "storage-filesystem", charm.Storage{ 950 Name: "data", 951 Type: charm.StorageFilesystem, 952 CountMin: 1, 953 CountMax: 1, 954 Location: "/not/in/srv", 955 }) 956 service := s.AddTestingService(c, "storage-filesystem", ch) 957 unit, err := service.AddUnit() 958 c.Assert(err, jc.ErrorIsNil) 959 960 defer state.SetBeforeHooks(c, s.State, func() { 961 err := s.State.DetachFilesystem(machine.MachineTag(), filesystem.FilesystemTag()) 962 c.Assert(err, jc.ErrorIsNil) 963 err = s.State.RemoveFilesystemAttachment( 964 machine.MachineTag(), filesystem.FilesystemTag(), 965 ) 966 c.Assert(err, jc.ErrorIsNil) 967 }).Check() 968 969 err = unit.AssignToMachine(machine) 970 c.Assert(err, jc.ErrorIsNil) 971 } 972 973 func (s *FilesystemStateSuite) TestFilesystemAttachmentParamsLocationStorageDir(c *gc.C) { 974 ch := s.createStorageCharm(c, "storage-filesystem", charm.Storage{ 975 Name: "data", 976 Type: charm.StorageFilesystem, 977 CountMin: 1, 978 CountMax: 1, 979 Location: "/var/lib/juju/storage", 980 }) 981 service := s.AddTestingService(c, "storage-filesystem", ch) 982 unit, err := service.AddUnit() 983 c.Assert(err, jc.ErrorIsNil) 984 err = s.State.AssignUnit(unit, state.AssignCleanEmpty) 985 c.Assert(err, gc.ErrorMatches, `cannot assign unit \"storage-filesystem/0\" to machine: `+ 986 `cannot assign unit "storage-filesystem/0" to clean, empty machine: `+ 987 `getting filesystem mount point for storage data: `+ 988 `invalid location "/var/lib/juju/storage": `+ 989 `must not fall within "/var/lib/juju/storage"`) 990 } 991 992 func (s *FilesystemStateSuite) TestFilesystemAttachmentLocationConflict(c *gc.C) { 993 // this creates a filesystem mounted at "/srv". 994 _, machine := s.setupFilesystemAttachment(c, "rootfs") 995 996 ch := s.createStorageCharm(c, "storage-filesystem", charm.Storage{ 997 Name: "data", 998 Type: charm.StorageFilesystem, 999 CountMin: 1, 1000 CountMax: 1, 1001 Location: "/srv/within", 1002 }) 1003 svc := s.AddTestingService(c, "storage-filesystem", ch) 1004 1005 u, err := svc.AddUnit() 1006 c.Assert(err, jc.ErrorIsNil) 1007 err = u.AssignToMachine(machine) 1008 c.Assert(err, gc.ErrorMatches, 1009 `cannot assign unit "storage-filesystem/0" to machine 0: `+ 1010 `validating filesystem mount points: `+ 1011 `mount point "/srv" for filesystem 0/0 contains `+ 1012 `mount point "/srv/within" for "data" storage`) 1013 } 1014 1015 func (s *FilesystemStateSuite) setupFilesystemAttachment(c *gc.C, pool string) (state.Filesystem, *state.Machine) { 1016 machine, err := s.State.AddOneMachine(state.MachineTemplate{ 1017 Series: "quantal", 1018 Jobs: []state.MachineJob{state.JobHostUnits}, 1019 Filesystems: []state.MachineFilesystemParams{{ 1020 Filesystem: state.FilesystemParams{Pool: pool, Size: 1024}, 1021 Attachment: state.FilesystemAttachmentParams{ 1022 Location: "/srv", 1023 }, 1024 }}, 1025 }) 1026 c.Assert(err, jc.ErrorIsNil) 1027 attachments, err := s.State.MachineFilesystemAttachments(machine.MachineTag()) 1028 c.Assert(err, jc.ErrorIsNil) 1029 c.Assert(attachments, gc.HasLen, 1) 1030 c.Assert(err, jc.ErrorIsNil) 1031 assertMachineStorageRefs(c, s.State, machine.MachineTag()) 1032 return s.filesystem(c, attachments[0].Filesystem()), machine 1033 }