github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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 "github.com/juju/errors" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 14 "github.com/juju/juju/apiserver/common" 15 "github.com/juju/juju/apiserver/deployer" 16 "github.com/juju/juju/apiserver/params" 17 apiservertesting "github.com/juju/juju/apiserver/testing" 18 "github.com/juju/juju/juju/testing" 19 "github.com/juju/juju/network" 20 "github.com/juju/juju/state" 21 statetesting "github.com/juju/juju/state/testing" 22 "github.com/juju/juju/status" 23 coretesting "github.com/juju/juju/testing" 24 ) 25 26 func Test(t *stdtesting.T) { 27 coretesting.MgoTestPackage(t) 28 } 29 30 type deployerSuite struct { 31 testing.JujuConnSuite 32 33 authorizer apiservertesting.FakeAuthorizer 34 35 service0 *state.Application 36 service1 *state.Application 37 machine0 *state.Machine 38 machine1 *state.Machine 39 principal0 *state.Unit 40 principal1 *state.Unit 41 subordinate0 *state.Unit 42 43 resources *common.Resources 44 deployer *deployer.DeployerAPI 45 } 46 47 var _ = gc.Suite(&deployerSuite{}) 48 49 func (s *deployerSuite) SetUpTest(c *gc.C) { 50 s.JujuConnSuite.SetUpTest(c) 51 52 // The two known machines now contain the following units: 53 // machine 0 (not authorized): mysql/1 (principal1) 54 // machine 1 (authorized): mysql/0 (principal0), logging/0 (subordinate0) 55 56 var err error 57 s.machine0, err = s.State.AddMachine("quantal", state.JobManageModel, state.JobHostUnits) 58 c.Assert(err, jc.ErrorIsNil) 59 60 s.machine1, err = s.State.AddMachine("quantal", state.JobHostUnits) 61 c.Assert(err, jc.ErrorIsNil) 62 63 s.service0 = s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql")) 64 65 s.service1 = s.AddTestingService(c, "logging", s.AddTestingCharm(c, "logging")) 66 eps, err := s.State.InferEndpoints("mysql", "logging") 67 c.Assert(err, jc.ErrorIsNil) 68 rel, err := s.State.AddRelation(eps...) 69 c.Assert(err, jc.ErrorIsNil) 70 71 s.principal0, err = s.service0.AddUnit() 72 c.Assert(err, jc.ErrorIsNil) 73 err = s.principal0.AssignToMachine(s.machine1) 74 c.Assert(err, jc.ErrorIsNil) 75 76 s.principal1, err = s.service0.AddUnit() 77 c.Assert(err, jc.ErrorIsNil) 78 err = s.principal1.AssignToMachine(s.machine0) 79 c.Assert(err, jc.ErrorIsNil) 80 81 relUnit0, err := rel.Unit(s.principal0) 82 c.Assert(err, jc.ErrorIsNil) 83 err = relUnit0.EnterScope(nil) 84 c.Assert(err, jc.ErrorIsNil) 85 s.subordinate0, err = s.State.Unit("logging/0") 86 c.Assert(err, jc.ErrorIsNil) 87 88 // Create a FakeAuthorizer so we can check permissions, 89 // set up assuming machine 1 has logged in. 90 s.authorizer = apiservertesting.FakeAuthorizer{ 91 Tag: s.machine1.Tag(), 92 } 93 94 // Create the resource registry separately to track invocations to 95 // Register. 96 s.resources = common.NewResources() 97 s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() }) 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, jc.ErrorIsNil) 106 s.deployer = deployer 107 } 108 109 func (s *deployerSuite) TestDeployerFailsWithNonMachineAgentUser(c *gc.C) { 110 anAuthorizer := s.authorizer 111 anAuthorizer.Tag = s.AdminUserTag(c) 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, jc.ErrorIsNil) 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.EntityPasswords{ 151 Changes: []params.EntityPassword{ 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, jc.ErrorIsNil) 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, jc.ErrorIsNil) 170 changed := s.principal0.PasswordValid("xxx-12345678901234567890") 171 c.Assert(changed, jc.IsTrue) 172 err = s.subordinate0.Refresh() 173 c.Assert(err, jc.ErrorIsNil) 174 changed = s.subordinate0.PasswordValid("zzz-12345678901234567890") 175 c.Assert(changed, jc.IsTrue) 176 177 // Remove the subordinate and make sure it's detected. 178 err = s.subordinate0.EnsureDead() 179 c.Assert(err, jc.ErrorIsNil) 180 err = s.subordinate0.Remove() 181 c.Assert(err, jc.ErrorIsNil) 182 err = s.subordinate0.Refresh() 183 c.Assert(err, jc.Satisfies, errors.IsNotFound) 184 185 results, err = s.deployer.SetPasswords(params.EntityPasswords{ 186 Changes: []params.EntityPassword{ 187 {Tag: "unit-logging-0", Password: "blah-12345678901234567890"}, 188 }, 189 }) 190 c.Assert(err, jc.ErrorIsNil) 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, jc.ErrorIsNil) 201 err = s.subordinate0.Refresh() 202 c.Assert(err, jc.ErrorIsNil) 203 c.Assert(s.subordinate0.Life(), gc.Equals, state.Dead) 204 err = s.principal0.Refresh() 205 c.Assert(err, jc.ErrorIsNil) 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, jc.ErrorIsNil) 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, jc.ErrorIsNil) 228 err = s.subordinate0.Remove() 229 c.Assert(err, jc.ErrorIsNil) 230 err = s.subordinate0.Refresh() 231 c.Assert(err, jc.Satisfies, errors.IsNotFound) 232 233 result, err = s.deployer.Life(params.Entities{ 234 Entities: []params.Entity{ 235 {Tag: "unit-logging-0"}, 236 }, 237 }) 238 c.Assert(err, jc.ErrorIsNil) 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, jc.ErrorIsNil) 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, jc.ErrorIsNil) 270 c.Assert(s.principal0.Life(), gc.Equals, state.Alive) 271 err = s.subordinate0.Refresh() 272 c.Assert(err, jc.ErrorIsNil) 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, jc.ErrorIsNil) 278 err = s.subordinate0.Refresh() 279 c.Assert(err, jc.ErrorIsNil) 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, jc.ErrorIsNil) 287 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 288 Results: []params.ErrorResult{{nil}}, 289 }) 290 291 err = s.subordinate0.Refresh() 292 c.Assert(err, jc.Satisfies, errors.IsNotFound) 293 294 // Make sure the subordinate is detected as removed. 295 result, err = s.deployer.Remove(args) 296 c.Assert(err, jc.ErrorIsNil) 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.SetProviderAddresses(network.NewAddress("0.1.2.3")) 304 c.Assert(err, jc.ErrorIsNil) 305 306 addresses, err := s.State.Addresses() 307 c.Assert(err, jc.ErrorIsNil) 308 309 result, err := s.deployer.StateAddresses() 310 c.Assert(err, jc.ErrorIsNil) 311 c.Assert(result, gc.DeepEquals, params.StringsResult{ 312 Result: addresses, 313 }) 314 } 315 316 func (s *deployerSuite) TestAPIAddresses(c *gc.C) { 317 hostPorts := [][]network.HostPort{ 318 network.NewHostPorts(1234, "0.1.2.3"), 319 } 320 err := s.State.SetAPIHostPorts(hostPorts) 321 c.Assert(err, jc.ErrorIsNil) 322 323 result, err := s.deployer.APIAddresses() 324 c.Assert(err, jc.ErrorIsNil) 325 c.Assert(result, gc.DeepEquals, params.StringsResult{ 326 Result: []string{"0.1.2.3:1234"}, 327 }) 328 } 329 330 func (s *deployerSuite) TestCACert(c *gc.C) { 331 result := s.deployer.CACert() 332 c.Assert(result, gc.DeepEquals, params.BytesResult{ 333 Result: []byte(s.State.CACert()), 334 }) 335 } 336 337 func (s *deployerSuite) TestConnectionInfo(c *gc.C) { 338 err := s.machine0.SetProviderAddresses(network.NewScopedAddress("0.1.2.3", network.ScopePublic), 339 network.NewScopedAddress("1.2.3.4", network.ScopeCloudLocal)) 340 c.Assert(err, jc.ErrorIsNil) 341 342 // Default host port scope is public, so change the cloud-local one 343 hostPorts := network.NewHostPorts(1234, "0.1.2.3", "1.2.3.4") 344 hostPorts[1].Scope = network.ScopeCloudLocal 345 346 err = s.State.SetAPIHostPorts([][]network.HostPort{hostPorts}) 347 c.Assert(err, jc.ErrorIsNil) 348 349 expected := params.DeployerConnectionValues{ 350 StateAddresses: []string{"1.2.3.4:1234"}, 351 APIAddresses: []string{"1.2.3.4:1234", "0.1.2.3:1234"}, 352 } 353 354 result, err := s.deployer.ConnectionInfo() 355 c.Assert(err, jc.ErrorIsNil) 356 c.Assert(result, gc.DeepEquals, expected) 357 } 358 359 func (s *deployerSuite) TestSetStatus(c *gc.C) { 360 args := params.SetStatus{ 361 Entities: []params.EntityStatusArgs{ 362 {Tag: "unit-mysql-0", Status: "blocked", Info: "waiting", Data: map[string]interface{}{"foo": "bar"}}, 363 {Tag: "unit-mysql-1", Status: "blocked", Info: "waiting", Data: map[string]interface{}{"foo": "bar"}}, 364 {Tag: "unit-fake-42", Status: "blocked", Info: "waiting", Data: map[string]interface{}{"foo": "bar"}}, 365 }, 366 } 367 results, err := s.deployer.SetStatus(args) 368 c.Assert(err, jc.ErrorIsNil) 369 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 370 Results: []params.ErrorResult{ 371 {nil}, 372 {apiservertesting.ErrUnauthorized}, 373 {apiservertesting.ErrUnauthorized}, 374 }, 375 }) 376 sInfo, err := s.principal0.Status() 377 c.Assert(err, jc.ErrorIsNil) 378 sInfo.Since = nil 379 c.Assert(sInfo, jc.DeepEquals, status.StatusInfo{ 380 Status: status.Blocked, 381 Message: "waiting", 382 Data: map[string]interface{}{"foo": "bar"}, 383 }) 384 }