github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/juju/machine/add_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package machine_test 5 6 import ( 7 "strconv" 8 "strings" 9 10 "github.com/juju/cmd" 11 "github.com/juju/errors" 12 jc "github.com/juju/testing/checkers" 13 gc "gopkg.in/check.v1" 14 15 "github.com/juju/juju/apiserver/common" 16 "github.com/juju/juju/apiserver/params" 17 "github.com/juju/juju/cmd/juju/machine" 18 "github.com/juju/juju/environs/manual" 19 "github.com/juju/juju/provider/dummy" 20 "github.com/juju/juju/state/multiwatcher" 21 "github.com/juju/juju/storage" 22 "github.com/juju/juju/testing" 23 ) 24 25 type AddMachineSuite struct { 26 testing.FakeJujuXDGDataHomeSuite 27 fakeAddMachine *fakeAddMachineAPI 28 fakeMachineManager *fakeMachineManagerAPI 29 } 30 31 var _ = gc.Suite(&AddMachineSuite{}) 32 33 func (s *AddMachineSuite) SetUpTest(c *gc.C) { 34 s.FakeJujuXDGDataHomeSuite.SetUpTest(c) 35 s.fakeAddMachine = &fakeAddMachineAPI{} 36 s.fakeMachineManager = &fakeMachineManagerAPI{} 37 } 38 39 func (s *AddMachineSuite) TestInit(c *gc.C) { 40 for i, test := range []struct { 41 args []string 42 series string 43 constraints string 44 placement string 45 count int 46 errorString string 47 }{ 48 { 49 count: 1, 50 }, { 51 args: []string{"--series", "some-series"}, 52 count: 1, 53 series: "some-series", 54 }, { 55 args: []string{"-n", "2"}, 56 count: 2, 57 }, { 58 args: []string{"lxc"}, 59 count: 1, 60 placement: "lxc:", 61 }, { 62 args: []string{"lxc", "-n", "2"}, 63 count: 2, 64 placement: "lxc:", 65 }, { 66 args: []string{"lxc:4"}, 67 count: 1, 68 placement: "lxc:4", 69 }, { 70 args: []string{"--constraints", "mem=8G"}, 71 count: 1, 72 constraints: "mem=8192M", 73 }, { 74 args: []string{"--constraints", "container=lxc"}, 75 errorString: `container constraint "lxc" not allowed when adding a machine`, 76 }, { 77 args: []string{"ssh:user@10.10.0.3"}, 78 count: 1, 79 placement: "ssh:user@10.10.0.3", 80 }, { 81 args: []string{"zone=us-east-1a"}, 82 count: 1, 83 placement: "model-uuid:zone=us-east-1a", 84 }, { 85 args: []string{"anything-here"}, 86 count: 1, 87 placement: "model-uuid:anything-here", 88 }, { 89 args: []string{"anything", "else"}, 90 errorString: `unrecognized args: \["else"\]`, 91 }, { 92 args: []string{"something:special"}, 93 count: 1, 94 placement: "something:special", 95 }, 96 } { 97 c.Logf("test %d", i) 98 wrappedCommand, addCmd := machine.NewAddCommandForTest(s.fakeAddMachine, s.fakeMachineManager) 99 err := testing.InitCommand(wrappedCommand, test.args) 100 if test.errorString == "" { 101 c.Check(err, jc.ErrorIsNil) 102 c.Check(addCmd.Series, gc.Equals, test.series) 103 c.Check(addCmd.Constraints.String(), gc.Equals, test.constraints) 104 if addCmd.Placement != nil { 105 c.Check(addCmd.Placement.String(), gc.Equals, test.placement) 106 } else { 107 c.Check("", gc.Equals, test.placement) 108 } 109 c.Check(addCmd.NumMachines, gc.Equals, test.count) 110 } else { 111 c.Check(err, gc.ErrorMatches, test.errorString) 112 } 113 } 114 } 115 116 func (s *AddMachineSuite) run(c *gc.C, args ...string) (*cmd.Context, error) { 117 add, _ := machine.NewAddCommandForTest(s.fakeAddMachine, s.fakeMachineManager) 118 return testing.RunCommand(c, add, args...) 119 } 120 121 func (s *AddMachineSuite) TestAddMachine(c *gc.C) { 122 context, err := s.run(c) 123 c.Assert(err, jc.ErrorIsNil) 124 c.Assert(testing.Stderr(context), gc.Equals, "created machine 0\n") 125 126 c.Assert(s.fakeAddMachine.args, gc.HasLen, 1) 127 param := s.fakeAddMachine.args[0] 128 c.Assert(param.Jobs, jc.DeepEquals, []multiwatcher.MachineJob{ 129 multiwatcher.JobHostUnits, 130 multiwatcher.JobManageNetworking, 131 }) 132 } 133 134 func (s *AddMachineSuite) TestSSHPlacement(c *gc.C) { 135 s.PatchValue(machine.ManualProvisioner, func(args manual.ProvisionMachineArgs) (string, error) { 136 return "42", nil 137 }) 138 context, err := s.run(c, "ssh:10.1.2.3") 139 c.Assert(err, jc.ErrorIsNil) 140 c.Assert(testing.Stderr(context), gc.Equals, "created machine 42\n") 141 } 142 143 func (s *AddMachineSuite) TestSSHPlacementError(c *gc.C) { 144 s.PatchValue(machine.ManualProvisioner, func(args manual.ProvisionMachineArgs) (string, error) { 145 return "", errors.New("failed to initialize warp core") 146 }) 147 context, err := s.run(c, "ssh:10.1.2.3") 148 c.Assert(err, gc.ErrorMatches, "failed to initialize warp core") 149 c.Assert(testing.Stderr(context), gc.Equals, "") 150 } 151 152 func (s *AddMachineSuite) TestParamsPassedOn(c *gc.C) { 153 _, err := s.run(c, "--constraints", "mem=8G", "--series=special", "zone=nz") 154 c.Assert(err, jc.ErrorIsNil) 155 c.Assert(s.fakeAddMachine.args, gc.HasLen, 1) 156 param := s.fakeAddMachine.args[0] 157 c.Assert(param.Placement.String(), gc.Equals, "fake-uuid:zone=nz") 158 c.Assert(param.Series, gc.Equals, "special") 159 c.Assert(param.Constraints.String(), gc.Equals, "mem=8192M") 160 } 161 162 func (s *AddMachineSuite) TestParamsPassedOnNTimes(c *gc.C) { 163 _, err := s.run(c, "-n", "3", "--constraints", "mem=8G", "--series=special") 164 c.Assert(err, jc.ErrorIsNil) 165 c.Assert(s.fakeAddMachine.args, gc.HasLen, 3) 166 param := s.fakeAddMachine.args[0] 167 c.Assert(param.Series, gc.Equals, "special") 168 c.Assert(param.Constraints.String(), gc.Equals, "mem=8192M") 169 c.Assert(s.fakeAddMachine.args[0], jc.DeepEquals, s.fakeAddMachine.args[1]) 170 c.Assert(s.fakeAddMachine.args[0], jc.DeepEquals, s.fakeAddMachine.args[2]) 171 } 172 173 func (s *AddMachineSuite) TestAddThreeMachinesWithTwoFailures(c *gc.C) { 174 s.fakeAddMachine.successOrder = []bool{true, false, false} 175 expectedOutput := `created machine 0 176 failed to create 2 machines 177 ` 178 context, err := s.run(c, "-n", "3") 179 c.Assert(err, gc.ErrorMatches, "something went wrong, something went wrong") 180 c.Assert(testing.Stderr(context), gc.Equals, expectedOutput) 181 } 182 183 func (s *AddMachineSuite) TestBlockedError(c *gc.C) { 184 s.fakeAddMachine.addError = common.OperationBlockedError("TestBlockedError") 185 _, err := s.run(c) 186 c.Assert(err, gc.Equals, cmd.ErrSilent) 187 // msg is logged 188 stripped := strings.Replace(c.GetTestLog(), "\n", "", -1) 189 c.Check(stripped, gc.Matches, ".*TestBlockedError.*") 190 } 191 192 func (s *AddMachineSuite) TestProviderDoesNotSupportJobManageNetworking(c *gc.C) { 193 s.fakeAddMachine.providerType = "maas" 194 _, err := s.run(c) 195 c.Assert(err, jc.ErrorIsNil) 196 197 c.Assert(s.fakeAddMachine.args, gc.HasLen, 1) 198 param := s.fakeAddMachine.args[0] 199 c.Assert(param.Jobs, jc.DeepEquals, []multiwatcher.MachineJob{ 200 multiwatcher.JobHostUnits, 201 }) 202 } 203 204 func (s *AddMachineSuite) TestAddMachineWithDisks(c *gc.C) { 205 s.fakeMachineManager.apiVersion = 1 206 _, err := s.run(c, "--disks", "2,1G", "--disks", "2G") 207 c.Assert(err, jc.ErrorIsNil) 208 c.Assert(s.fakeAddMachine.args, gc.HasLen, 0) 209 c.Assert(s.fakeMachineManager.args, gc.HasLen, 1) 210 param := s.fakeMachineManager.args[0] 211 c.Assert(param.Disks, gc.DeepEquals, []storage.Constraints{ 212 {Size: 1024, Count: 2}, 213 {Size: 2048, Count: 1}, 214 }) 215 } 216 217 func (s *AddMachineSuite) TestAddMachineWithDisksUnsupported(c *gc.C) { 218 _, err := s.run(c, "--disks", "2,1G", "--disks", "2G") 219 c.Assert(err, gc.ErrorMatches, "cannot add machines with disks: not supported by the API server") 220 } 221 222 type fakeAddMachineAPI struct { 223 successOrder []bool 224 currentOp int 225 args []params.AddMachineParams 226 addError error 227 providerType string 228 } 229 230 func (f *fakeAddMachineAPI) Close() error { 231 return nil 232 } 233 234 func (f *fakeAddMachineAPI) ModelUUID() string { 235 return "fake-uuid" 236 } 237 238 func (f *fakeAddMachineAPI) AddMachines(args []params.AddMachineParams) ([]params.AddMachinesResult, error) { 239 if f.addError != nil { 240 return nil, f.addError 241 } 242 results := []params.AddMachinesResult{} 243 for i := range args { 244 f.args = append(f.args, args[i]) 245 if i >= len(f.successOrder) || f.successOrder[i] { 246 results = append(results, params.AddMachinesResult{ 247 Machine: strconv.Itoa(i), 248 Error: nil, 249 }) 250 } else { 251 results = append(results, params.AddMachinesResult{ 252 Machine: string(i), 253 Error: ¶ms.Error{Message: "something went wrong", Code: "1"}, 254 }) 255 } 256 f.currentOp++ 257 } 258 return results, nil 259 } 260 261 func (f *fakeAddMachineAPI) ForceDestroyMachines(machines ...string) error { 262 return errors.NotImplementedf("ForceDestroyMachines") 263 } 264 265 func (f *fakeAddMachineAPI) ProvisioningScript(params.ProvisioningScriptParams) (script string, err error) { 266 return "", errors.NotImplementedf("ProvisioningScript") 267 } 268 269 func (f *fakeAddMachineAPI) ModelGet() (map[string]interface{}, error) { 270 providerType := "dummy" 271 if f.providerType != "" { 272 providerType = f.providerType 273 } 274 return dummy.SampleConfig().Merge(map[string]interface{}{ 275 "type": providerType, 276 }), nil 277 } 278 279 type fakeMachineManagerAPI struct { 280 apiVersion int 281 fakeAddMachineAPI 282 } 283 284 func (f *fakeMachineManagerAPI) BestAPIVersion() int { 285 return f.apiVersion 286 }