github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/cmd/juju/deploy_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/errors" 10 jc "github.com/juju/testing/checkers" 11 "github.com/juju/utils" 12 gc "launchpad.net/gocheck" 13 14 "github.com/juju/juju/charm" 15 charmtesting "github.com/juju/juju/charm/testing" 16 "github.com/juju/juju/cmd/envcmd" 17 "github.com/juju/juju/constraints" 18 "github.com/juju/juju/instance" 19 "github.com/juju/juju/juju/testing" 20 "github.com/juju/juju/state" 21 coretesting "github.com/juju/juju/testing" 22 ) 23 24 type DeploySuite struct { 25 testing.RepoSuite 26 } 27 28 var _ = gc.Suite(&DeploySuite{}) 29 30 func runDeploy(c *gc.C, args ...string) error { 31 _, err := coretesting.RunCommand(c, envcmd.Wrap(&DeployCommand{}), args...) 32 return err 33 } 34 35 var initErrorTests = []struct { 36 args []string 37 err string 38 }{ 39 { 40 args: nil, 41 err: `no charm specified`, 42 }, { 43 args: []string{"charm-name", "service-name", "hotdog"}, 44 err: `unrecognized args: \["hotdog"\]`, 45 }, { 46 args: []string{"craz~ness"}, 47 err: `invalid charm name "craz~ness"`, 48 }, { 49 args: []string{"craziness", "burble-1"}, 50 err: `invalid service name "burble-1"`, 51 }, { 52 args: []string{"craziness", "burble1", "-n", "0"}, 53 err: `--num-units must be a positive integer`, 54 }, { 55 args: []string{"craziness", "burble1", "--to", "bigglesplop"}, 56 err: `invalid --to parameter "bigglesplop"`, 57 }, { 58 args: []string{"craziness", "burble1", "-n", "2", "--to", "123"}, 59 err: `cannot use --num-units > 1 with --to`, 60 }, { 61 args: []string{"craziness", "burble1", "--constraints", "gibber=plop"}, 62 err: `invalid value "gibber=plop" for flag --constraints: unknown constraint "gibber"`, 63 }, 64 } 65 66 func (s *DeploySuite) TestInitErrors(c *gc.C) { 67 for i, t := range initErrorTests { 68 c.Logf("test %d", i) 69 err := coretesting.InitCommand(envcmd.Wrap(&DeployCommand{}), t.args) 70 c.Assert(err, gc.ErrorMatches, t.err) 71 } 72 } 73 74 func (s *DeploySuite) TestNoCharm(c *gc.C) { 75 err := runDeploy(c, "local:unknown-123") 76 c.Assert(err, gc.ErrorMatches, `charm not found in ".*": local:precise/unknown-123`) 77 } 78 79 func (s *DeploySuite) TestCharmDir(c *gc.C) { 80 charmtesting.Charms.ClonedDirPath(s.SeriesPath, "dummy") 81 err := runDeploy(c, "local:dummy") 82 c.Assert(err, gc.IsNil) 83 curl := charm.MustParseURL("local:precise/dummy-1") 84 s.AssertService(c, "dummy", curl, 1, 0) 85 } 86 87 func (s *DeploySuite) TestUpgradeReportsDeprecated(c *gc.C) { 88 charmtesting.Charms.ClonedDirPath(s.SeriesPath, "dummy") 89 ctx, err := coretesting.RunCommand(c, envcmd.Wrap(&DeployCommand{}), "local:dummy", "-u") 90 c.Assert(err, gc.IsNil) 91 92 c.Assert(coretesting.Stdout(ctx), gc.Equals, "") 93 output := strings.Split(coretesting.Stderr(ctx), "\n") 94 c.Check(output[0], gc.Matches, `Added charm ".*" to the environment.`) 95 c.Check(output[1], gc.Equals, "--upgrade (or -u) is deprecated and ignored; charms are always deployed with a unique revision.") 96 } 97 98 func (s *DeploySuite) TestUpgradeCharmDir(c *gc.C) { 99 // Add the charm, so the url will exist and a new revision will be 100 // picked in ServiceDeploy. 101 dummyCharm := s.AddTestingCharm(c, "dummy") 102 103 dirPath := charmtesting.Charms.ClonedDirPath(s.SeriesPath, "dummy") 104 err := runDeploy(c, "local:quantal/dummy") 105 c.Assert(err, gc.IsNil) 106 upgradedRev := dummyCharm.Revision() + 1 107 curl := dummyCharm.URL().WithRevision(upgradedRev) 108 s.AssertService(c, "dummy", curl, 1, 0) 109 // Check the charm dir was left untouched. 110 ch, err := charm.ReadDir(dirPath) 111 c.Assert(err, gc.IsNil) 112 c.Assert(ch.Revision(), gc.Equals, 1) 113 } 114 115 func (s *DeploySuite) TestCharmBundle(c *gc.C) { 116 charmtesting.Charms.BundlePath(s.SeriesPath, "dummy") 117 err := runDeploy(c, "local:dummy", "some-service-name") 118 c.Assert(err, gc.IsNil) 119 curl := charm.MustParseURL("local:precise/dummy-1") 120 s.AssertService(c, "some-service-name", curl, 1, 0) 121 } 122 123 func (s *DeploySuite) TestSubordinateCharm(c *gc.C) { 124 charmtesting.Charms.BundlePath(s.SeriesPath, "logging") 125 err := runDeploy(c, "local:logging") 126 c.Assert(err, gc.IsNil) 127 curl := charm.MustParseURL("local:precise/logging-1") 128 s.AssertService(c, "logging", curl, 0, 0) 129 } 130 131 func (s *DeploySuite) TestConfig(c *gc.C) { 132 charmtesting.Charms.BundlePath(s.SeriesPath, "dummy") 133 path := setupConfigFile(c, c.MkDir()) 134 err := runDeploy(c, "local:dummy", "dummy-service", "--config", path) 135 c.Assert(err, gc.IsNil) 136 service, err := s.State.Service("dummy-service") 137 c.Assert(err, gc.IsNil) 138 settings, err := service.ConfigSettings() 139 c.Assert(err, gc.IsNil) 140 c.Assert(settings, gc.DeepEquals, charm.Settings{ 141 "skill-level": int64(9000), 142 "username": "admin001", 143 }) 144 } 145 146 func (s *DeploySuite) TestRelativeConfigPath(c *gc.C) { 147 charmtesting.Charms.BundlePath(s.SeriesPath, "dummy") 148 // Putting a config file in home is okay as $HOME is set to a tempdir 149 setupConfigFile(c, utils.Home()) 150 err := runDeploy(c, "local:dummy", "dummy-service", "--config", "~/testconfig.yaml") 151 c.Assert(err, gc.IsNil) 152 } 153 154 func (s *DeploySuite) TestConfigError(c *gc.C) { 155 charmtesting.Charms.BundlePath(s.SeriesPath, "dummy") 156 path := setupConfigFile(c, c.MkDir()) 157 err := runDeploy(c, "local:dummy", "other-service", "--config", path) 158 c.Assert(err, gc.ErrorMatches, `no settings found for "other-service"`) 159 _, err = s.State.Service("other-service") 160 c.Assert(err, jc.Satisfies, errors.IsNotFound) 161 } 162 163 func (s *DeploySuite) TestConstraints(c *gc.C) { 164 charmtesting.Charms.BundlePath(s.SeriesPath, "dummy") 165 err := runDeploy(c, "local:dummy", "--constraints", "mem=2G cpu-cores=2 networks=net1,^net2") 166 c.Assert(err, gc.IsNil) 167 curl := charm.MustParseURL("local:precise/dummy-1") 168 service, _ := s.AssertService(c, "dummy", curl, 1, 0) 169 cons, err := service.Constraints() 170 c.Assert(err, gc.IsNil) 171 c.Assert(cons, jc.DeepEquals, constraints.MustParse("mem=2G cpu-cores=2 networks=net1,^net2")) 172 } 173 174 func (s *DeploySuite) TestNetworks(c *gc.C) { 175 charmtesting.Charms.BundlePath(s.SeriesPath, "dummy") 176 err := runDeploy(c, "local:dummy", "--networks", ", net1, net2 , ", "--constraints", "mem=2G cpu-cores=2 networks=net1,net0,^net3,^net4") 177 c.Assert(err, gc.IsNil) 178 curl := charm.MustParseURL("local:precise/dummy-1") 179 service, _ := s.AssertService(c, "dummy", curl, 1, 0) 180 networks, err := service.Networks() 181 c.Assert(err, gc.IsNil) 182 c.Assert(networks, jc.DeepEquals, []string{"net1", "net2"}) 183 cons, err := service.Constraints() 184 c.Assert(err, gc.IsNil) 185 c.Assert(cons, jc.DeepEquals, constraints.MustParse("mem=2G cpu-cores=2 networks=net1,net0,^net3,^net4")) 186 } 187 188 func (s *DeploySuite) TestSubordinateConstraints(c *gc.C) { 189 charmtesting.Charms.BundlePath(s.SeriesPath, "logging") 190 err := runDeploy(c, "local:logging", "--constraints", "mem=1G") 191 c.Assert(err, gc.ErrorMatches, "cannot use --constraints with subordinate service") 192 } 193 194 func (s *DeploySuite) TestNumUnits(c *gc.C) { 195 charmtesting.Charms.BundlePath(s.SeriesPath, "dummy") 196 err := runDeploy(c, "local:dummy", "-n", "13") 197 c.Assert(err, gc.IsNil) 198 curl := charm.MustParseURL("local:precise/dummy-1") 199 s.AssertService(c, "dummy", curl, 13, 0) 200 } 201 202 func (s *DeploySuite) TestNumUnitsSubordinate(c *gc.C) { 203 charmtesting.Charms.BundlePath(s.SeriesPath, "logging") 204 err := runDeploy(c, "--num-units", "3", "local:logging") 205 c.Assert(err, gc.ErrorMatches, "cannot use --num-units or --to with subordinate service") 206 _, err = s.State.Service("dummy") 207 c.Assert(err, gc.ErrorMatches, `service "dummy" not found`) 208 } 209 210 func (s *DeploySuite) assertForceMachine(c *gc.C, machineId string) { 211 svc, err := s.State.Service("portlandia") 212 c.Assert(err, gc.IsNil) 213 units, err := svc.AllUnits() 214 c.Assert(err, gc.IsNil) 215 c.Assert(units, gc.HasLen, 1) 216 mid, err := units[0].AssignedMachineId() 217 c.Assert(err, gc.IsNil) 218 c.Assert(mid, gc.Equals, machineId) 219 } 220 221 func (s *DeploySuite) TestForceMachine(c *gc.C) { 222 charmtesting.Charms.BundlePath(s.SeriesPath, "dummy") 223 machine, err := s.State.AddMachine("precise", state.JobHostUnits) 224 c.Assert(err, gc.IsNil) 225 err = runDeploy(c, "--to", machine.Id(), "local:dummy", "portlandia") 226 c.Assert(err, gc.IsNil) 227 s.assertForceMachine(c, machine.Id()) 228 } 229 230 func (s *DeploySuite) TestForceMachineExistingContainer(c *gc.C) { 231 charmtesting.Charms.BundlePath(s.SeriesPath, "dummy") 232 template := state.MachineTemplate{ 233 Series: "precise", 234 Jobs: []state.MachineJob{state.JobHostUnits}, 235 } 236 container, err := s.State.AddMachineInsideNewMachine(template, template, instance.LXC) 237 c.Assert(err, gc.IsNil) 238 err = runDeploy(c, "--to", container.Id(), "local:dummy", "portlandia") 239 c.Assert(err, gc.IsNil) 240 s.assertForceMachine(c, container.Id()) 241 machines, err := s.State.AllMachines() 242 c.Assert(err, gc.IsNil) 243 c.Assert(machines, gc.HasLen, 2) 244 } 245 246 func (s *DeploySuite) TestForceMachineNewContainer(c *gc.C) { 247 charmtesting.Charms.BundlePath(s.SeriesPath, "dummy") 248 machine, err := s.State.AddMachine("precise", state.JobHostUnits) 249 c.Assert(err, gc.IsNil) 250 err = runDeploy(c, "--to", "lxc:"+machine.Id(), "local:dummy", "portlandia") 251 c.Assert(err, gc.IsNil) 252 s.assertForceMachine(c, machine.Id()+"/lxc/0") 253 machines, err := s.State.AllMachines() 254 c.Assert(err, gc.IsNil) 255 c.Assert(machines, gc.HasLen, 2) 256 } 257 258 func (s *DeploySuite) TestForceMachineNotFound(c *gc.C) { 259 charmtesting.Charms.BundlePath(s.SeriesPath, "dummy") 260 err := runDeploy(c, "--to", "42", "local:dummy", "portlandia") 261 c.Assert(err, gc.ErrorMatches, `cannot assign unit "portlandia/0" to machine: machine 42 not found`) 262 _, err = s.State.Service("dummy") 263 c.Assert(err, gc.ErrorMatches, `service "dummy" not found`) 264 } 265 266 func (s *DeploySuite) TestForceMachineSubordinate(c *gc.C) { 267 machine, err := s.State.AddMachine("precise", state.JobHostUnits) 268 c.Assert(err, gc.IsNil) 269 charmtesting.Charms.BundlePath(s.SeriesPath, "logging") 270 err = runDeploy(c, "--to", machine.Id(), "local:logging") 271 c.Assert(err, gc.ErrorMatches, "cannot use --num-units or --to with subordinate service") 272 _, err = s.State.Service("dummy") 273 c.Assert(err, gc.ErrorMatches, `service "dummy" not found`) 274 }