github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/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 "github.com/juju/errors" 11 "github.com/juju/names" 12 jc "github.com/juju/testing/checkers" 13 gc "launchpad.net/gocheck" 14 15 "github.com/juju/juju/instance" 16 "github.com/juju/juju/juju/testing" 17 "github.com/juju/juju/state" 18 "github.com/juju/juju/state/api/params" 19 "github.com/juju/juju/state/apiserver/common" 20 "github.com/juju/juju/state/apiserver/deployer" 21 apiservertesting "github.com/juju/juju/state/apiserver/testing" 22 statetesting "github.com/juju/juju/state/testing" 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.Service 36 service1 *state.Service 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.JobManageEnviron, state.JobHostUnits) 58 c.Assert(err, gc.IsNil) 59 60 s.machine1, err = s.State.AddMachine("quantal", state.JobHostUnits) 61 c.Assert(err, gc.IsNil) 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([]string{"mysql", "logging"}) 67 c.Assert(err, gc.IsNil) 68 rel, err := s.State.AddRelation(eps...) 69 c.Assert(err, gc.IsNil) 70 71 s.principal0, err = s.service0.AddUnit() 72 c.Assert(err, gc.IsNil) 73 err = s.principal0.AssignToMachine(s.machine1) 74 c.Assert(err, gc.IsNil) 75 76 s.principal1, err = s.service0.AddUnit() 77 c.Assert(err, gc.IsNil) 78 err = s.principal1.AssignToMachine(s.machine0) 79 c.Assert(err, gc.IsNil) 80 81 relUnit0, err := rel.Unit(s.principal0) 82 c.Assert(err, gc.IsNil) 83 err = relUnit0.EnterScope(nil) 84 c.Assert(err, gc.IsNil) 85 s.subordinate0, err = s.service1.Unit("logging/0") 86 c.Assert(err, gc.IsNil) 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: names.MachineTag(s.machine1.Id()), 92 LoggedIn: true, 93 MachineAgent: true, 94 } 95 96 // Create the resource registry separately to track invocations to 97 // Register. 98 s.resources = common.NewResources() 99 100 // Create a deployer API for machine 1. 101 deployer, err := deployer.NewDeployerAPI( 102 s.State, 103 s.resources, 104 s.authorizer, 105 ) 106 c.Assert(err, gc.IsNil) 107 s.deployer = deployer 108 } 109 110 func (s *deployerSuite) TestDeployerFailsWithNonMachineAgentUser(c *gc.C) { 111 anAuthorizer := s.authorizer 112 anAuthorizer.MachineAgent = false 113 aDeployer, err := deployer.NewDeployerAPI(s.State, s.resources, anAuthorizer) 114 c.Assert(err, gc.NotNil) 115 c.Assert(aDeployer, gc.IsNil) 116 c.Assert(err, gc.ErrorMatches, "permission denied") 117 } 118 119 func (s *deployerSuite) TestWatchUnits(c *gc.C) { 120 c.Assert(s.resources.Count(), gc.Equals, 0) 121 122 args := params.Entities{Entities: []params.Entity{ 123 {Tag: "machine-1"}, 124 {Tag: "machine-0"}, 125 {Tag: "machine-42"}, 126 }} 127 result, err := s.deployer.WatchUnits(args) 128 c.Assert(err, gc.IsNil) 129 sort.Strings(result.Results[0].Changes) 130 c.Assert(result, gc.DeepEquals, params.StringsWatchResults{ 131 Results: []params.StringsWatchResult{ 132 {Changes: []string{"logging/0", "mysql/0"}, StringsWatcherId: "1"}, 133 {Error: apiservertesting.ErrUnauthorized}, 134 {Error: apiservertesting.ErrUnauthorized}, 135 }, 136 }) 137 138 // Verify the resource was registered and stop when done 139 c.Assert(s.resources.Count(), gc.Equals, 1) 140 c.Assert(result.Results[0].StringsWatcherId, gc.Equals, "1") 141 resource := s.resources.Get("1") 142 defer statetesting.AssertStop(c, resource) 143 144 // Check that the Watch has consumed the initial event ("returned" in 145 // the Watch call) 146 wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher)) 147 wc.AssertNoChange() 148 } 149 150 func (s *deployerSuite) TestSetPasswords(c *gc.C) { 151 args := params.EntityPasswords{ 152 Changes: []params.EntityPassword{ 153 {Tag: "unit-mysql-0", Password: "xxx-12345678901234567890"}, 154 {Tag: "unit-mysql-1", Password: "yyy-12345678901234567890"}, 155 {Tag: "unit-logging-0", Password: "zzz-12345678901234567890"}, 156 {Tag: "unit-fake-42", Password: "abc-12345678901234567890"}, 157 }, 158 } 159 results, err := s.deployer.SetPasswords(args) 160 c.Assert(err, gc.IsNil) 161 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 162 Results: []params.ErrorResult{ 163 {nil}, 164 {apiservertesting.ErrUnauthorized}, 165 {nil}, 166 {apiservertesting.ErrUnauthorized}, 167 }, 168 }) 169 err = s.principal0.Refresh() 170 c.Assert(err, gc.IsNil) 171 changed := s.principal0.PasswordValid("xxx-12345678901234567890") 172 c.Assert(changed, gc.Equals, true) 173 err = s.subordinate0.Refresh() 174 c.Assert(err, gc.IsNil) 175 changed = s.subordinate0.PasswordValid("zzz-12345678901234567890") 176 c.Assert(changed, gc.Equals, true) 177 178 // Remove the subordinate and make sure it's detected. 179 err = s.subordinate0.EnsureDead() 180 c.Assert(err, gc.IsNil) 181 err = s.subordinate0.Remove() 182 c.Assert(err, gc.IsNil) 183 err = s.subordinate0.Refresh() 184 c.Assert(err, jc.Satisfies, errors.IsNotFound) 185 186 results, err = s.deployer.SetPasswords(params.EntityPasswords{ 187 Changes: []params.EntityPassword{ 188 {Tag: "unit-logging-0", Password: "blah-12345678901234567890"}, 189 }, 190 }) 191 c.Assert(err, gc.IsNil) 192 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 193 Results: []params.ErrorResult{ 194 {apiservertesting.ErrUnauthorized}, 195 }, 196 }) 197 } 198 199 func (s *deployerSuite) TestLife(c *gc.C) { 200 err := s.subordinate0.EnsureDead() 201 c.Assert(err, gc.IsNil) 202 err = s.subordinate0.Refresh() 203 c.Assert(err, gc.IsNil) 204 c.Assert(s.subordinate0.Life(), gc.Equals, state.Dead) 205 err = s.principal0.Refresh() 206 c.Assert(err, gc.IsNil) 207 c.Assert(s.principal0.Life(), gc.Equals, state.Alive) 208 209 args := params.Entities{Entities: []params.Entity{ 210 {Tag: "unit-mysql-0"}, 211 {Tag: "unit-mysql-1"}, 212 {Tag: "unit-logging-0"}, 213 {Tag: "unit-fake-42"}, 214 }} 215 result, err := s.deployer.Life(args) 216 c.Assert(err, gc.IsNil) 217 c.Assert(result, gc.DeepEquals, params.LifeResults{ 218 Results: []params.LifeResult{ 219 {Life: "alive"}, 220 {Error: apiservertesting.ErrUnauthorized}, 221 {Life: "dead"}, 222 {Error: apiservertesting.ErrUnauthorized}, 223 }, 224 }) 225 226 // Remove the subordinate and make sure it's detected. 227 err = s.subordinate0.EnsureDead() 228 c.Assert(err, gc.IsNil) 229 err = s.subordinate0.Remove() 230 c.Assert(err, gc.IsNil) 231 err = s.subordinate0.Refresh() 232 c.Assert(err, jc.Satisfies, errors.IsNotFound) 233 234 result, err = s.deployer.Life(params.Entities{ 235 Entities: []params.Entity{ 236 {Tag: "unit-logging-0"}, 237 }, 238 }) 239 c.Assert(err, gc.IsNil) 240 c.Assert(result, gc.DeepEquals, params.LifeResults{ 241 Results: []params.LifeResult{ 242 {Error: apiservertesting.ErrUnauthorized}, 243 }, 244 }) 245 } 246 247 func (s *deployerSuite) TestRemove(c *gc.C) { 248 c.Assert(s.principal0.Life(), gc.Equals, state.Alive) 249 c.Assert(s.subordinate0.Life(), gc.Equals, state.Alive) 250 251 // Try removing alive units - should fail. 252 args := params.Entities{Entities: []params.Entity{ 253 {Tag: "unit-mysql-0"}, 254 {Tag: "unit-mysql-1"}, 255 {Tag: "unit-logging-0"}, 256 {Tag: "unit-fake-42"}, 257 }} 258 result, err := s.deployer.Remove(args) 259 c.Assert(err, gc.IsNil) 260 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 261 Results: []params.ErrorResult{ 262 {¶ms.Error{Message: `cannot remove entity "unit-mysql-0": still alive`}}, 263 {apiservertesting.ErrUnauthorized}, 264 {¶ms.Error{Message: `cannot remove entity "unit-logging-0": still alive`}}, 265 {apiservertesting.ErrUnauthorized}, 266 }, 267 }) 268 269 err = s.principal0.Refresh() 270 c.Assert(err, gc.IsNil) 271 c.Assert(s.principal0.Life(), gc.Equals, state.Alive) 272 err = s.subordinate0.Refresh() 273 c.Assert(err, gc.IsNil) 274 c.Assert(s.subordinate0.Life(), gc.Equals, state.Alive) 275 276 // Now make the subordinate dead and try again. 277 err = s.subordinate0.EnsureDead() 278 c.Assert(err, gc.IsNil) 279 err = s.subordinate0.Refresh() 280 c.Assert(err, gc.IsNil) 281 c.Assert(s.subordinate0.Life(), gc.Equals, state.Dead) 282 283 args = params.Entities{ 284 Entities: []params.Entity{{Tag: "unit-logging-0"}}, 285 } 286 result, err = s.deployer.Remove(args) 287 c.Assert(err, gc.IsNil) 288 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 289 Results: []params.ErrorResult{{nil}}, 290 }) 291 292 err = s.subordinate0.Refresh() 293 c.Assert(err, jc.Satisfies, errors.IsNotFound) 294 295 // Make sure the subordinate is detected as removed. 296 result, err = s.deployer.Remove(args) 297 c.Assert(err, gc.IsNil) 298 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 299 Results: []params.ErrorResult{{apiservertesting.ErrUnauthorized}}, 300 }) 301 } 302 303 func (s *deployerSuite) TestStateAddresses(c *gc.C) { 304 err := s.machine0.SetAddresses(instance.NewAddress("0.1.2.3", instance.NetworkUnknown)) 305 c.Assert(err, gc.IsNil) 306 307 addresses, err := s.State.Addresses() 308 c.Assert(err, gc.IsNil) 309 310 result, err := s.deployer.StateAddresses() 311 c.Assert(err, gc.IsNil) 312 c.Assert(result, gc.DeepEquals, params.StringsResult{ 313 Result: addresses, 314 }) 315 } 316 317 func (s *deployerSuite) TestAPIAddresses(c *gc.C) { 318 hostPorts := [][]instance.HostPort{{{ 319 Address: instance.NewAddress("0.1.2.3", instance.NetworkUnknown), 320 Port: 1234, 321 }}} 322 323 err := s.State.SetAPIHostPorts(hostPorts) 324 c.Assert(err, gc.IsNil) 325 326 result, err := s.deployer.APIAddresses() 327 c.Assert(err, gc.IsNil) 328 c.Assert(result, gc.DeepEquals, params.StringsResult{ 329 Result: []string{"0.1.2.3:1234"}, 330 }) 331 } 332 333 func (s *deployerSuite) TestCACert(c *gc.C) { 334 result := s.deployer.CACert() 335 c.Assert(result, gc.DeepEquals, params.BytesResult{ 336 Result: []byte(s.State.CACert()), 337 }) 338 }