state: check constraints when destroying storage #7096

Merged
merged 3 commits into from Mar 16, 2017

Conversation

Projects
None yet
3 participants
Member

axw commented Mar 14, 2017

Description of change

When detaching or destroying storage, ensure that
doing so does not violate the minimum storage
requirements of the owner (unit or application).
The minimum storage requirements are ignored when
the owner is dying, to allow storage to be cleanly
detached during unit destruction.

Also: rename DestroyStorageAttachment to
DetachStorage, to better match what we have with
volumes and filesystems. An AttachStorage method
will be added in a future PR.

QA steps

  1. export JUJU_DEV_FEATURE_FLAGS=lxd-storage
  2. juju bootstrap localhost
  3. juju deploy /path/to/storagetest --storage fs=lxd # [0]
    (wait for unit to become idle)
  4. juju remove-storage fs/0
    (should fail, saying that the storage is singular)
  5. juju detach-storage fs/0
    (should fail, saying that the storage is singular)
  6. juju destroy-controller -y localhost --destroy-all-models

[0] The storagetest charm's metadata.yaml is as follows:

name: storagetest
summary: ...
maintainer: Andrew Wilkins <andrew.wilkins@canonical.com>
description: ...
series: [xenial]
storage:
  fs:
    type: filesystem

Documentation changes

None.

Bug reference

None.

state: s/DestroyStorageAttachment/DetachStorage/
To match what we have for volumes and filesystems.

A few quibbles, nothing major

state/filesystem_test.go
@@ -554,6 +559,8 @@ func (s *FilesystemStateSuite) TestDestroyFilesystemStorageAssigned(c *gc.C) {
err = s.State.DestroyFilesystem(filesystem.FilesystemTag())
c.Assert(err, gc.ErrorMatches, "destroying filesystem 0/0: filesystem is assigned to storage data/0")
+ err = u.Destroy()
@wallyworld

wallyworld Mar 14, 2017

Owner

could we add the "we must destroy the unit...." message here too?

@axw

axw Mar 14, 2017

Member

done

state/storage.go
+ // machine, since the only other option is to destroy
+ // them. The user can remove them explicitly, or else
+ // leave them to be removed along with the machine.
+ return nil, nil
@wallyworld

wallyworld Mar 14, 2017

Owner

For these nil, nil cases, perhaps a debug line would be useful

@axw

axw Mar 14, 2017

Member

done

+
+ count := uint64(current + n)
+ if charmStorage.CountMin == 1 && charmStorage.CountMax == 1 && count != 1 {
+ return errors.Errorf("cannot %s, storage is singular", action)
@wallyworld

wallyworld Mar 14, 2017

Owner

For most users, not sure if "singular" is better than "there can be at most 1" type thing. It's certainly more concise. Let's make sure we get user feedback on the wording

@axw

axw Mar 14, 2017

Member

yeah, it's a bit clunky. I'll leave it for now, may have another go at it in a follow-up -- otherwise based on feedback

state/unit.go
@@ -1150,6 +1150,31 @@ func (u *Unit) SetCharmURL(curl *charm.URL) error {
return err
}
+// charm returns the charm for the unit, and txn.Ops to ensure that
+// it does not change.
+func (u *Unit) charm() (*Charm, []txn.Op, error) {
@wallyworld

wallyworld Mar 14, 2017

Owner

Would this be better named "assertCharmOps"?
Or "ensureCharmOps" or something.

But then I look at the usage and half the time we just use the charm and ignore the ops. So the above rename is a bit off. It's convenient to combine the 2 operations in one method, but seems a little muddy. Maybe we should just have 2 methods? One for ops and one for charm? Then the 2 places that need the ops can just make an extra call at that point.

@axw

axw Mar 14, 2017

Member

I've split it so we have:

func (*Unit) charm() (*Charm, error) {...}
func (*Unit) assertCharmOps(ch *Charm) []txn.Ops {...}
state/volume_test.go
wc.AssertNoChange()
}
func (s *VolumeStateSuite) TestWatchMachineVolumeAttachments(c *gc.C) {
- service := s.setupMixedScopeStorageService(c, "block")
+ service := s.setupMixedScopeStorageService(
@wallyworld

wallyworld Mar 14, 2017

Owner

drive by change to application?

@axw

axw Mar 14, 2017

Member

done

state: check constraints when destroying storage
When detaching or destroying storage, ensure that
doing so does not violate the minimum storage
requirements of the owner (unit or application).
The minimum storage requirements are ignored when
the owner is dying, to allow storage to be cleanly
detached during unit destruction.
Member

axw commented Mar 14, 2017

$$merge$$

Contributor

jujubot commented Mar 14, 2017

Status: merge request accepted. Url: http://juju-ci.vapour.ws:8080/job/github-merge-juju

Contributor

jujubot commented Mar 14, 2017

Build failed: Tests failed
build url: http://juju-ci.vapour.ws:8080/job/github-merge-juju/10455

Contributor

jujubot commented Mar 16, 2017

Status: merge request accepted. Url: http://juju-ci.vapour.ws:8080/job/github-merge-juju

Member

axw commented Mar 16, 2017

Build failed: cancele

Member

axw commented Mar 16, 2017

$$merge$$

Contributor

jujubot commented Mar 16, 2017

Status: merge request accepted. Url: http://juju-ci.vapour.ws:8080/job/github-merge-juju

Contributor

jujubot commented Mar 16, 2017

Build failed: Tests failed
build url: http://juju-ci.vapour.ws:8080/job/github-merge-juju/10470

Member

axw commented Mar 16, 2017

$$merge$$

Contributor

jujubot commented Mar 16, 2017

Status: merge request accepted. Url: http://juju-ci.vapour.ws:8080/job/github-merge-juju

@jujubot jujubot merged commit b346d83 into juju:develop Mar 16, 2017

1 check failed

github-check-merge-juju Built PR, ran unit tests, and tested LXD deploy. Use !!.*!! to request another build. IE, !!build!!, !!retry!!
Details
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment