Description:
Add safety belt to destroy-environment
Destroy-environment is dangerous and we should prevent people from
shooting themselves in the foot if at all possible. This change removes
the -y flag from destroy-environment and changes the "are you sure?"
prompt to force the user to type "destroy <environment_name>". The flag
is too easy to pass without ththinking, and the y at the prompt is
similarly too easy to type in without the user actually thinking about
what they're doing. Forcing them to type the environment name will also
ensure they don't accidentally destroy the wrong environment by
accident.
-const destroyEnvMsg = `
-WARNING: this command will destroy the %q environment (type: %s)
+var destroyEnvMsg = `
+WARNING! This command will destroy the %q environment (type: %s)
This includes all machines, services, data and other resources.
-Continue [y/N]? `
+Type "destroy %s" to continue: `[1:]
Reviewers: mp+191501_ code.launchpad. net,
Message:
Please take a look.
Description:
Add safety belt to destroy-environment
Destroy-environment is dangerous and we should prevent people from name>". The flag
shooting themselves in the foot if at all possible. This change removes
the -y flag from destroy-environment and changes the "are you sure?"
prompt to force the user to type "destroy <environment_
is too easy to pass without ththinking, and the y at the prompt is
similarly too easy to type in without the user actually thinking about
what they're doing. Forcing them to type the environment name will also
ensure they don't accidentally destroy the wrong environment by
accident.
https:/ /code.launchpad .net/~natefinch /juju-core/ 022-destroyer/ +merge/ 191501
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/14502070/
Affected files (+33, -44 lines): cmd_test. go destroyenvironm ent.go
A [revision details]
M cmd/juju/
M cmd/juju/
Index: [revision details] 20131016154732- 13eh4uj8dhsfc1m w
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision: tarmac-
+New revision: <email address hidden>
Index: cmd/juju/ cmd_test. go cmd_test. go' cmd_test. go 2013-10-10 23:17:43 +0000 cmd_test. go 2013-10-16 20:26:42 +0000
=== modified file 'cmd/juju/
--- cmd/juju/
+++ cmd/juju/
@@ -160,6 +160,10 @@
}
func (*CmdSuite) TestDestroyEnvi ronmentCommand( c *gc.C) { ext() Default( )
+ var stdin bytes.Buffer
+ ctx := cmd.DefaultCont
+ ctx.Stdin = &stdin
+
// Prepare the environment so we can destroy it.
store, err := configstore.
c.Assert(err, gc.IsNil)
@@ -171,7 +175,8 @@
c.Assert(err, gc.IsNil)
// normal destroy nullContext( ), ronmentCommand) , "--yes") ng("destroy peckham") ronmentCommand) ) (<-opc) .(dummy. OpDestroy) .Env, gc.Equals, "peckham")
- opc, errc := runCommand(
new(DestroyEnvi
+ stdin.WriteStri
+ opc, errc := runCommand(ctx, new(DestroyEnvi
c.Check(<-errc, gc.IsNil)
c.Check(
@@ -183,26 +188,13 @@
c.Assert(err, gc.IsNil)
// destroy with broken environment nullContext( ), ronmentCommand) , "--yes", "-e", "brokenenv") ng("destroy brokenenv") ronmentCommand) , "-e", "brokenenv")
- opc, errc = runCommand(
new(DestroyEnvi
+ stdin.WriteStri
+ opc, errc = runCommand(ctx,
new(DestroyEnvi
c.Check(<-opc, gc.IsNil)
c.Check(<-errc, gc.ErrorMatches, "dummy.Destroy is broken")
c.Check(<-opc, gc.IsNil)
}
-func (*CmdSuite) TestDestroyEnvi ronmentCommandC onfirmationFlag (c *gc.C) { ronmentCommand) coretesting. InitCommand( com, nil), gc.IsNil) com.assumeYes, gc.Equals, false) ronmentCommand) coretesting. InitCommand( com, []string{"-y"}), gc.IsNil) com.assumeYes, gc.Equals, true) ronmentCommand) coretesting. InitCommand( com, []string{"--yes"}), gc.IsNil) com.assumeYes, gc.Equals, true) ronmentCommandC onfirmation( c *gc.C) { ext()
- com := new(DestroyEnvi
- c.Check(
- c.Check(
-
- com = new(DestroyEnvi
- c.Check(
- c.Check(
-
- com = new(DestroyEnvi
- c.Check(
- c.Check(
-}
-
func (*CmdSuite) TestDestroyEnvi
var stdin, stdout bytes.Buffer
ctx := cmd.DefaultCont
@@ -217,12 +209,12 @@
assertEnviro nNotDestroyed( c, env, store)
- // Ensure confirmation is requested if "-y" is not specified. WriteString( "n") ronmentCommand) ) stdout. String( ), gc.Matches, "WARNING: .*peckham. *\\(type: stdout. String( ), gc.Matches, "WARNING! .*peckham. *\\(type: nNotDestroyed( c, env, store)
+ // Ensure confirmation is requested
stdin.
opc, errc := runCommand(ctx, new(DestroyEnvi
c.Check(<-errc, gc.ErrorMatches, "Environment destruction aborted")
c.Check(<-opc, gc.IsNil)
- c.Check(
dummy\\)(.|\n)*")
+ c.Check(
dummy\\)(.|\n)*")
assertEnviro
// EOF on stdin: equivalent to answering no. nNotDestroyed( c, env, store)
@@ -233,17 +225,8 @@
c.Check(<-errc, gc.ErrorMatches, "Environment destruction aborted")
assertEnviro
- // "--yes" passed: no confirmation request. ronmentCommand) , "--yes") (<-opc) .(dummy. OpDestroy) .Env, gc.Equals, "peckham") stdout. String( ), gc.Equals, "") stroyed( c, env, store) PrepareFromName ("", store) ronmentCommand) ) (<-opc) .(dummy. OpDestroy) .Env, gc.Equals, "peckham") stdout. String( ), gc.Matches, "WARNING: .*peckham. *\\(type: stdout. String( ), gc.Matches, "WARNING! .*peckham. *\\(type: onDestroyed( c, env, store)
- stdin.Reset()
- stdout.Reset()
- opc, errc = runCommand(ctx, new(DestroyEnvi
- c.Check(<-errc, gc.IsNil)
- c.Check(
- c.Check(
- assertEnvironDe
-
- // Any of casing of "y" and "yes" will confirm.
- for _, answer := range []string{"y", "Y", "yes", "YES"} {
+ // "destroy <envname>" will confirm
+ for _, answer := range []string{"destroy peckham", "DESTROY PECKHAM"} {
// Prepare the environment so we can destroy it.
_, err := environs.
c.Assert(err, gc.IsNil)
@@ -254,7 +237,7 @@
opc, errc = runCommand(ctx, new(DestroyEnvi
c.Check(<-errc, gc.IsNil)
c.Check(
- c.Check(
dummy\\)(.|\n)*")
+ c.Check(
dummy\\)(.|\n)*")
assertEnvir
}
}
Index: cmd/juju/ destroyenvironm ent.go destroyenvironm ent.go' destroyenvironm ent.go 2013-10-02 10:34:22 +0000 destroyenvironm ent.go 2013-10-16 20:26:42 +0000
=== modified file 'cmd/juju/
--- cmd/juju/
+++ cmd/juju/
@@ -4,8 +4,10 @@
package main
import (
+ "bufio"
"errors"
"fmt"
+ "io"
"strings"
"launchpad. net/gnuflag" entCommand destroys an environment. entCommand struct { EnvCommandBase
@@ -18,7 +20,6 @@
// DestroyEnvironm
type DestroyEnvironm
cmd.
- assumeYes bool
}
func (c *DestroyEnviron mentCommand) Info() *cmd.Info {
@@ -30,8 +31,6 @@
func (c *DestroyEnviron mentCommand) SetFlags(f *gnuflag.FlagSet) { Base.SetFlags( f) &c.assumeYes, "y", false, "Do not ask for confirmation") &c.assumeYes, "yes", false, "")
c.EnvCommand
- f.BoolVar(
- f.BoolVar(
}
func (c *DestroyEnviron mentCommand) Run(ctx *cmd.Context) error { ctx.Stdout, destroyEnvMsg[1:], environ.Name(), Config( ).Type( )) ctx.Stdin, &answer) // ignore error, treat as "n" ToLower( answer) New("Environmen t destruction aborted") ctx.Stdout, destroyEnvMsg, environ.Name(), Config( ).Type( ), environ.Name()) r(ctx.Stdin) "Environment destruction aborted. Error reading ToLower( scanner. Text()) ToLower( "destroy "+environ.Name()) { New("Environmen t destruction aborted")
@@ -43,14 +42,19 @@
if err != nil {
return err
}
- if !c.assumeYes {
- var answer string
- fmt.Fprintf(
environ.
- fmt.Fscanln(
- answer = strings.
- if answer != "y" && answer != "yes" {
- return errors.
- }
+
+ fmt.Fprintf(
environ.
+
+ scanner := bufio.NewScanne
+ scanner.Scan()
+ err = scanner.Err()
+ if err != nil && err != io.EOF {
+ return fmt.Errorf(
input: %s", scanner.Err())
+ }
+
+ answer := strings.
+ if answer != strings.
+ return errors.
}
// TODO(axw) 2013-08-30 bug 1218688 Destroy( environ, store)
@@ -60,8 +64,8 @@
return environs.
}
-const destroyEnvMsg = `
-WARNING: this command will destroy the %q environment (type: %s)
+var destroyEnvMsg = `
+WARNING! This command will destroy the %q environment (type: %s)
This includes all machines, services, data and other resources.
-Continue [y/N]? `
+Type "destroy %s" to continue: `[1:]