github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/cmd/juju/addunit_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package main 5 6 import ( 7 "strings" 8 9 "github.com/juju/cmd" 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 "gopkg.in/juju/charm.v4" 13 14 "github.com/juju/juju/api" 15 "github.com/juju/juju/cmd/envcmd" 16 "github.com/juju/juju/environs/config" 17 "github.com/juju/juju/instance" 18 jujutesting "github.com/juju/juju/juju/testing" 19 "github.com/juju/juju/state" 20 "github.com/juju/juju/testcharms" 21 "github.com/juju/juju/testing" 22 ) 23 24 type AddUnitSuite struct { 25 jujutesting.RepoSuite 26 } 27 28 var _ = gc.Suite(&AddUnitSuite{}) 29 30 var initAddUnitErrorTests = []struct { 31 args []string 32 err string 33 }{ 34 { 35 args: []string{"some-service-name", "-n", "0"}, 36 err: `--num-units must be a positive integer`, 37 }, { 38 args: []string{"some-service-name", "--to", "bigglesplop"}, 39 err: `invalid --to parameter "bigglesplop"`, 40 }, { 41 args: []string{"some-service-name", "-n", "2", "--to", "123"}, 42 err: `cannot use --num-units > 1 with --to`, 43 }, 44 } 45 46 func (s *AddUnitSuite) TestInitErrors(c *gc.C) { 47 for i, t := range initAddUnitErrorTests { 48 c.Logf("test %d", i) 49 err := testing.InitCommand(envcmd.Wrap(&AddUnitCommand{}), t.args) 50 c.Check(err, gc.ErrorMatches, t.err) 51 } 52 } 53 54 func runAddUnit(c *gc.C, args ...string) error { 55 _, err := testing.RunCommand(c, envcmd.Wrap(&AddUnitCommand{}), args...) 56 return err 57 } 58 59 func (s *AddUnitSuite) setupService(c *gc.C) *charm.URL { 60 testcharms.Repo.CharmArchivePath(s.SeriesPath, "dummy") 61 err := runDeploy(c, "local:dummy", "some-service-name") 62 c.Assert(err, jc.ErrorIsNil) 63 curl := charm.MustParseURL("local:trusty/dummy-1") 64 s.AssertService(c, "some-service-name", curl, 1, 0) 65 return curl 66 } 67 68 func (s *AddUnitSuite) TestAddUnit(c *gc.C) { 69 curl := s.setupService(c) 70 71 err := runAddUnit(c, "some-service-name") 72 c.Assert(err, jc.ErrorIsNil) 73 s.AssertService(c, "some-service-name", curl, 2, 0) 74 75 err = runAddUnit(c, "--num-units", "2", "some-service-name") 76 c.Assert(err, jc.ErrorIsNil) 77 s.AssertService(c, "some-service-name", curl, 4, 0) 78 } 79 80 func (s *AddUnitSuite) TestBlockAddUnit(c *gc.C) { 81 s.setupService(c) 82 83 // Block operation 84 s.AssertConfigParameterUpdated(c, "block-all-changes", true) 85 c.Assert(runAddUnit(c, "some-service-name"), gc.ErrorMatches, cmd.ErrSilent.Error()) 86 87 // msg is logged 88 stripped := strings.Replace(c.GetTestLog(), "\n", "", -1) 89 c.Check(stripped, gc.Matches, ".*To unblock changes.*") 90 } 91 92 // assertForceMachine ensures that the result of assigning a unit with --to 93 // is as expected. 94 func (s *AddUnitSuite) assertForceMachine(c *gc.C, svc *state.Service, expectedNumMachines, unitNum int, machineId string) { 95 units, err := svc.AllUnits() 96 c.Assert(err, jc.ErrorIsNil) 97 c.Assert(units, gc.HasLen, expectedNumMachines) 98 mid, err := units[unitNum].AssignedMachineId() 99 c.Assert(err, jc.ErrorIsNil) 100 c.Assert(mid, gc.Equals, machineId) 101 } 102 103 func (s *AddUnitSuite) TestForceMachine(c *gc.C) { 104 curl := s.setupService(c) 105 machine, err := s.State.AddMachine(testing.FakeDefaultSeries, state.JobHostUnits) 106 c.Assert(err, jc.ErrorIsNil) 107 machine2, err := s.State.AddMachine(testing.FakeDefaultSeries, state.JobHostUnits) 108 c.Assert(err, jc.ErrorIsNil) 109 110 err = runAddUnit(c, "some-service-name", "--to", machine2.Id()) 111 c.Assert(err, jc.ErrorIsNil) 112 err = runAddUnit(c, "some-service-name", "--to", machine.Id()) 113 c.Assert(err, jc.ErrorIsNil) 114 svc, _ := s.AssertService(c, "some-service-name", curl, 3, 0) 115 s.assertForceMachine(c, svc, 3, 1, machine2.Id()) 116 s.assertForceMachine(c, svc, 3, 2, machine.Id()) 117 } 118 119 func (s *AddUnitSuite) TestBlockForceMachine(c *gc.C) { 120 curl := s.setupService(c) 121 machine, err := s.State.AddMachine(testing.FakeDefaultSeries, state.JobHostUnits) 122 c.Assert(err, jc.ErrorIsNil) 123 machine2, err := s.State.AddMachine(testing.FakeDefaultSeries, state.JobHostUnits) 124 c.Assert(err, jc.ErrorIsNil) 125 126 err = runAddUnit(c, "some-service-name", "--to", machine2.Id()) 127 c.Assert(err, jc.ErrorIsNil) 128 err = runAddUnit(c, "some-service-name", "--to", machine.Id()) 129 c.Assert(err, jc.ErrorIsNil) 130 svc, _ := s.AssertService(c, "some-service-name", curl, 3, 0) 131 // Block operation: should be ignored :) 132 s.AssertConfigParameterUpdated(c, "block-all-changes", true) 133 s.assertForceMachine(c, svc, 3, 1, machine2.Id()) 134 s.assertForceMachine(c, svc, 3, 2, machine.Id()) 135 } 136 137 func (s *AddUnitSuite) TestForceMachineExistingContainer(c *gc.C) { 138 curl := s.setupService(c) 139 machine, err := s.State.AddMachine(testing.FakeDefaultSeries, state.JobHostUnits) 140 c.Assert(err, jc.ErrorIsNil) 141 template := state.MachineTemplate{ 142 Series: testing.FakeDefaultSeries, 143 Jobs: []state.MachineJob{state.JobHostUnits}, 144 } 145 container, err := s.State.AddMachineInsideMachine(template, machine.Id(), instance.LXC) 146 c.Assert(err, jc.ErrorIsNil) 147 148 err = runAddUnit(c, "some-service-name", "--to", container.Id()) 149 c.Assert(err, jc.ErrorIsNil) 150 err = runAddUnit(c, "some-service-name", "--to", machine.Id()) 151 c.Assert(err, jc.ErrorIsNil) 152 svc, _ := s.AssertService(c, "some-service-name", curl, 3, 0) 153 s.assertForceMachine(c, svc, 3, 1, container.Id()) 154 s.assertForceMachine(c, svc, 3, 2, machine.Id()) 155 } 156 157 func (s *AddUnitSuite) TestForceMachineNewContainer(c *gc.C) { 158 curl := s.setupService(c) 159 machine, err := s.State.AddMachine(testing.FakeDefaultSeries, state.JobHostUnits) 160 c.Assert(err, jc.ErrorIsNil) 161 162 err = runAddUnit(c, "some-service-name", "--to", "lxc:"+machine.Id()) 163 c.Assert(err, jc.ErrorIsNil) 164 err = runAddUnit(c, "some-service-name", "--to", machine.Id()) 165 c.Assert(err, jc.ErrorIsNil) 166 svc, _ := s.AssertService(c, "some-service-name", curl, 3, 0) 167 s.assertForceMachine(c, svc, 3, 1, machine.Id()+"/lxc/0") 168 s.assertForceMachine(c, svc, 3, 2, machine.Id()) 169 } 170 171 func (s *AddUnitSuite) TestNonLocalCannotHostUnits(c *gc.C) { 172 err := runAddUnit(c, "some-service-name", "--to", "0") 173 c.Assert(err, gc.Not(gc.ErrorMatches), "machine 0 is the state server for a local environment and cannot host units") 174 } 175 176 func (s *AddUnitSuite) TestBlockNonLocalCannotHostUnits(c *gc.C) { 177 // Block operation 178 s.AssertConfigParameterUpdated(c, "block-all-changes", true) 179 c.Assert(runAddUnit(c, "some-service-name", "--to", "0"), gc.ErrorMatches, cmd.ErrSilent.Error()) 180 181 // msg is logged 182 stripped := strings.Replace(c.GetTestLog(), "\n", "", -1) 183 c.Check(stripped, gc.Matches, ".*To unblock changes.*") 184 } 185 186 func (s *AddUnitSuite) TestCannotDeployToNonExistentMachine(c *gc.C) { 187 s.setupService(c) 188 err := runAddUnit(c, "some-service-name", "--to", "42") 189 c.Assert(err, gc.ErrorMatches, `cannot add units for service "some-service-name" to machine 42: machine 42 not found`) 190 } 191 192 func (s *AddUnitSuite) TestBlockCannotDeployToNonExistentMachine(c *gc.C) { 193 s.setupService(c) 194 // Block operation 195 s.AssertConfigParameterUpdated(c, "block-all-changes", true) 196 c.Assert(runAddUnit(c, "some-service-name", "--to", "42"), gc.ErrorMatches, cmd.ErrSilent.Error()) 197 198 // msg is logged 199 stripped := strings.Replace(c.GetTestLog(), "\n", "", -1) 200 c.Check(stripped, gc.Matches, ".*To unblock changes.*") 201 } 202 203 type AddUnitLocalSuite struct { 204 jujutesting.RepoSuite 205 } 206 207 var _ = gc.Suite(&AddUnitLocalSuite{}) 208 209 func (s *AddUnitLocalSuite) SetUpTest(c *gc.C) { 210 s.RepoSuite.SetUpTest(c) 211 212 // override provider type 213 s.PatchValue(&getClientConfig, func(client *api.Client) (*config.Config, error) { 214 attrs, err := client.EnvironmentGet() 215 if err != nil { 216 return nil, err 217 } 218 attrs["type"] = "local" 219 return config.New(config.NoDefaults, attrs) 220 }) 221 } 222 223 func (s *AddUnitLocalSuite) TestLocalCannotHostUnits(c *gc.C) { 224 err := runAddUnit(c, "some-service-name", "--to", "0") 225 c.Assert(err, gc.ErrorMatches, "machine 0 is the state server for a local environment and cannot host units") 226 } 227 228 type namesSuite struct { 229 } 230 231 var _ = gc.Suite(&namesSuite{}) 232 233 func (*namesSuite) TestNameChecks(c *gc.C) { 234 assertMachineOrNewContainer := func(s string, expect bool) { 235 c.Logf("%s -> %v", s, expect) 236 c.Assert(isMachineOrNewContainer(s), gc.Equals, expect) 237 } 238 assertMachineOrNewContainer("0", true) 239 assertMachineOrNewContainer("00", false) 240 assertMachineOrNewContainer("1", true) 241 assertMachineOrNewContainer("0/lxc/0", true) 242 assertMachineOrNewContainer("lxc:0", true) 243 assertMachineOrNewContainer("lxc:lxc:0", false) 244 assertMachineOrNewContainer("kvm:0/lxc/1", true) 245 assertMachineOrNewContainer("lxc:", false) 246 assertMachineOrNewContainer(":lxc", false) 247 assertMachineOrNewContainer("0/lxc/", false) 248 assertMachineOrNewContainer("0/lxc", false) 249 assertMachineOrNewContainer("kvm:0/lxc", false) 250 assertMachineOrNewContainer("0/lxc/01", false) 251 assertMachineOrNewContainer("0/lxc/10", true) 252 assertMachineOrNewContainer("0/kvm/4", true) 253 }