juju destroy-model blocks #6405

Merged
merged 1 commit into from Oct 10, 2016

Conversation

Projects
None yet
4 participants
Owner

wallyworld commented Oct 7, 2016

Fixes: https://bugs.launchpad.net/juju/+bug/1611111

juju destroy-model will block until the model is completely cleaned up.
As soon as the command returns, add-model can be called again with the same model name.

QA:
$ juju add-model amodel
Added 'amodel' model on lxd/localhost with credential 'default' for user 'admin'
$ juju destroy-model amodel -y
Destroying model
Waititng on model to be removed, 1 machine(s), 1 application(s)...
Waititng on model to be removed, 1 machine(s), 1 application(s)...
Waititng on model to be removed, 1 machine(s), 1 application(s)...
Waititng on model to be removed, 1 machine(s), 1 application(s)...
Waititng on model to be removed, 1 machine(s)...
Waititng on model to be removed, 1 machine(s)...
Waititng on model to be removed, 1 machine(s)...
Waititng on model to be removed, 1 machine(s)...
Waititng on model to be removed, 1 machine(s)...
Waititng on model to be removed...
Waititng on model to be removed...
Waititng on model to be removed...
$ juju add-model amodel
Added 'amodel' model on lxd/localhost with credential 'default' for user 'admin'
$

Mostly LGTM, but would really like if we could improve the output.

cmd/juju/model/destroy.go
+ modelFound := newTimedModelFound(ctx, api, names.NewModelTag(modelDetails.ModelUUID), c.clock)
+ found := modelFound(0)
+ for found {
+ ctx.Infof("Waiting for model to be removed...")
@axw

axw Oct 7, 2016

Member

Can you please make this do the same thing as destroy-controller? i.e. like

"Waiting on %d machines, %d applications"

The output is not very useful as it is.

@wallyworld

wallyworld Oct 7, 2016

Owner

reworked output

cmd/juju/model/destroy.go
+ found := modelFound(0)
+ for found {
+ ctx.Infof("Waiting for model to be removed...")
+ found = modelFound(2 * time.Second)
@axw

axw Oct 7, 2016

Member

create a constant?

cmd/juju/model/destroy.go
+func newTimedModelFound(ctx *cmd.Context, api DestroyModelAPI, tag names.ModelTag, clock clock.Clock) func(time.Duration) bool {
+ return func(wait time.Duration) bool {
+ if wait > 0 {
+ <-clock.After(wait)
@axw

axw Oct 7, 2016

Member

time.Sleep(wait)

EDIT: I guess you're doing this so you can use a mock clock. Perhaps just have a mock "sleep" function, rather than a whole clock.

cmd/juju/model/destroy.go
+ if res[0].Error == nil {
+ return true
+ }
+ return params.ErrCode(res[0].Error) != params.CodeUnauthorized
@axw

axw Oct 7, 2016

Member

the intent would be a bit clearer if you used params.IsCodeNotFoundOrCodeUnauthorized

@wallyworld

wallyworld Oct 7, 2016

Owner

used different api

axw approved these changes Oct 7, 2016

LGTM with the Controller.ModelStatus permission changes as discussed.

cmd/juju/model/destroy.go
@@ -156,19 +181,78 @@ func (c *destroyCommand) Run(ctx *cmd.Context) error {
}
defer api.Close()
+ // Attempt to connect to the controller API. If we can't, fail the destroy.
+ controllerAPI, err := c.getControllerAPI()
@axw

axw Oct 7, 2016

Member

This will make a second API connection, which isn't great. It would be better to create a single, composite API from the two facades that we need.

@wallyworld

wallyworld Oct 9, 2016

Owner

We get a second API in several other CLI commands (sometimes even 3). How strongly do you feel about this?

@axw

axw Oct 9, 2016

Member

Not strong enough to block this PR, but other CLI commands being crappy isn't a good argument to make another one crappy. It can be fixed later.

@wallyworld

wallyworld Oct 10, 2016

Owner

Ok, I've added a common.ModelStatus API which is embedded in the Controller and ModelManager facades

+ sleepFunc(wait)
+ status, err := api.ModelStatus(tag)
+ if err != nil {
+ if params.ErrCode(err) != params.CodeNotFound {
@axw

axw Oct 7, 2016

Member

you may need to change this to cater for CodeUnauthorized when you change Controller.ModelStatus permission handling? also in existing destroy/kill-controller usage

@wallyworld

wallyworld Oct 9, 2016

Owner

This is ok as is I think - if there would be a permission issue here, then the previous call to Destroy() would fail and we'd never get to this point.

@axw

axw Oct 9, 2016

Member

I was thinking more that ErrPerm might be returned once the model is removed. Presumably you tested it, and it would have shown up if it was a problem.

@wallyworld

wallyworld Oct 9, 2016

Owner

Yeah, this ModelStatus api call returns not found if the model is not there. I did test it and that's how it behaved. I'll double check to be sure.

cmd/juju/model/destroy.go
+}
+
+func formatDestroyModelInfo(data *modelData) string {
+ out := "Waititng on model to be removed"
cmd/juju/model/destroy_test.go
@@ -60,15 +74,18 @@ func (s *DestroySuite) SetUpTest(c *gc.C) {
s.store.Accounts["test1"] = jujuclient.AccountDetails{
User: "admin",
}
+ s.sleep = func(time.Duration) {
+ time.Sleep(1 * time.Millisecond)
@axw

axw Oct 7, 2016

Member

do we really need to sleep at all?

@wallyworld

wallyworld Oct 9, 2016

Owner

guess not

Owner

mitechie commented Oct 7, 2016

ty @wallyworld !!!

apiserver/controller/controller.go
- if err := c.checkHasAdmin(); err != nil {
- return results, errors.Trace(err)
- }
+ //if err := c.checkHasAdmin(); err != nil {
Owner

wallyworld commented Oct 10, 2016

$$merge$$

Contributor

jujubot commented Oct 10, 2016

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

@jujubot jujubot merged commit 9e62160 into juju:master Oct 10, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment