github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/juju/controller/kill_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package controller_test 5 6 import ( 7 "bytes" 8 "time" 9 10 "github.com/juju/cmd" 11 "github.com/juju/errors" 12 "github.com/juju/names" 13 jc "github.com/juju/testing/checkers" 14 "github.com/juju/utils/clock" 15 gc "gopkg.in/check.v1" 16 17 "github.com/juju/juju/api" 18 "github.com/juju/juju/api/base" 19 "github.com/juju/juju/apiserver/common" 20 "github.com/juju/juju/apiserver/params" 21 "github.com/juju/juju/cmd/juju/controller" 22 "github.com/juju/juju/cmd/modelcmd" 23 cmdtesting "github.com/juju/juju/cmd/testing" 24 "github.com/juju/juju/jujuclient" 25 _ "github.com/juju/juju/provider/dummy" 26 "github.com/juju/juju/testing" 27 ) 28 29 type KillSuite struct { 30 baseDestroySuite 31 } 32 33 var _ = gc.Suite(&KillSuite{}) 34 35 func (s *KillSuite) runKillCommand(c *gc.C, args ...string) (*cmd.Context, error) { 36 return testing.RunCommand(c, s.newKillCommand(), args...) 37 } 38 39 func (s *KillSuite) newKillCommand() cmd.Command { 40 return controller.NewKillCommandForTest( 41 s.api, s.clientapi, s.store, s.apierror, &mockClock{}, nil) 42 } 43 44 func (s *KillSuite) TestKillNoControllerNameError(c *gc.C) { 45 _, err := s.runKillCommand(c) 46 c.Assert(err, gc.ErrorMatches, "no controller specified") 47 } 48 49 func (s *KillSuite) TestKillBadFlags(c *gc.C) { 50 _, err := s.runKillCommand(c, "-n") 51 c.Assert(err, gc.ErrorMatches, "flag provided but not defined: -n") 52 } 53 54 func (s *KillSuite) TestKillUnknownArgument(c *gc.C) { 55 _, err := s.runKillCommand(c, "model", "whoops") 56 c.Assert(err, gc.ErrorMatches, `unrecognized args: \["whoops"\]`) 57 } 58 59 func (s *KillSuite) TestKillUnknownController(c *gc.C) { 60 _, err := s.runKillCommand(c, "foo") 61 c.Assert(err, gc.ErrorMatches, `controller foo not found`) 62 } 63 64 func (s *KillSuite) TestKillCannotConnectToAPISucceeds(c *gc.C) { 65 s.apierror = errors.New("connection refused") 66 ctx, err := s.runKillCommand(c, "local.test1", "-y") 67 c.Assert(err, jc.ErrorIsNil) 68 c.Check(testing.Stderr(ctx), jc.Contains, "Unable to open API: connection refused") 69 checkControllerRemovedFromStore(c, "local.test1", s.store) 70 } 71 72 func (s *KillSuite) TestKillWithAPIConnection(c *gc.C) { 73 _, err := s.runKillCommand(c, "local.test1", "-y") 74 c.Assert(err, jc.ErrorIsNil) 75 c.Assert(s.api.destroyAll, jc.IsTrue) 76 c.Assert(s.clientapi.destroycalled, jc.IsFalse) 77 checkControllerRemovedFromStore(c, "local.test1", s.store) 78 } 79 80 func (s *KillSuite) TestKillEnvironmentGetFailsWithoutAPIConnection(c *gc.C) { 81 s.apierror = errors.New("connection refused") 82 s.api.SetErrors(errors.NotFoundf(`controller "test3"`)) 83 _, err := s.runKillCommand(c, "test3", "-y") 84 c.Assert(err, gc.ErrorMatches, 85 "getting controller environ: unable to get bootstrap information from client store or API", 86 ) 87 checkControllerExistsInStore(c, "test3", s.store) 88 } 89 90 func (s *KillSuite) TestKillEnvironmentGetFailsWithAPIConnection(c *gc.C) { 91 s.api.SetErrors(errors.NotFoundf(`controller "test3"`)) 92 _, err := s.runKillCommand(c, "test3", "-y") 93 c.Assert(err, gc.ErrorMatches, 94 "getting controller environ: getting bootstrap config from API: controller \"test3\" not found", 95 ) 96 checkControllerExistsInStore(c, "test3", s.store) 97 } 98 99 func (s *KillSuite) TestKillDestroysControllerWithAPIError(c *gc.C) { 100 s.api.SetErrors(errors.New("some destroy error")) 101 ctx, err := s.runKillCommand(c, "local.test1", "-y") 102 c.Assert(err, jc.ErrorIsNil) 103 c.Check(testing.Stderr(ctx), jc.Contains, "Unable to destroy controller through the API: some destroy error. Destroying through provider.") 104 c.Assert(s.api.destroyAll, jc.IsTrue) 105 checkControllerRemovedFromStore(c, "local.test1", s.store) 106 } 107 108 func (s *KillSuite) TestKillCommandConfirmation(c *gc.C) { 109 var stdin, stdout bytes.Buffer 110 ctx, err := cmd.DefaultContext() 111 c.Assert(err, jc.ErrorIsNil) 112 ctx.Stdout = &stdout 113 ctx.Stdin = &stdin 114 115 // Ensure confirmation is requested if "-y" is not specified. 116 stdin.WriteString("n") 117 _, errc := cmdtesting.RunCommand(ctx, s.newKillCommand(), "local.test1") 118 select { 119 case err := <-errc: 120 c.Check(err, gc.ErrorMatches, "controller destruction aborted") 121 case <-time.After(testing.LongWait): 122 c.Fatalf("command took too long") 123 } 124 c.Check(testing.Stdout(ctx), gc.Matches, "WARNING!.*local.test1(.|\n)*") 125 checkControllerExistsInStore(c, "local.test1", s.store) 126 } 127 128 func (s *KillSuite) TestKillCommandControllerAlias(c *gc.C) { 129 _, err := testing.RunCommand(c, s.newKillCommand(), "local.test1", "-y") 130 c.Assert(err, jc.ErrorIsNil) 131 checkControllerRemovedFromStore(c, "local.test1:test1", s.store) 132 } 133 134 func (s *KillSuite) TestKillAPIPermErrFails(c *gc.C) { 135 testDialer := func(_ jujuclient.ClientStore, controllerName, accountName, modelName string) (api.Connection, error) { 136 return nil, common.ErrPerm 137 } 138 cmd := controller.NewKillCommandForTest(nil, nil, s.store, nil, clock.WallClock, modelcmd.OpenFunc(testDialer)) 139 _, err := testing.RunCommand(c, cmd, "local.test1", "-y") 140 c.Assert(err, gc.ErrorMatches, "cannot destroy controller: permission denied") 141 checkControllerExistsInStore(c, "local.test1", s.store) 142 } 143 144 func (s *KillSuite) TestKillEarlyAPIConnectionTimeout(c *gc.C) { 145 clock := &mockClock{} 146 147 stop := make(chan struct{}) 148 defer close(stop) 149 testDialer := func(_ jujuclient.ClientStore, controllerName, accountName, modelName string) (api.Connection, error) { 150 <-stop 151 return nil, errors.New("kill command waited too long") 152 } 153 154 cmd := controller.NewKillCommandForTest(nil, nil, s.store, nil, clock, modelcmd.OpenFunc(testDialer)) 155 ctx, err := testing.RunCommand(c, cmd, "local.test1", "-y") 156 c.Check(err, jc.ErrorIsNil) 157 c.Check(testing.Stderr(ctx), jc.Contains, "Unable to open API: open connection timed out") 158 checkControllerRemovedFromStore(c, "local.test1", s.store) 159 // Check that we were actually told to wait for 10s. 160 c.Assert(clock.wait, gc.Equals, 10*time.Second) 161 } 162 163 // mockClock will panic if anything but After is called 164 type mockClock struct { 165 clock.Clock 166 wait time.Duration 167 } 168 169 func (m *mockClock) After(duration time.Duration) <-chan time.Time { 170 m.wait = duration 171 return time.After(time.Millisecond) 172 } 173 174 func (s *KillSuite) TestControllerStatus(c *gc.C) { 175 s.api.allEnvs = []base.UserModel{ 176 {Name: "admin", 177 UUID: "123", 178 Owner: names.NewUserTag("admin").String(), 179 }, {Name: "env1", 180 UUID: "456", 181 Owner: names.NewUserTag("bob").String(), 182 }, {Name: "env2", 183 UUID: "789", 184 Owner: names.NewUserTag("jo").String(), 185 }, 186 } 187 188 s.api.envStatus = make(map[string]base.ModelStatus) 189 for _, env := range s.api.allEnvs { 190 owner, err := names.ParseUserTag(env.Owner) 191 c.Assert(err, jc.ErrorIsNil) 192 s.api.envStatus[env.UUID] = base.ModelStatus{ 193 UUID: env.UUID, 194 Life: params.Dying, 195 HostedMachineCount: 2, 196 ServiceCount: 1, 197 Owner: owner.Canonical(), 198 } 199 } 200 201 ctrStatus, envsStatus, err := controller.NewData(s.api, "123") 202 c.Assert(err, jc.ErrorIsNil) 203 c.Assert(ctrStatus.HostedModelCount, gc.Equals, 2) 204 c.Assert(ctrStatus.HostedMachineCount, gc.Equals, 6) 205 c.Assert(ctrStatus.ServiceCount, gc.Equals, 3) 206 c.Assert(envsStatus, gc.HasLen, 2) 207 208 for i, expected := range []struct { 209 Owner string 210 Name string 211 Life params.Life 212 HostedMachineCount int 213 ServiceCount int 214 }{ 215 { 216 Owner: "bob@local", 217 Name: "env1", 218 Life: params.Dying, 219 HostedMachineCount: 2, 220 ServiceCount: 1, 221 }, { 222 Owner: "jo@local", 223 Name: "env2", 224 Life: params.Dying, 225 HostedMachineCount: 2, 226 ServiceCount: 1, 227 }, 228 } { 229 c.Assert(envsStatus[i].Owner, gc.Equals, expected.Owner) 230 c.Assert(envsStatus[i].Name, gc.Equals, expected.Name) 231 c.Assert(envsStatus[i].Life, gc.Equals, expected.Life) 232 c.Assert(envsStatus[i].HostedMachineCount, gc.Equals, expected.HostedMachineCount) 233 c.Assert(envsStatus[i].ServiceCount, gc.Equals, expected.ServiceCount) 234 } 235 236 } 237 238 func (s *KillSuite) TestFmtControllerStatus(c *gc.C) { 239 data := controller.CtrData{ 240 "uuid", 241 params.Alive, 242 3, 243 20, 244 8, 245 } 246 out := controller.FmtCtrStatus(data) 247 c.Assert(out, gc.Equals, "Waiting on 3 models, 20 machines, 8 services") 248 } 249 250 func (s *KillSuite) TestFmtEnvironStatus(c *gc.C) { 251 data := controller.ModelData{ 252 "uuid", 253 "owner@local", 254 "envname", 255 params.Dying, 256 8, 257 1, 258 } 259 260 out := controller.FmtModelStatus(data) 261 c.Assert(out, gc.Equals, "\towner@local/envname (dying), 8 machines, 1 service") 262 }