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