github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/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{"lxd"}, 59 count: 1, 60 placement: "lxd:", 61 }, { 62 args: []string{"lxd", "-n", "2"}, 63 count: 2, 64 placement: "lxd:", 65 }, { 66 args: []string{"lxd:4"}, 67 count: 1, 68 placement: "lxd:4", 69 }, { 70 args: []string{"ssh:user@10.10.0.3"}, 71 count: 1, 72 placement: "ssh:user@10.10.0.3", 73 }, { 74 args: []string{"zone=us-east-1a"}, 75 count: 1, 76 placement: "model-uuid:zone=us-east-1a", 77 }, { 78 args: []string{"anything-here"}, 79 count: 1, 80 placement: "model-uuid:anything-here", 81 }, { 82 args: []string{"anything", "else"}, 83 errorString: `unrecognized args: \["else"\]`, 84 }, { 85 args: []string{"something:special"}, 86 count: 1, 87 placement: "something:special", 88 }, 89 } { 90 c.Logf("test %d", i) 91 wrappedCommand, addCmd := machine.NewAddCommandForTest(s.fakeAddMachine, s.fakeAddMachine, s.fakeMachineManager) 92 err := testing.InitCommand(wrappedCommand, test.args) 93 if test.errorString == "" { 94 c.Check(err, jc.ErrorIsNil) 95 c.Check(addCmd.Series, gc.Equals, test.series) 96 c.Check(addCmd.Constraints.String(), gc.Equals, test.constraints) 97 if addCmd.Placement != nil { 98 c.Check(addCmd.Placement.String(), gc.Equals, test.placement) 99 } else { 100 c.Check("", gc.Equals, test.placement) 101 } 102 c.Check(addCmd.NumMachines, gc.Equals, test.count) 103 } else { 104 c.Check(err, gc.ErrorMatches, test.errorString) 105 } 106 } 107 } 108 109 func (s *AddMachineSuite) run(c *gc.C, args ...string) (*cmd.Context, error) { 110 add, _ := machine.NewAddCommandForTest(s.fakeAddMachine, s.fakeAddMachine, s.fakeMachineManager) 111 return testing.RunCommand(c, add, args...) 112 } 113 114 func (s *AddMachineSuite) TestAddMachine(c *gc.C) { 115 context, err := s.run(c) 116 c.Assert(err, jc.ErrorIsNil) 117 c.Assert(testing.Stderr(context), gc.Equals, "created machine 0\n") 118 119 c.Assert(s.fakeAddMachine.args, gc.HasLen, 1) 120 param := s.fakeAddMachine.args[0] 121 c.Assert(param.Jobs, jc.DeepEquals, []multiwatcher.MachineJob{ 122 multiwatcher.JobHostUnits, 123 }) 124 } 125 126 func (s *AddMachineSuite) TestAddMachineUnauthorizedMentionsJujuGrant(c *gc.C) { 127 s.fakeAddMachine.addModelGetError = ¶ms.Error{ 128 Message: "permission denied", 129 Code: params.CodeUnauthorized, 130 } 131 ctx, _ := s.run(c) 132 errString := strings.Replace(testing.Stderr(ctx), "\n", " ", -1) 133 c.Assert(errString, gc.Matches, `.*juju grant.*`) 134 } 135 136 func (s *AddMachineSuite) TestSSHPlacement(c *gc.C) { 137 s.PatchValue(machine.ManualProvisioner, func(args manual.ProvisionMachineArgs) (string, error) { 138 return "42", nil 139 }) 140 context, err := s.run(c, "ssh:10.1.2.3") 141 c.Assert(err, jc.ErrorIsNil) 142 c.Assert(testing.Stderr(context), gc.Equals, "created machine 42\n") 143 } 144 145 func (s *AddMachineSuite) TestSSHPlacementError(c *gc.C) { 146 s.PatchValue(machine.ManualProvisioner, func(args manual.ProvisionMachineArgs) (string, error) { 147 return "", errors.New("failed to initialize warp core") 148 }) 149 context, err := s.run(c, "ssh:10.1.2.3") 150 c.Assert(err, gc.ErrorMatches, "failed to initialize warp core") 151 c.Assert(testing.Stderr(context), gc.Equals, "") 152 } 153 154 func (s *AddMachineSuite) TestParamsPassedOn(c *gc.C) { 155 _, err := s.run(c, "--constraints", "mem=8G", "--series=special", "zone=nz") 156 c.Assert(err, jc.ErrorIsNil) 157 c.Assert(s.fakeAddMachine.args, gc.HasLen, 1) 158 param := s.fakeAddMachine.args[0] 159 c.Assert(param.Placement.String(), gc.Equals, "fake-uuid:zone=nz") 160 c.Assert(param.Series, gc.Equals, "special") 161 c.Assert(param.Constraints.String(), gc.Equals, "mem=8192M") 162 } 163 164 func (s *AddMachineSuite) TestParamsPassedOnNTimes(c *gc.C) { 165 _, err := s.run(c, "-n", "3", "--constraints", "mem=8G", "--series=special") 166 c.Assert(err, jc.ErrorIsNil) 167 c.Assert(s.fakeAddMachine.args, gc.HasLen, 3) 168 param := s.fakeAddMachine.args[0] 169 c.Assert(param.Series, gc.Equals, "special") 170 c.Assert(param.Constraints.String(), gc.Equals, "mem=8192M") 171 c.Assert(s.fakeAddMachine.args[0], jc.DeepEquals, s.fakeAddMachine.args[1]) 172 c.Assert(s.fakeAddMachine.args[0], jc.DeepEquals, s.fakeAddMachine.args[2]) 173 } 174 175 func (s *AddMachineSuite) TestAddThreeMachinesWithTwoFailures(c *gc.C) { 176 s.fakeAddMachine.successOrder = []bool{true, false, false} 177 expectedOutput := `created machine 0 178 failed to create 2 machines 179 ` 180 context, err := s.run(c, "-n", "3") 181 c.Assert(err, gc.ErrorMatches, "something went wrong, something went wrong") 182 c.Assert(testing.Stderr(context), gc.Equals, expectedOutput) 183 } 184 185 func (s *AddMachineSuite) TestBlockedError(c *gc.C) { 186 s.fakeAddMachine.addError = common.OperationBlockedError("TestBlockedError") 187 _, err := s.run(c) 188 testing.AssertOperationWasBlocked(c, err, ".*TestBlockedError.*") 189 } 190 191 func (s *AddMachineSuite) TestAddMachineWithDisks(c *gc.C) { 192 s.fakeMachineManager.apiVersion = 1 193 _, err := s.run(c, "--disks", "2,1G", "--disks", "2G") 194 c.Assert(err, jc.ErrorIsNil) 195 c.Assert(s.fakeAddMachine.args, gc.HasLen, 0) 196 c.Assert(s.fakeMachineManager.args, gc.HasLen, 1) 197 param := s.fakeMachineManager.args[0] 198 c.Assert(param.Disks, gc.DeepEquals, []storage.Constraints{ 199 {Size: 1024, Count: 2}, 200 {Size: 2048, Count: 1}, 201 }) 202 } 203 204 func (s *AddMachineSuite) TestAddMachineWithDisksUnsupported(c *gc.C) { 205 _, err := s.run(c, "--disks", "2,1G", "--disks", "2G") 206 c.Assert(err, gc.ErrorMatches, "cannot add machines with disks: not supported by the API server") 207 } 208 209 type fakeAddMachineAPI struct { 210 successOrder []bool 211 currentOp int 212 args []params.AddMachineParams 213 addError error 214 addModelGetError error 215 providerType string 216 } 217 218 func (f *fakeAddMachineAPI) Close() error { 219 return nil 220 } 221 222 func (f *fakeAddMachineAPI) ModelUUID() (string, bool) { 223 return "fake-uuid", true 224 } 225 226 func (f *fakeAddMachineAPI) AddMachines(args []params.AddMachineParams) ([]params.AddMachinesResult, error) { 227 if f.addError != nil { 228 return nil, f.addError 229 } 230 results := []params.AddMachinesResult{} 231 for i := range args { 232 f.args = append(f.args, args[i]) 233 if i >= len(f.successOrder) || f.successOrder[i] { 234 results = append(results, params.AddMachinesResult{ 235 Machine: strconv.Itoa(i), 236 Error: nil, 237 }) 238 } else { 239 results = append(results, params.AddMachinesResult{ 240 Machine: string(i), 241 Error: ¶ms.Error{Message: "something went wrong", Code: "1"}, 242 }) 243 } 244 f.currentOp++ 245 } 246 return results, nil 247 } 248 249 func (f *fakeAddMachineAPI) ForceDestroyMachines(machines ...string) error { 250 return errors.NotImplementedf("ForceDestroyMachines") 251 } 252 253 func (f *fakeAddMachineAPI) ProvisioningScript(params.ProvisioningScriptParams) (script string, err error) { 254 return "", errors.NotImplementedf("ProvisioningScript") 255 } 256 257 func (f *fakeAddMachineAPI) ModelGet() (map[string]interface{}, error) { 258 if f.addModelGetError != nil { 259 return nil, f.addModelGetError 260 } 261 providerType := "dummy" 262 if f.providerType != "" { 263 providerType = f.providerType 264 } 265 return dummy.SampleConfig().Merge(map[string]interface{}{ 266 "type": providerType, 267 }), nil 268 } 269 270 type fakeMachineManagerAPI struct { 271 apiVersion int 272 fakeAddMachineAPI 273 } 274 275 func (f *fakeMachineManagerAPI) BestAPIVersion() int { 276 return f.apiVersion 277 }