github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/client/action/run_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package action_test 5 6 import ( 7 "time" 8 9 "github.com/juju/errors" 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 "gopkg.in/juju/names.v2" 13 14 "github.com/juju/juju/apiserver/common" 15 commontesting "github.com/juju/juju/apiserver/common/testing" 16 "github.com/juju/juju/apiserver/facades/client/action" 17 "github.com/juju/juju/apiserver/params" 18 apiservertesting "github.com/juju/juju/apiserver/testing" 19 jujutesting "github.com/juju/juju/juju/testing" 20 "github.com/juju/juju/state" 21 "github.com/juju/juju/testing" 22 ) 23 24 type runSuite struct { 25 jujutesting.JujuConnSuite 26 commontesting.BlockHelper 27 28 client *action.ActionAPI 29 } 30 31 var _ = gc.Suite(&runSuite{}) 32 33 func (s *runSuite) SetUpTest(c *gc.C) { 34 s.JujuConnSuite.SetUpTest(c) 35 s.BlockHelper = commontesting.NewBlockHelper(s.APIState) 36 s.AddCleanup(func(*gc.C) { s.BlockHelper.Close() }) 37 38 var err error 39 auth := apiservertesting.FakeAuthorizer{ 40 Tag: s.AdminUserTag(c), 41 } 42 s.client, err = action.NewActionAPI(s.State, nil, auth) 43 c.Assert(err, jc.ErrorIsNil) 44 } 45 46 func (s *runSuite) addMachine(c *gc.C) *state.Machine { 47 machine, err := s.State.AddMachine("quantal", state.JobHostUnits) 48 c.Assert(err, jc.ErrorIsNil) 49 return machine 50 } 51 52 func (s *runSuite) addUnit(c *gc.C, application *state.Application) *state.Unit { 53 unit, err := application.AddUnit(state.AddUnitParams{}) 54 c.Assert(err, jc.ErrorIsNil) 55 err = unit.AssignToNewMachine() 56 c.Assert(err, jc.ErrorIsNil) 57 return unit 58 } 59 60 func (s *runSuite) TestGetAllUnitNames(c *gc.C) { 61 charm := s.AddTestingCharm(c, "dummy") 62 magic, err := s.State.AddApplication(state.AddApplicationArgs{Name: "magic", Charm: charm}) 63 s.addUnit(c, magic) 64 s.addUnit(c, magic) 65 66 // Ensure magic/1 is the leader. 67 claimer, err := s.LeaseManager.Claimer("application-leadership", s.State.ModelUUID()) 68 c.Assert(err, jc.ErrorIsNil) 69 err = claimer.Claim("magic", "magic/1", time.Minute) 70 c.Assert(err, jc.ErrorIsNil) 71 72 notAssigned, err := s.State.AddApplication(state.AddApplicationArgs{Name: "not-assigned", Charm: charm}) 73 c.Assert(err, jc.ErrorIsNil) 74 _, err = notAssigned.AddUnit(state.AddUnitParams{}) 75 c.Assert(err, jc.ErrorIsNil) 76 77 _, err = s.State.AddApplication(state.AddApplicationArgs{Name: "no-units", Charm: charm}) 78 c.Assert(err, jc.ErrorIsNil) 79 80 wordpress, err := s.State.AddApplication(state.AddApplicationArgs{Name: "wordpress", Charm: s.AddTestingCharm(c, "wordpress")}) 81 c.Assert(err, jc.ErrorIsNil) 82 wordpress0 := s.addUnit(c, wordpress) 83 _, err = s.State.AddApplication(state.AddApplicationArgs{Name: "logging", Charm: s.AddTestingCharm(c, "logging")}) 84 c.Assert(err, jc.ErrorIsNil) 85 86 eps, err := s.State.InferEndpoints("logging", "wordpress") 87 c.Assert(err, jc.ErrorIsNil) 88 rel, err := s.State.AddRelation(eps...) 89 c.Assert(err, jc.ErrorIsNil) 90 ru, err := rel.Unit(wordpress0) 91 c.Assert(err, jc.ErrorIsNil) 92 err = ru.EnterScope(nil) 93 c.Assert(err, jc.ErrorIsNil) 94 95 for i, test := range []struct { 96 message string 97 expected []string 98 units []string 99 applications []string 100 error string 101 }{{ 102 message: "no units, expected nil slice", 103 }, { 104 message: "asking for an empty string application", 105 applications: []string{""}, 106 error: `"" is not a valid application name`, 107 }, { 108 message: "asking for an empty string unit", 109 units: []string{""}, 110 error: `invalid unit name ""`, 111 }, { 112 message: "asking for a application that isn't there", 113 applications: []string{"foo"}, 114 error: `application "foo" not found`, 115 }, { 116 message: "application with no units is not really an error", 117 applications: []string{"no-units"}, 118 }, { 119 message: "A application with units", 120 applications: []string{"magic"}, 121 expected: []string{"magic/0", "magic/1"}, 122 }, { 123 message: "Asking for just a unit", 124 units: []string{"magic/0"}, 125 expected: []string{"magic/0"}, 126 }, { 127 message: "Asking for just a subordinate unit", 128 units: []string{"logging/0"}, 129 expected: []string{"logging/0"}, 130 }, { 131 message: "Asking for a unit, and the application", 132 applications: []string{"magic"}, 133 units: []string{"magic/0"}, 134 expected: []string{"magic/0", "magic/1"}, 135 }, { 136 message: "Asking for an application leader unit", 137 units: []string{"magic/leader"}, 138 expected: []string{"magic/1"}, 139 }, { 140 message: "Asking for an application leader unit of an unknown application", 141 units: []string{"foo/leader"}, 142 error: `could not determine leader for "foo"`, 143 }} { 144 c.Logf("%v: %s", i, test.message) 145 result, err := action.GetAllUnitNames(s.State, test.units, test.applications) 146 if test.error == "" { 147 c.Check(err, jc.ErrorIsNil) 148 var units []string 149 for _, unit := range result { 150 units = append(units, unit.Id()) 151 } 152 c.Check(units, jc.SameContents, test.expected) 153 } else { 154 c.Check(err, gc.ErrorMatches, test.error) 155 } 156 } 157 } 158 159 func (s *runSuite) AssertBlocked(c *gc.C, err error, msg string) { 160 c.Assert(params.IsCodeOperationBlocked(err), jc.IsTrue, gc.Commentf("error: %#v", err)) 161 c.Assert(errors.Cause(err), gc.DeepEquals, ¶ms.Error{ 162 Message: msg, 163 Code: "operation is blocked", 164 }) 165 } 166 167 func (s *runSuite) TestBlockRunOnAllMachines(c *gc.C) { 168 // block all changes 169 s.BlockAllChanges(c, "TestBlockRunOnAllMachines") 170 _, err := s.client.RunOnAllMachines( 171 params.RunParams{ 172 Commands: "hostname", 173 Timeout: testing.LongWait, 174 }) 175 s.AssertBlocked(c, err, "TestBlockRunOnAllMachines") 176 } 177 178 func (s *runSuite) TestBlockRunMachineAndApplication(c *gc.C) { 179 // block all changes 180 s.BlockAllChanges(c, "TestBlockRunMachineAndApplication") 181 _, err := s.client.Run( 182 params.RunParams{ 183 Commands: "hostname", 184 Timeout: testing.LongWait, 185 Machines: []string{"0"}, 186 Applications: []string{"magic"}, 187 }) 188 s.AssertBlocked(c, err, "TestBlockRunMachineAndApplication") 189 } 190 191 func (s *runSuite) TestRunMachineAndApplication(c *gc.C) { 192 // We only test that we create the actions correctly 193 // There is no need to test anything else at this level. 194 expectedPayload := map[string]interface{}{ 195 "command": "hostname", 196 "timeout": int64(0), 197 } 198 expectedArgs := params.Actions{ 199 Actions: []params.Action{ 200 {Receiver: "unit-magic-0", Name: "juju-run", Parameters: expectedPayload}, 201 {Receiver: "unit-magic-1", Name: "juju-run", Parameters: expectedPayload}, 202 {Receiver: "machine-0", Name: "juju-run", Parameters: expectedPayload}, 203 }, 204 } 205 called := false 206 s.PatchValue(action.QueueActions, func(client *action.ActionAPI, args params.Actions) (params.ActionResults, error) { 207 called = true 208 c.Assert(args, jc.DeepEquals, expectedArgs) 209 return params.ActionResults{}, nil 210 }) 211 212 s.addMachine(c) 213 214 charm := s.AddTestingCharm(c, "dummy") 215 magic, err := s.State.AddApplication(state.AddApplicationArgs{Name: "magic", Charm: charm}) 216 c.Assert(err, jc.ErrorIsNil) 217 s.addUnit(c, magic) 218 s.addUnit(c, magic) 219 220 s.client.Run( 221 params.RunParams{ 222 Commands: "hostname", 223 Machines: []string{"0"}, 224 Applications: []string{"magic"}, 225 }) 226 c.Assert(called, jc.IsTrue) 227 } 228 229 func (s *runSuite) TestRunOnAllMachines(c *gc.C) { 230 // We only test that we create the actions correctly 231 // There is no need to test anything else at this level. 232 expectedPayload := map[string]interface{}{ 233 "command": "hostname", 234 "timeout": testing.LongWait.Nanoseconds(), 235 } 236 expectedArgs := params.Actions{ 237 Actions: []params.Action{ 238 {Receiver: "machine-0", Name: "juju-run", Parameters: expectedPayload}, 239 {Receiver: "machine-1", Name: "juju-run", Parameters: expectedPayload}, 240 {Receiver: "machine-2", Name: "juju-run", Parameters: expectedPayload}, 241 }, 242 } 243 called := false 244 s.PatchValue(action.QueueActions, func(client *action.ActionAPI, args params.Actions) (params.ActionResults, error) { 245 called = true 246 c.Assert(args, jc.DeepEquals, expectedArgs) 247 return params.ActionResults{}, nil 248 }) 249 // Make three machines. 250 s.addMachine(c) 251 s.addMachine(c) 252 s.addMachine(c) 253 254 s.client.RunOnAllMachines( 255 params.RunParams{ 256 Commands: "hostname", 257 Timeout: testing.LongWait, 258 }) 259 c.Assert(called, jc.IsTrue) 260 } 261 262 func (s *runSuite) TestRunRequiresAdmin(c *gc.C) { 263 alpha := names.NewUserTag("alpha@bravo") 264 auth := apiservertesting.FakeAuthorizer{ 265 Tag: alpha, 266 HasWriteTag: alpha, 267 } 268 client, err := action.NewActionAPI(s.State, nil, auth) 269 c.Assert(err, jc.ErrorIsNil) 270 _, err = client.Run(params.RunParams{}) 271 c.Assert(errors.Cause(err), gc.Equals, common.ErrPerm) 272 273 auth.AdminTag = alpha 274 client, err = action.NewActionAPI(s.State, nil, auth) 275 c.Assert(err, jc.ErrorIsNil) 276 _, err = client.Run(params.RunParams{}) 277 c.Assert(err, jc.ErrorIsNil) 278 } 279 280 func (s *runSuite) TestRunOnAllMachinesRequiresAdmin(c *gc.C) { 281 alpha := names.NewUserTag("alpha@bravo") 282 auth := apiservertesting.FakeAuthorizer{ 283 Tag: alpha, 284 HasWriteTag: alpha, 285 } 286 client, err := action.NewActionAPI(s.State, nil, auth) 287 c.Assert(err, jc.ErrorIsNil) 288 _, err = client.RunOnAllMachines(params.RunParams{}) 289 c.Assert(errors.Cause(err), gc.Equals, common.ErrPerm) 290 291 auth.AdminTag = alpha 292 client, err = action.NewActionAPI(s.State, nil, auth) 293 c.Assert(err, jc.ErrorIsNil) 294 _, err = client.RunOnAllMachines(params.RunParams{}) 295 c.Assert(err, jc.ErrorIsNil) 296 }