github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/state/apiserver/deployer/deployer_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package deployer_test 5 6 import ( 7 "sort" 8 stdtesting "testing" 9 10 gc "launchpad.net/gocheck" 11 12 "launchpad.net/juju-core/errors" 13 "launchpad.net/juju-core/instance" 14 "launchpad.net/juju-core/juju/testing" 15 "launchpad.net/juju-core/names" 16 "launchpad.net/juju-core/state" 17 "launchpad.net/juju-core/state/api/params" 18 "launchpad.net/juju-core/state/apiserver/common" 19 "launchpad.net/juju-core/state/apiserver/deployer" 20 apiservertesting "launchpad.net/juju-core/state/apiserver/testing" 21 statetesting "launchpad.net/juju-core/state/testing" 22 coretesting "launchpad.net/juju-core/testing" 23 ) 24 25 func Test(t *stdtesting.T) { 26 coretesting.MgoTestPackage(t) 27 } 28 29 type deployerSuite struct { 30 testing.JujuConnSuite 31 32 authorizer apiservertesting.FakeAuthorizer 33 34 service0 *state.Service 35 service1 *state.Service 36 machine0 *state.Machine 37 machine1 *state.Machine 38 principal0 *state.Unit 39 principal1 *state.Unit 40 subordinate0 *state.Unit 41 42 resources *common.Resources 43 deployer *deployer.DeployerAPI 44 } 45 46 var _ = gc.Suite(&deployerSuite{}) 47 48 func (s *deployerSuite) SetUpTest(c *gc.C) { 49 s.JujuConnSuite.SetUpTest(c) 50 51 // The two known machines now contain the following units: 52 // machine 0 (not authorized): mysql/1 (principal1) 53 // machine 1 (authorized): mysql/0 (principal0), logging/0 (subordinate0) 54 55 var err error 56 s.machine0, err = s.State.AddMachine("quantal", state.JobManageEnviron, state.JobHostUnits) 57 c.Assert(err, gc.IsNil) 58 59 s.machine1, err = s.State.AddMachine("quantal", state.JobHostUnits) 60 c.Assert(err, gc.IsNil) 61 62 s.service0 = s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql")) 63 64 s.service1 = s.AddTestingService(c, "logging", s.AddTestingCharm(c, "logging")) 65 eps, err := s.State.InferEndpoints([]string{"mysql", "logging"}) 66 c.Assert(err, gc.IsNil) 67 rel, err := s.State.AddRelation(eps...) 68 c.Assert(err, gc.IsNil) 69 70 s.principal0, err = s.service0.AddUnit() 71 c.Assert(err, gc.IsNil) 72 err = s.principal0.AssignToMachine(s.machine1) 73 c.Assert(err, gc.IsNil) 74 75 s.principal1, err = s.service0.AddUnit() 76 c.Assert(err, gc.IsNil) 77 err = s.principal1.AssignToMachine(s.machine0) 78 c.Assert(err, gc.IsNil) 79 80 relUnit0, err := rel.Unit(s.principal0) 81 c.Assert(err, gc.IsNil) 82 err = relUnit0.EnterScope(nil) 83 c.Assert(err, gc.IsNil) 84 s.subordinate0, err = s.service1.Unit("logging/0") 85 c.Assert(err, gc.IsNil) 86 87 // Create a FakeAuthorizer so we can check permissions, 88 // set up assuming machine 1 has logged in. 89 s.authorizer = apiservertesting.FakeAuthorizer{ 90 Tag: names.MachineTag(s.machine1.Id()), 91 LoggedIn: true, 92 MachineAgent: true, 93 } 94 95 // Create the resource registry separately to track invocations to 96 // Register. 97 s.resources = common.NewResources() 98 99 // Create a deployer API for machine 1. 100 deployer, err := deployer.NewDeployerAPI( 101 s.State, 102 s.resources, 103 s.authorizer, 104 ) 105 c.Assert(err, gc.IsNil) 106 s.deployer = deployer 107 } 108 109 func (s *deployerSuite) TestDeployerFailsWithNonMachineAgentUser(c *gc.C) { 110 anAuthorizer := s.authorizer 111 anAuthorizer.MachineAgent = false 112 aDeployer, err := deployer.NewDeployerAPI(s.State, s.resources, anAuthorizer) 113 c.Assert(err, gc.NotNil) 114 c.Assert(aDeployer, gc.IsNil) 115 c.Assert(err, gc.ErrorMatches, "permission denied") 116 } 117 118 func (s *deployerSuite) TestWatchUnits(c *gc.C) { 119 c.Assert(s.resources.Count(), gc.Equals, 0) 120 121 args := params.Entities{Entities: []params.Entity{ 122 {Tag: "machine-1"}, 123 {Tag: "machine-0"}, 124 {Tag: "machine-42"}, 125 }} 126 result, err := s.deployer.WatchUnits(args) 127 c.Assert(err, gc.IsNil) 128 sort.Strings(result.Results[0].Changes) 129 c.Assert(result, gc.DeepEquals, params.StringsWatchResults{ 130 Results: []params.StringsWatchResult{ 131 {Changes: []string{"logging/0", "mysql/0"}, StringsWatcherId: "1"}, 132 {Error: apiservertesting.ErrUnauthorized}, 133 {Error: apiservertesting.ErrUnauthorized}, 134 }, 135 }) 136 137 // Verify the resource was registered and stop when done 138 c.Assert(s.resources.Count(), gc.Equals, 1) 139 c.Assert(result.Results[0].StringsWatcherId, gc.Equals, "1") 140 resource := s.resources.Get("1") 141 defer statetesting.AssertStop(c, resource) 142 143 // Check that the Watch has consumed the initial event ("returned" in 144 // the Watch call) 145 wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher)) 146 wc.AssertNoChange() 147 } 148 149 func (s *deployerSuite) TestSetPasswords(c *gc.C) { 150 args := params.PasswordChanges{ 151 Changes: []params.PasswordChange{ 152 {Tag: "unit-mysql-0", Password: "xxx-12345678901234567890"}, 153 {Tag: "unit-mysql-1", Password: "yyy-12345678901234567890"}, 154 {Tag: "unit-logging-0", Password: "zzz-12345678901234567890"}, 155 {Tag: "unit-fake-42", Password: "abc-12345678901234567890"}, 156 }, 157 } 158 results, err := s.deployer.SetPasswords(args) 159 c.Assert(err, gc.IsNil) 160 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 161 Results: []params.ErrorResult{ 162 {nil}, 163 {apiservertesting.ErrUnauthorized}, 164 {nil}, 165 {apiservertesting.ErrUnauthorized}, 166 }, 167 }) 168 err = s.principal0.Refresh() 169 c.Assert(err, gc.IsNil) 170 changed := s.principal0.PasswordValid("xxx-12345678901234567890") 171 c.Assert(changed, gc.Equals, true) 172 err = s.subordinate0.Refresh() 173 c.Assert(err, gc.IsNil) 174 changed = s.subordinate0.PasswordValid("zzz-12345678901234567890") 175 c.Assert(changed, gc.Equals, true) 176 177 // Remove the subordinate and make sure it's detected. 178 err = s.subordinate0.EnsureDead() 179 c.Assert(err, gc.IsNil) 180 err = s.subordinate0.Remove() 181 c.Assert(err, gc.IsNil) 182 err = s.subordinate0.Refresh() 183 c.Assert(errors.IsNotFoundError(err), gc.Equals, true) 184 185 results, err = s.deployer.SetPasswords(params.PasswordChanges{ 186 Changes: []params.PasswordChange{ 187 {Tag: "unit-logging-0", Password: "blah-12345678901234567890"}, 188 }, 189 }) 190 c.Assert(err, gc.IsNil) 191 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 192 Results: []params.ErrorResult{ 193 {apiservertesting.ErrUnauthorized}, 194 }, 195 }) 196 } 197 198 func (s *deployerSuite) TestLife(c *gc.C) { 199 err := s.subordinate0.EnsureDead() 200 c.Assert(err, gc.IsNil) 201 err = s.subordinate0.Refresh() 202 c.Assert(err, gc.IsNil) 203 c.Assert(s.subordinate0.Life(), gc.Equals, state.Dead) 204 err = s.principal0.Refresh() 205 c.Assert(err, gc.IsNil) 206 c.Assert(s.principal0.Life(), gc.Equals, state.Alive) 207 208 args := params.Entities{Entities: []params.Entity{ 209 {Tag: "unit-mysql-0"}, 210 {Tag: "unit-mysql-1"}, 211 {Tag: "unit-logging-0"}, 212 {Tag: "unit-fake-42"}, 213 }} 214 result, err := s.deployer.Life(args) 215 c.Assert(err, gc.IsNil) 216 c.Assert(result, gc.DeepEquals, params.LifeResults{ 217 Results: []params.LifeResult{ 218 {Life: "alive"}, 219 {Error: apiservertesting.ErrUnauthorized}, 220 {Life: "dead"}, 221 {Error: apiservertesting.ErrUnauthorized}, 222 }, 223 }) 224 225 // Remove the subordinate and make sure it's detected. 226 err = s.subordinate0.EnsureDead() 227 c.Assert(err, gc.IsNil) 228 err = s.subordinate0.Remove() 229 c.Assert(err, gc.IsNil) 230 err = s.subordinate0.Refresh() 231 c.Assert(errors.IsNotFoundError(err), gc.Equals, true) 232 233 result, err = s.deployer.Life(params.Entities{ 234 Entities: []params.Entity{ 235 {Tag: "unit-logging-0"}, 236 }, 237 }) 238 c.Assert(err, gc.IsNil) 239 c.Assert(result, gc.DeepEquals, params.LifeResults{ 240 Results: []params.LifeResult{ 241 {Error: apiservertesting.ErrUnauthorized}, 242 }, 243 }) 244 } 245 246 func (s *deployerSuite) TestRemove(c *gc.C) { 247 c.Assert(s.principal0.Life(), gc.Equals, state.Alive) 248 c.Assert(s.subordinate0.Life(), gc.Equals, state.Alive) 249 250 // Try removing alive units - should fail. 251 args := params.Entities{Entities: []params.Entity{ 252 {Tag: "unit-mysql-0"}, 253 {Tag: "unit-mysql-1"}, 254 {Tag: "unit-logging-0"}, 255 {Tag: "unit-fake-42"}, 256 }} 257 result, err := s.deployer.Remove(args) 258 c.Assert(err, gc.IsNil) 259 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 260 Results: []params.ErrorResult{ 261 {¶ms.Error{Message: `cannot remove entity "unit-mysql-0": still alive`}}, 262 {apiservertesting.ErrUnauthorized}, 263 {¶ms.Error{Message: `cannot remove entity "unit-logging-0": still alive`}}, 264 {apiservertesting.ErrUnauthorized}, 265 }, 266 }) 267 268 err = s.principal0.Refresh() 269 c.Assert(err, gc.IsNil) 270 c.Assert(s.principal0.Life(), gc.Equals, state.Alive) 271 err = s.subordinate0.Refresh() 272 c.Assert(err, gc.IsNil) 273 c.Assert(s.subordinate0.Life(), gc.Equals, state.Alive) 274 275 // Now make the subordinate dead and try again. 276 err = s.subordinate0.EnsureDead() 277 c.Assert(err, gc.IsNil) 278 err = s.subordinate0.Refresh() 279 c.Assert(err, gc.IsNil) 280 c.Assert(s.subordinate0.Life(), gc.Equals, state.Dead) 281 282 args = params.Entities{ 283 Entities: []params.Entity{{Tag: "unit-logging-0"}}, 284 } 285 result, err = s.deployer.Remove(args) 286 c.Assert(err, gc.IsNil) 287 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 288 Results: []params.ErrorResult{{nil}}, 289 }) 290 291 err = s.subordinate0.Refresh() 292 c.Assert(errors.IsNotFoundError(err), gc.Equals, true) 293 294 // Make sure the subordinate is detected as removed. 295 result, err = s.deployer.Remove(args) 296 c.Assert(err, gc.IsNil) 297 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 298 Results: []params.ErrorResult{{apiservertesting.ErrUnauthorized}}, 299 }) 300 } 301 302 func (s *deployerSuite) TestStateAddresses(c *gc.C) { 303 err := s.machine0.SetAddresses([]instance.Address{ 304 instance.NewAddress("0.1.2.3"), 305 }) 306 c.Assert(err, gc.IsNil) 307 308 addresses, err := s.State.Addresses() 309 c.Assert(err, gc.IsNil) 310 311 result, err := s.deployer.StateAddresses() 312 c.Assert(err, gc.IsNil) 313 c.Assert(result, gc.DeepEquals, params.StringsResult{ 314 Result: addresses, 315 }) 316 } 317 318 func (s *deployerSuite) TestAPIAddresses(c *gc.C) { 319 err := s.machine0.SetAddresses([]instance.Address{ 320 instance.NewAddress("0.1.2.3"), 321 }) 322 c.Assert(err, gc.IsNil) 323 324 apiAddresses, err := s.State.APIAddresses() 325 c.Assert(err, gc.IsNil) 326 327 result, err := s.deployer.APIAddresses() 328 c.Assert(err, gc.IsNil) 329 c.Assert(result, gc.DeepEquals, params.StringsResult{ 330 Result: apiAddresses, 331 }) 332 } 333 334 func (s *deployerSuite) TestCACert(c *gc.C) { 335 result := s.deployer.CACert() 336 c.Assert(result, gc.DeepEquals, params.BytesResult{ 337 Result: s.State.CACert(), 338 }) 339 }