github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/state/apiserver/uniter/uniter_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package uniter_test 5 6 import ( 7 stdtesting "testing" 8 9 "github.com/juju/errors" 10 jc "github.com/juju/testing/checkers" 11 gc "launchpad.net/gocheck" 12 13 "github.com/juju/juju/charm" 14 envtesting "github.com/juju/juju/environs/testing" 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 commontesting "github.com/juju/juju/state/apiserver/common/testing" 21 apiservertesting "github.com/juju/juju/state/apiserver/testing" 22 "github.com/juju/juju/state/apiserver/uniter" 23 statetesting "github.com/juju/juju/state/testing" 24 coretesting "github.com/juju/juju/testing" 25 ) 26 27 func Test(t *stdtesting.T) { 28 coretesting.MgoTestPackage(t) 29 } 30 31 type uniterSuite struct { 32 testing.JujuConnSuite 33 *commontesting.EnvironWatcherTest 34 35 authorizer apiservertesting.FakeAuthorizer 36 resources *common.Resources 37 38 machine0 *state.Machine 39 machine1 *state.Machine 40 wordpress *state.Service 41 wpCharm *state.Charm 42 mysql *state.Service 43 wordpressUnit *state.Unit 44 mysqlUnit *state.Unit 45 46 uniter *uniter.UniterAPI 47 } 48 49 var _ = gc.Suite(&uniterSuite{}) 50 51 func (s *uniterSuite) SetUpTest(c *gc.C) { 52 s.JujuConnSuite.SetUpTest(c) 53 54 s.wpCharm = s.AddTestingCharm(c, "wordpress") 55 // Create two machines, two services and add a unit to each service. 56 var err error 57 s.machine0, err = s.State.AddMachine("quantal", state.JobHostUnits, state.JobManageEnviron) 58 c.Assert(err, gc.IsNil) 59 s.machine1, err = s.State.AddMachine("quantal", state.JobHostUnits) 60 c.Assert(err, gc.IsNil) 61 s.wordpress = s.AddTestingService(c, "wordpress", s.wpCharm) 62 s.mysql = s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql")) 63 s.wordpressUnit, err = s.wordpress.AddUnit() 64 c.Assert(err, gc.IsNil) 65 s.mysqlUnit, err = s.mysql.AddUnit() 66 c.Assert(err, gc.IsNil) 67 // Assign each unit to each machine. 68 err = s.wordpressUnit.AssignToMachine(s.machine0) 69 c.Assert(err, gc.IsNil) 70 err = s.mysqlUnit.AssignToMachine(s.machine1) 71 c.Assert(err, gc.IsNil) 72 73 // Create a FakeAuthorizer so we can check permissions, 74 // set up assuming unit 0 has logged in. 75 s.authorizer = apiservertesting.FakeAuthorizer{ 76 Tag: s.wordpressUnit.Tag(), 77 LoggedIn: true, 78 UnitAgent: true, 79 Entity: s.wordpressUnit, 80 } 81 82 // Create the resource registry separately to track invocations to 83 // Register. 84 s.resources = common.NewResources() 85 86 // Create a uniter API for unit 0. 87 s.uniter, err = uniter.NewUniterAPI( 88 s.State, 89 s.resources, 90 s.authorizer, 91 ) 92 c.Assert(err, gc.IsNil) 93 s.EnvironWatcherTest = commontesting.NewEnvironWatcherTest(s.uniter, s.State, s.resources, commontesting.NoSecrets) 94 } 95 96 func (s *uniterSuite) TestUniterFailsWithNonUnitAgentUser(c *gc.C) { 97 anAuthorizer := s.authorizer 98 anAuthorizer.UnitAgent = false 99 anUniter, err := uniter.NewUniterAPI(s.State, s.resources, anAuthorizer) 100 c.Assert(err, gc.NotNil) 101 c.Assert(anUniter, gc.IsNil) 102 c.Assert(err, gc.ErrorMatches, "permission denied") 103 } 104 105 func (s *uniterSuite) TestSetStatus(c *gc.C) { 106 err := s.wordpressUnit.SetStatus(params.StatusStarted, "blah", nil) 107 c.Assert(err, gc.IsNil) 108 err = s.mysqlUnit.SetStatus(params.StatusStopped, "foo", nil) 109 c.Assert(err, gc.IsNil) 110 111 args := params.SetStatus{ 112 Entities: []params.EntityStatus{ 113 {Tag: "unit-mysql-0", Status: params.StatusError, Info: "not really"}, 114 {Tag: "unit-wordpress-0", Status: params.StatusStopped, Info: "foobar"}, 115 {Tag: "unit-foo-42", Status: params.StatusStarted, Info: "blah"}, 116 }} 117 result, err := s.uniter.SetStatus(args) 118 c.Assert(err, gc.IsNil) 119 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 120 Results: []params.ErrorResult{ 121 {apiservertesting.ErrUnauthorized}, 122 {nil}, 123 {apiservertesting.ErrUnauthorized}, 124 }, 125 }) 126 127 // Verify mysqlUnit - no change. 128 status, info, _, err := s.mysqlUnit.Status() 129 c.Assert(err, gc.IsNil) 130 c.Assert(status, gc.Equals, params.StatusStopped) 131 c.Assert(info, gc.Equals, "foo") 132 // ...wordpressUnit is fine though. 133 status, info, _, err = s.wordpressUnit.Status() 134 c.Assert(err, gc.IsNil) 135 c.Assert(status, gc.Equals, params.StatusStopped) 136 c.Assert(info, gc.Equals, "foobar") 137 } 138 139 func (s *uniterSuite) TestLife(c *gc.C) { 140 // Add a relation wordpress-mysql. 141 rel := s.addRelation(c, "wordpress", "mysql") 142 relUnit, err := rel.Unit(s.wordpressUnit) 143 c.Assert(err, gc.IsNil) 144 err = relUnit.EnterScope(nil) 145 c.Assert(err, gc.IsNil) 146 c.Assert(rel.Life(), gc.Equals, state.Alive) 147 148 // Make the wordpressUnit dead. 149 err = s.wordpressUnit.EnsureDead() 150 c.Assert(err, gc.IsNil) 151 err = s.wordpressUnit.Refresh() 152 c.Assert(err, gc.IsNil) 153 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Dead) 154 155 // Add another unit, so the service will stay dying when we 156 // destroy it later. 157 extraUnit, err := s.wordpress.AddUnit() 158 c.Assert(err, gc.IsNil) 159 c.Assert(extraUnit, gc.NotNil) 160 161 // Make the wordpress service dying. 162 err = s.wordpress.Destroy() 163 c.Assert(err, gc.IsNil) 164 err = s.wordpress.Refresh() 165 c.Assert(err, gc.IsNil) 166 c.Assert(s.wordpress.Life(), gc.Equals, state.Dying) 167 168 args := params.Entities{Entities: []params.Entity{ 169 {Tag: "unit-mysql-0"}, 170 {Tag: "unit-wordpress-0"}, 171 {Tag: "unit-foo-42"}, 172 {Tag: "service-mysql"}, 173 {Tag: "service-wordpress"}, 174 {Tag: "service-foo"}, 175 {Tag: "just-foo"}, 176 {Tag: rel.Tag()}, 177 {Tag: "relation-svc1.rel1#svc2.rel2"}, 178 {Tag: "relation-blah"}, 179 }} 180 result, err := s.uniter.Life(args) 181 c.Assert(err, gc.IsNil) 182 c.Assert(result, gc.DeepEquals, params.LifeResults{ 183 Results: []params.LifeResult{ 184 {Error: apiservertesting.ErrUnauthorized}, 185 {Life: "dead"}, 186 {Error: apiservertesting.ErrUnauthorized}, 187 {Error: apiservertesting.ErrUnauthorized}, 188 {Life: "dying"}, 189 {Error: apiservertesting.ErrUnauthorized}, 190 {Error: apiservertesting.ErrUnauthorized}, 191 {Error: apiservertesting.ErrUnauthorized}, 192 {Error: apiservertesting.ErrUnauthorized}, 193 {Error: apiservertesting.ErrUnauthorized}, 194 }, 195 }) 196 } 197 198 func (s *uniterSuite) TestEnsureDead(c *gc.C) { 199 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive) 200 c.Assert(s.mysqlUnit.Life(), gc.Equals, state.Alive) 201 202 args := params.Entities{Entities: []params.Entity{ 203 {Tag: "unit-mysql-0"}, 204 {Tag: "unit-wordpress-0"}, 205 {Tag: "unit-foo-42"}, 206 }} 207 result, err := s.uniter.EnsureDead(args) 208 c.Assert(err, gc.IsNil) 209 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 210 Results: []params.ErrorResult{ 211 {apiservertesting.ErrUnauthorized}, 212 {nil}, 213 {apiservertesting.ErrUnauthorized}, 214 }, 215 }) 216 217 err = s.wordpressUnit.Refresh() 218 c.Assert(err, gc.IsNil) 219 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Dead) 220 err = s.mysqlUnit.Refresh() 221 c.Assert(err, gc.IsNil) 222 c.Assert(s.mysqlUnit.Life(), gc.Equals, state.Alive) 223 224 // Try it again on a Dead unit; should work. 225 args = params.Entities{ 226 Entities: []params.Entity{{Tag: "unit-wordpress-0"}}, 227 } 228 result, err = s.uniter.EnsureDead(args) 229 c.Assert(err, gc.IsNil) 230 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 231 Results: []params.ErrorResult{{nil}}, 232 }) 233 234 // Verify Life is unchanged. 235 err = s.wordpressUnit.Refresh() 236 c.Assert(err, gc.IsNil) 237 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Dead) 238 } 239 240 func (s *uniterSuite) assertOneStringsWatcher(c *gc.C, result params.StringsWatchResults, err error) { 241 c.Assert(err, gc.IsNil) 242 c.Assert(result.Results, gc.HasLen, 3) 243 c.Assert(result.Results[0].Error, gc.DeepEquals, apiservertesting.ErrUnauthorized) 244 c.Assert(result.Results[1].StringsWatcherId, gc.Equals, "1") 245 c.Assert(result.Results[1].Changes, gc.NotNil) 246 c.Assert(result.Results[1].Error, gc.IsNil) 247 c.Assert(result.Results[2].Error, gc.DeepEquals, apiservertesting.ErrUnauthorized) 248 249 // Verify the resource was registered and stop when done 250 c.Assert(s.resources.Count(), gc.Equals, 1) 251 resource := s.resources.Get("1") 252 defer statetesting.AssertStop(c, resource) 253 254 // Check that the Watch has consumed the initial event ("returned" in 255 // the Watch call) 256 wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher)) 257 wc.AssertNoChange() 258 } 259 260 func (s *uniterSuite) TestWatch(c *gc.C) { 261 c.Assert(s.resources.Count(), gc.Equals, 0) 262 263 args := params.Entities{Entities: []params.Entity{ 264 {Tag: "unit-mysql-0"}, 265 {Tag: "unit-wordpress-0"}, 266 {Tag: "unit-foo-42"}, 267 {Tag: "service-mysql"}, 268 {Tag: "service-wordpress"}, 269 {Tag: "service-foo"}, 270 {Tag: "just-foo"}, 271 }} 272 result, err := s.uniter.Watch(args) 273 c.Assert(err, gc.IsNil) 274 c.Assert(result, gc.DeepEquals, params.NotifyWatchResults{ 275 Results: []params.NotifyWatchResult{ 276 {Error: apiservertesting.ErrUnauthorized}, 277 {NotifyWatcherId: "1"}, 278 {Error: apiservertesting.ErrUnauthorized}, 279 {Error: apiservertesting.ErrUnauthorized}, 280 {NotifyWatcherId: "2"}, 281 {Error: apiservertesting.ErrUnauthorized}, 282 {Error: apiservertesting.ErrUnauthorized}, 283 }, 284 }) 285 286 // Verify the resource was registered and stop when done 287 c.Assert(s.resources.Count(), gc.Equals, 2) 288 resource1 := s.resources.Get("1") 289 defer statetesting.AssertStop(c, resource1) 290 resource2 := s.resources.Get("2") 291 defer statetesting.AssertStop(c, resource2) 292 293 // Check that the Watch has consumed the initial event ("returned" in 294 // the Watch call) 295 wc := statetesting.NewNotifyWatcherC(c, s.State, resource1.(state.NotifyWatcher)) 296 wc.AssertNoChange() 297 wc = statetesting.NewNotifyWatcherC(c, s.State, resource2.(state.NotifyWatcher)) 298 wc.AssertNoChange() 299 } 300 301 func (s *uniterSuite) TestPublicAddress(c *gc.C) { 302 // Try first without setting an address. 303 args := params.Entities{Entities: []params.Entity{ 304 {Tag: "unit-mysql-0"}, 305 {Tag: "unit-wordpress-0"}, 306 {Tag: "unit-foo-42"}, 307 }} 308 expectErr := ¶ms.Error{ 309 Code: params.CodeNoAddressSet, 310 Message: `"unit-wordpress-0" has no public address set`, 311 } 312 result, err := s.uniter.PublicAddress(args) 313 c.Assert(err, gc.IsNil) 314 c.Assert(result, gc.DeepEquals, params.StringResults{ 315 Results: []params.StringResult{ 316 {Error: apiservertesting.ErrUnauthorized}, 317 {Error: expectErr}, 318 {Error: apiservertesting.ErrUnauthorized}, 319 }, 320 }) 321 322 // Now set it an try again. 323 err = s.machine0.SetAddresses(instance.NewAddress("1.2.3.4", instance.NetworkPublic)) 324 c.Assert(err, gc.IsNil) 325 address, ok := s.wordpressUnit.PublicAddress() 326 c.Assert(address, gc.Equals, "1.2.3.4") 327 c.Assert(ok, jc.IsTrue) 328 329 result, err = s.uniter.PublicAddress(args) 330 c.Assert(err, gc.IsNil) 331 c.Assert(result, gc.DeepEquals, params.StringResults{ 332 Results: []params.StringResult{ 333 {Error: apiservertesting.ErrUnauthorized}, 334 {Result: "1.2.3.4"}, 335 {Error: apiservertesting.ErrUnauthorized}, 336 }, 337 }) 338 } 339 340 func (s *uniterSuite) TestPrivateAddress(c *gc.C) { 341 args := params.Entities{Entities: []params.Entity{ 342 {Tag: "unit-mysql-0"}, 343 {Tag: "unit-wordpress-0"}, 344 {Tag: "unit-foo-42"}, 345 }} 346 expectErr := ¶ms.Error{ 347 Code: params.CodeNoAddressSet, 348 Message: `"unit-wordpress-0" has no private address set`, 349 } 350 result, err := s.uniter.PrivateAddress(args) 351 c.Assert(err, gc.IsNil) 352 c.Assert(result, gc.DeepEquals, params.StringResults{ 353 Results: []params.StringResult{ 354 {Error: apiservertesting.ErrUnauthorized}, 355 {Error: expectErr}, 356 {Error: apiservertesting.ErrUnauthorized}, 357 }, 358 }) 359 360 // Now set it and try again. 361 err = s.machine0.SetAddresses(instance.NewAddress("1.2.3.4", instance.NetworkCloudLocal)) 362 c.Assert(err, gc.IsNil) 363 address, ok := s.wordpressUnit.PrivateAddress() 364 c.Assert(address, gc.Equals, "1.2.3.4") 365 c.Assert(ok, jc.IsTrue) 366 367 result, err = s.uniter.PrivateAddress(args) 368 c.Assert(err, gc.IsNil) 369 c.Assert(result, gc.DeepEquals, params.StringResults{ 370 Results: []params.StringResult{ 371 {Error: apiservertesting.ErrUnauthorized}, 372 {Result: "1.2.3.4"}, 373 {Error: apiservertesting.ErrUnauthorized}, 374 }, 375 }) 376 } 377 378 func (s *uniterSuite) TestResolved(c *gc.C) { 379 err := s.wordpressUnit.SetResolved(state.ResolvedRetryHooks) 380 c.Assert(err, gc.IsNil) 381 mode := s.wordpressUnit.Resolved() 382 c.Assert(mode, gc.Equals, state.ResolvedRetryHooks) 383 384 args := params.Entities{Entities: []params.Entity{ 385 {Tag: "unit-mysql-0"}, 386 {Tag: "unit-wordpress-0"}, 387 {Tag: "unit-foo-42"}, 388 }} 389 result, err := s.uniter.Resolved(args) 390 c.Assert(err, gc.IsNil) 391 c.Assert(result, gc.DeepEquals, params.ResolvedModeResults{ 392 Results: []params.ResolvedModeResult{ 393 {Error: apiservertesting.ErrUnauthorized}, 394 {Mode: params.ResolvedMode(mode)}, 395 {Error: apiservertesting.ErrUnauthorized}, 396 }, 397 }) 398 } 399 400 func (s *uniterSuite) TestClearResolved(c *gc.C) { 401 err := s.wordpressUnit.SetResolved(state.ResolvedRetryHooks) 402 c.Assert(err, gc.IsNil) 403 mode := s.wordpressUnit.Resolved() 404 c.Assert(mode, gc.Equals, state.ResolvedRetryHooks) 405 406 args := params.Entities{Entities: []params.Entity{ 407 {Tag: "unit-mysql-0"}, 408 {Tag: "unit-wordpress-0"}, 409 {Tag: "unit-foo-42"}, 410 }} 411 result, err := s.uniter.ClearResolved(args) 412 c.Assert(err, gc.IsNil) 413 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 414 Results: []params.ErrorResult{ 415 {apiservertesting.ErrUnauthorized}, 416 {nil}, 417 {apiservertesting.ErrUnauthorized}, 418 }, 419 }) 420 421 // Verify wordpressUnit's resolved mode has changed. 422 err = s.wordpressUnit.Refresh() 423 c.Assert(err, gc.IsNil) 424 mode = s.wordpressUnit.Resolved() 425 c.Assert(mode, gc.Equals, state.ResolvedNone) 426 } 427 428 func (s *uniterSuite) TestGetPrincipal(c *gc.C) { 429 // Add a subordinate to wordpressUnit. 430 _, _, subordinate := s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit) 431 432 principal, ok := subordinate.PrincipalName() 433 c.Assert(principal, gc.Equals, s.wordpressUnit.Name()) 434 c.Assert(ok, jc.IsTrue) 435 436 // First try it as wordpressUnit's agent. 437 args := params.Entities{Entities: []params.Entity{ 438 {Tag: "unit-mysql-0"}, 439 {Tag: "unit-wordpress-0"}, 440 {Tag: subordinate.Tag()}, 441 {Tag: "unit-foo-42"}, 442 }} 443 result, err := s.uniter.GetPrincipal(args) 444 c.Assert(err, gc.IsNil) 445 c.Assert(result, gc.DeepEquals, params.StringBoolResults{ 446 Results: []params.StringBoolResult{ 447 {Error: apiservertesting.ErrUnauthorized}, 448 {Result: "", Ok: false, Error: nil}, 449 {Error: apiservertesting.ErrUnauthorized}, 450 {Error: apiservertesting.ErrUnauthorized}, 451 }, 452 }) 453 454 // Now try as subordinate's agent. 455 subAuthorizer := s.authorizer 456 subAuthorizer.Tag = subordinate.Tag() 457 subUniter, err := uniter.NewUniterAPI(s.State, s.resources, subAuthorizer) 458 c.Assert(err, gc.IsNil) 459 460 result, err = subUniter.GetPrincipal(args) 461 c.Assert(err, gc.IsNil) 462 c.Assert(result, gc.DeepEquals, params.StringBoolResults{ 463 Results: []params.StringBoolResult{ 464 {Error: apiservertesting.ErrUnauthorized}, 465 {Error: apiservertesting.ErrUnauthorized}, 466 {Result: "unit-wordpress-0", Ok: true, Error: nil}, 467 {Error: apiservertesting.ErrUnauthorized}, 468 }, 469 }) 470 } 471 472 func (s *uniterSuite) addRelatedService(c *gc.C, firstSvc, relatedSvc string, unit *state.Unit) (*state.Relation, *state.Service, *state.Unit) { 473 relatedService := s.AddTestingService(c, relatedSvc, s.AddTestingCharm(c, relatedSvc)) 474 rel := s.addRelation(c, firstSvc, relatedSvc) 475 relUnit, err := rel.Unit(unit) 476 c.Assert(err, gc.IsNil) 477 err = relUnit.EnterScope(nil) 478 c.Assert(err, gc.IsNil) 479 relatedUnit, err := relatedService.Unit(relatedSvc + "/0") 480 c.Assert(err, gc.IsNil) 481 return rel, relatedService, relatedUnit 482 } 483 484 func (s *uniterSuite) TestHasSubordinates(c *gc.C) { 485 // Try first without any subordinates for wordpressUnit. 486 args := params.Entities{Entities: []params.Entity{ 487 {Tag: "unit-mysql-0"}, 488 {Tag: "unit-wordpress-0"}, 489 {Tag: "unit-logging-0"}, 490 {Tag: "unit-foo-42"}, 491 }} 492 result, err := s.uniter.HasSubordinates(args) 493 c.Assert(err, gc.IsNil) 494 c.Assert(result, gc.DeepEquals, params.BoolResults{ 495 Results: []params.BoolResult{ 496 {Error: apiservertesting.ErrUnauthorized}, 497 {Result: false}, 498 {Error: apiservertesting.ErrUnauthorized}, 499 {Error: apiservertesting.ErrUnauthorized}, 500 }, 501 }) 502 503 // Add two subordinates to wordpressUnit and try again. 504 s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit) 505 s.addRelatedService(c, "wordpress", "monitoring", s.wordpressUnit) 506 507 result, err = s.uniter.HasSubordinates(args) 508 c.Assert(err, gc.IsNil) 509 c.Assert(result, gc.DeepEquals, params.BoolResults{ 510 Results: []params.BoolResult{ 511 {Error: apiservertesting.ErrUnauthorized}, 512 {Result: true}, 513 {Error: apiservertesting.ErrUnauthorized}, 514 {Error: apiservertesting.ErrUnauthorized}, 515 }, 516 }) 517 } 518 519 func (s *uniterSuite) TestDestroy(c *gc.C) { 520 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive) 521 522 args := params.Entities{Entities: []params.Entity{ 523 {Tag: "unit-mysql-0"}, 524 {Tag: "unit-wordpress-0"}, 525 {Tag: "unit-foo-42"}, 526 }} 527 result, err := s.uniter.Destroy(args) 528 c.Assert(err, gc.IsNil) 529 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 530 Results: []params.ErrorResult{ 531 {apiservertesting.ErrUnauthorized}, 532 {nil}, 533 {apiservertesting.ErrUnauthorized}, 534 }, 535 }) 536 537 // Verify wordpressUnit is destroyed and removed. 538 err = s.wordpressUnit.Refresh() 539 c.Assert(err, jc.Satisfies, errors.IsNotFound) 540 } 541 542 func (s *uniterSuite) TestDestroyAllSubordinates(c *gc.C) { 543 // Add two subordinates to wordpressUnit. 544 _, _, loggingSub := s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit) 545 _, _, monitoringSub := s.addRelatedService(c, "wordpress", "monitoring", s.wordpressUnit) 546 c.Assert(loggingSub.Life(), gc.Equals, state.Alive) 547 c.Assert(monitoringSub.Life(), gc.Equals, state.Alive) 548 549 err := s.wordpressUnit.Refresh() 550 c.Assert(err, gc.IsNil) 551 subordinates := s.wordpressUnit.SubordinateNames() 552 c.Assert(subordinates, gc.DeepEquals, []string{"logging/0", "monitoring/0"}) 553 554 args := params.Entities{Entities: []params.Entity{ 555 {Tag: "unit-mysql-0"}, 556 {Tag: "unit-wordpress-0"}, 557 {Tag: "unit-foo-42"}, 558 }} 559 result, err := s.uniter.DestroyAllSubordinates(args) 560 c.Assert(err, gc.IsNil) 561 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 562 Results: []params.ErrorResult{ 563 {apiservertesting.ErrUnauthorized}, 564 {nil}, 565 {apiservertesting.ErrUnauthorized}, 566 }, 567 }) 568 569 // Verify wordpressUnit's subordinates were destroyed. 570 err = loggingSub.Refresh() 571 c.Assert(err, gc.IsNil) 572 c.Assert(loggingSub.Life(), gc.Equals, state.Dying) 573 err = monitoringSub.Refresh() 574 c.Assert(err, gc.IsNil) 575 c.Assert(monitoringSub.Life(), gc.Equals, state.Dying) 576 } 577 578 func (s *uniterSuite) TestCharmURL(c *gc.C) { 579 // Set wordpressUnit's charm URL first. 580 err := s.wordpressUnit.SetCharmURL(s.wpCharm.URL()) 581 c.Assert(err, gc.IsNil) 582 curl, ok := s.wordpressUnit.CharmURL() 583 c.Assert(curl, gc.DeepEquals, s.wpCharm.URL()) 584 c.Assert(ok, jc.IsTrue) 585 586 // Make sure wordpress service's charm is what we expect. 587 curl, force := s.wordpress.CharmURL() 588 c.Assert(curl, gc.DeepEquals, s.wpCharm.URL()) 589 c.Assert(force, jc.IsFalse) 590 591 args := params.Entities{Entities: []params.Entity{ 592 {Tag: "unit-mysql-0"}, 593 {Tag: "unit-wordpress-0"}, 594 {Tag: "unit-foo-42"}, 595 {Tag: "service-mysql"}, 596 {Tag: "service-wordpress"}, 597 {Tag: "service-foo"}, 598 {Tag: "just-foo"}, 599 }} 600 result, err := s.uniter.CharmURL(args) 601 c.Assert(err, gc.IsNil) 602 c.Assert(result, gc.DeepEquals, params.StringBoolResults{ 603 Results: []params.StringBoolResult{ 604 {Error: apiservertesting.ErrUnauthorized}, 605 {Result: s.wpCharm.String(), Ok: ok}, 606 {Error: apiservertesting.ErrUnauthorized}, 607 {Error: apiservertesting.ErrUnauthorized}, 608 {Result: s.wpCharm.String(), Ok: force}, 609 {Error: apiservertesting.ErrUnauthorized}, 610 {Error: apiservertesting.ErrUnauthorized}, 611 }, 612 }) 613 } 614 615 func (s *uniterSuite) TestSetCharmURL(c *gc.C) { 616 charmUrl, ok := s.wordpressUnit.CharmURL() 617 c.Assert(charmUrl, gc.IsNil) 618 c.Assert(ok, jc.IsFalse) 619 620 args := params.EntitiesCharmURL{Entities: []params.EntityCharmURL{ 621 {Tag: "unit-mysql-0", CharmURL: "cs:quantal/service-42"}, 622 {Tag: "unit-wordpress-0", CharmURL: s.wpCharm.String()}, 623 {Tag: "unit-foo-42", CharmURL: "cs:quantal/foo-321"}, 624 }} 625 result, err := s.uniter.SetCharmURL(args) 626 c.Assert(err, gc.IsNil) 627 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 628 Results: []params.ErrorResult{ 629 {apiservertesting.ErrUnauthorized}, 630 {nil}, 631 {apiservertesting.ErrUnauthorized}, 632 }, 633 }) 634 635 // Verify the charm URL was set. 636 err = s.wordpressUnit.Refresh() 637 c.Assert(err, gc.IsNil) 638 charmUrl, ok = s.wordpressUnit.CharmURL() 639 c.Assert(charmUrl, gc.NotNil) 640 c.Assert(charmUrl.String(), gc.Equals, s.wpCharm.String()) 641 c.Assert(ok, jc.IsTrue) 642 } 643 644 func (s *uniterSuite) TestOpenPort(c *gc.C) { 645 openedPorts := s.wordpressUnit.OpenedPorts() 646 c.Assert(openedPorts, gc.HasLen, 0) 647 648 args := params.EntitiesPorts{Entities: []params.EntityPort{ 649 {Tag: "unit-mysql-0", Protocol: "tcp", Port: 1234}, 650 {Tag: "unit-wordpress-0", Protocol: "udp", Port: 4321}, 651 {Tag: "unit-foo-42", Protocol: "tcp", Port: 42}, 652 }} 653 result, err := s.uniter.OpenPort(args) 654 c.Assert(err, gc.IsNil) 655 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 656 Results: []params.ErrorResult{ 657 {apiservertesting.ErrUnauthorized}, 658 {nil}, 659 {apiservertesting.ErrUnauthorized}, 660 }, 661 }) 662 663 // Verify the wordpressUnit's port is opened. 664 err = s.wordpressUnit.Refresh() 665 c.Assert(err, gc.IsNil) 666 openedPorts = s.wordpressUnit.OpenedPorts() 667 c.Assert(openedPorts, gc.DeepEquals, []instance.Port{ 668 {Protocol: "udp", Number: 4321}, 669 }) 670 } 671 672 func (s *uniterSuite) TestClosePort(c *gc.C) { 673 // Open port udp:4321 in advance on wordpressUnit. 674 err := s.wordpressUnit.OpenPort("udp", 4321) 675 c.Assert(err, gc.IsNil) 676 err = s.wordpressUnit.Refresh() 677 c.Assert(err, gc.IsNil) 678 openedPorts := s.wordpressUnit.OpenedPorts() 679 c.Assert(openedPorts, gc.DeepEquals, []instance.Port{ 680 {Protocol: "udp", Number: 4321}, 681 }) 682 683 args := params.EntitiesPorts{Entities: []params.EntityPort{ 684 {Tag: "unit-mysql-0", Protocol: "tcp", Port: 1234}, 685 {Tag: "unit-wordpress-0", Protocol: "udp", Port: 4321}, 686 {Tag: "unit-foo-42", Protocol: "tcp", Port: 42}, 687 }} 688 result, err := s.uniter.ClosePort(args) 689 c.Assert(err, gc.IsNil) 690 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 691 Results: []params.ErrorResult{ 692 {apiservertesting.ErrUnauthorized}, 693 {nil}, 694 {apiservertesting.ErrUnauthorized}, 695 }, 696 }) 697 698 // Verify the wordpressUnit's port is closed. 699 err = s.wordpressUnit.Refresh() 700 c.Assert(err, gc.IsNil) 701 openedPorts = s.wordpressUnit.OpenedPorts() 702 c.Assert(openedPorts, gc.HasLen, 0) 703 } 704 705 func (s *uniterSuite) TestWatchConfigSettings(c *gc.C) { 706 err := s.wordpressUnit.SetCharmURL(s.wpCharm.URL()) 707 c.Assert(err, gc.IsNil) 708 709 c.Assert(s.resources.Count(), gc.Equals, 0) 710 711 args := params.Entities{Entities: []params.Entity{ 712 {Tag: "unit-mysql-0"}, 713 {Tag: "unit-wordpress-0"}, 714 {Tag: "unit-foo-42"}, 715 }} 716 result, err := s.uniter.WatchConfigSettings(args) 717 c.Assert(err, gc.IsNil) 718 c.Assert(result, gc.DeepEquals, params.NotifyWatchResults{ 719 Results: []params.NotifyWatchResult{ 720 {Error: apiservertesting.ErrUnauthorized}, 721 {NotifyWatcherId: "1"}, 722 {Error: apiservertesting.ErrUnauthorized}, 723 }, 724 }) 725 726 // Verify the resource was registered and stop when done 727 c.Assert(s.resources.Count(), gc.Equals, 1) 728 resource := s.resources.Get("1") 729 defer statetesting.AssertStop(c, resource) 730 731 // Check that the Watch has consumed the initial event ("returned" in 732 // the Watch call) 733 wc := statetesting.NewNotifyWatcherC(c, s.State, resource.(state.NotifyWatcher)) 734 wc.AssertNoChange() 735 } 736 737 func (s *uniterSuite) TestConfigSettings(c *gc.C) { 738 err := s.wordpressUnit.SetCharmURL(s.wpCharm.URL()) 739 c.Assert(err, gc.IsNil) 740 settings, err := s.wordpressUnit.ConfigSettings() 741 c.Assert(err, gc.IsNil) 742 c.Assert(settings, gc.DeepEquals, charm.Settings{"blog-title": "My Title"}) 743 744 args := params.Entities{Entities: []params.Entity{ 745 {Tag: "unit-mysql-0"}, 746 {Tag: "unit-wordpress-0"}, 747 {Tag: "unit-foo-42"}, 748 }} 749 result, err := s.uniter.ConfigSettings(args) 750 c.Assert(err, gc.IsNil) 751 c.Assert(result, gc.DeepEquals, params.ConfigSettingsResults{ 752 Results: []params.ConfigSettingsResult{ 753 {Error: apiservertesting.ErrUnauthorized}, 754 {Settings: params.ConfigSettings{"blog-title": "My Title"}}, 755 {Error: apiservertesting.ErrUnauthorized}, 756 }, 757 }) 758 } 759 760 func (s *uniterSuite) TestWatchServiceRelations(c *gc.C) { 761 c.Assert(s.resources.Count(), gc.Equals, 0) 762 763 args := params.Entities{Entities: []params.Entity{ 764 {Tag: "service-mysql"}, 765 {Tag: "service-wordpress"}, 766 {Tag: "service-foo"}, 767 }} 768 result, err := s.uniter.WatchServiceRelations(args) 769 s.assertOneStringsWatcher(c, result, err) 770 } 771 772 func (s *uniterSuite) TestCharmArchiveURL(c *gc.C) { 773 dummyCharm := s.AddTestingCharm(c, "dummy") 774 775 args := params.CharmURLs{URLs: []params.CharmURL{ 776 {URL: "something-invalid"}, 777 {URL: s.wpCharm.String()}, 778 {URL: dummyCharm.String()}, 779 }} 780 result, err := s.uniter.CharmArchiveURL(args) 781 c.Assert(err, gc.IsNil) 782 c.Assert(result, gc.DeepEquals, params.CharmArchiveURLResults{ 783 Results: []params.CharmArchiveURLResult{ 784 {Error: apiservertesting.ErrUnauthorized}, 785 { 786 Result: s.wpCharm.BundleURL().String(), 787 DisableSSLHostnameVerification: false, 788 }, 789 { 790 Result: dummyCharm.BundleURL().String(), 791 DisableSSLHostnameVerification: false, 792 }, 793 }, 794 }) 795 796 envtesting.SetSSLHostnameVerification(c, s.State, false) 797 798 result, err = s.uniter.CharmArchiveURL(args) 799 c.Assert(err, gc.IsNil) 800 c.Assert(result, gc.DeepEquals, params.CharmArchiveURLResults{ 801 Results: []params.CharmArchiveURLResult{ 802 {Error: apiservertesting.ErrUnauthorized}, 803 { 804 Result: s.wpCharm.BundleURL().String(), 805 DisableSSLHostnameVerification: true, 806 }, 807 { 808 Result: dummyCharm.BundleURL().String(), 809 DisableSSLHostnameVerification: true, 810 }, 811 }, 812 }) 813 } 814 815 func (s *uniterSuite) TestCharmArchiveSha256(c *gc.C) { 816 dummyCharm := s.AddTestingCharm(c, "dummy") 817 818 args := params.CharmURLs{URLs: []params.CharmURL{ 819 {URL: "something-invalid"}, 820 {URL: s.wpCharm.String()}, 821 {URL: dummyCharm.String()}, 822 }} 823 result, err := s.uniter.CharmArchiveSha256(args) 824 c.Assert(err, gc.IsNil) 825 c.Assert(result, gc.DeepEquals, params.StringResults{ 826 Results: []params.StringResult{ 827 {Error: apiservertesting.ErrUnauthorized}, 828 {Result: s.wpCharm.BundleSha256()}, 829 {Result: dummyCharm.BundleSha256()}, 830 }, 831 }) 832 } 833 834 func (s *uniterSuite) TestCurrentEnvironUUID(c *gc.C) { 835 env, err := s.State.Environment() 836 c.Assert(err, gc.IsNil) 837 838 result, err := s.uniter.CurrentEnvironUUID() 839 c.Assert(err, gc.IsNil) 840 c.Assert(result, gc.DeepEquals, params.StringResult{Result: env.UUID()}) 841 } 842 843 func (s *uniterSuite) TestCurrentEnvironment(c *gc.C) { 844 env, err := s.State.Environment() 845 c.Assert(err, gc.IsNil) 846 847 result, err := s.uniter.CurrentEnvironment() 848 c.Assert(err, gc.IsNil) 849 expected := params.EnvironmentResult{ 850 Name: env.Name(), 851 UUID: env.UUID(), 852 } 853 c.Assert(result, gc.DeepEquals, expected) 854 } 855 856 func (s *uniterSuite) addRelation(c *gc.C, first, second string) *state.Relation { 857 eps, err := s.State.InferEndpoints([]string{first, second}) 858 c.Assert(err, gc.IsNil) 859 rel, err := s.State.AddRelation(eps...) 860 c.Assert(err, gc.IsNil) 861 return rel 862 } 863 864 func (s *uniterSuite) TestRelation(c *gc.C) { 865 rel := s.addRelation(c, "wordpress", "mysql") 866 wpEp, err := rel.Endpoint("wordpress") 867 c.Assert(err, gc.IsNil) 868 869 args := params.RelationUnits{RelationUnits: []params.RelationUnit{ 870 {Relation: "relation-42", Unit: "unit-foo-0"}, 871 {Relation: rel.Tag(), Unit: "unit-wordpress-0"}, 872 {Relation: rel.Tag(), Unit: "unit-mysql-0"}, 873 {Relation: rel.Tag(), Unit: "unit-foo-0"}, 874 {Relation: "relation-blah", Unit: "unit-wordpress-0"}, 875 {Relation: "service-foo", Unit: "user-admin"}, 876 {Relation: "foo", Unit: "bar"}, 877 {Relation: "unit-wordpress-0", Unit: rel.Tag()}, 878 }} 879 result, err := s.uniter.Relation(args) 880 c.Assert(err, gc.IsNil) 881 c.Assert(result, gc.DeepEquals, params.RelationResults{ 882 Results: []params.RelationResult{ 883 {Error: apiservertesting.ErrUnauthorized}, 884 { 885 Id: rel.Id(), 886 Key: rel.String(), 887 Life: params.Life(rel.Life().String()), 888 Endpoint: params.Endpoint{ 889 ServiceName: wpEp.ServiceName, 890 Relation: wpEp.Relation, 891 }, 892 }, 893 {Error: apiservertesting.ErrUnauthorized}, 894 {Error: apiservertesting.ErrUnauthorized}, 895 {Error: apiservertesting.ErrUnauthorized}, 896 {Error: apiservertesting.ErrUnauthorized}, 897 {Error: apiservertesting.ErrUnauthorized}, 898 {Error: apiservertesting.ErrUnauthorized}, 899 }, 900 }) 901 } 902 903 func (s *uniterSuite) TestRelationById(c *gc.C) { 904 rel := s.addRelation(c, "wordpress", "mysql") 905 c.Assert(rel.Id(), gc.Equals, 0) 906 wpEp, err := rel.Endpoint("wordpress") 907 c.Assert(err, gc.IsNil) 908 909 // Add another relation to mysql service, so we can see we can't 910 // get it. 911 otherRel, _, _ := s.addRelatedService(c, "mysql", "logging", s.mysqlUnit) 912 913 args := params.RelationIds{ 914 RelationIds: []int{-1, rel.Id(), otherRel.Id(), 42, 234}, 915 } 916 result, err := s.uniter.RelationById(args) 917 c.Assert(err, gc.IsNil) 918 c.Assert(result, gc.DeepEquals, params.RelationResults{ 919 Results: []params.RelationResult{ 920 {Error: apiservertesting.ErrUnauthorized}, 921 { 922 Id: rel.Id(), 923 Key: rel.String(), 924 Life: params.Life(rel.Life().String()), 925 Endpoint: params.Endpoint{ 926 ServiceName: wpEp.ServiceName, 927 Relation: wpEp.Relation, 928 }, 929 }, 930 {Error: apiservertesting.ErrUnauthorized}, 931 {Error: apiservertesting.ErrUnauthorized}, 932 {Error: apiservertesting.ErrUnauthorized}, 933 }, 934 }) 935 } 936 937 func (s *uniterSuite) TestProviderType(c *gc.C) { 938 cfg, err := s.State.EnvironConfig() 939 c.Assert(err, gc.IsNil) 940 941 result, err := s.uniter.ProviderType() 942 c.Assert(err, gc.IsNil) 943 c.Assert(result, gc.DeepEquals, params.StringResult{Result: cfg.Type()}) 944 } 945 946 func (s *uniterSuite) assertInScope(c *gc.C, relUnit *state.RelationUnit, inScope bool) { 947 ok, err := relUnit.InScope() 948 c.Assert(err, gc.IsNil) 949 c.Assert(ok, gc.Equals, inScope) 950 } 951 952 func (s *uniterSuite) TestEnterScope(c *gc.C) { 953 // Set wordpressUnit's private address first. 954 err := s.machine0.SetAddresses(instance.NewAddress("1.2.3.4", instance.NetworkCloudLocal)) 955 c.Assert(err, gc.IsNil) 956 957 rel := s.addRelation(c, "wordpress", "mysql") 958 relUnit, err := rel.Unit(s.wordpressUnit) 959 c.Assert(err, gc.IsNil) 960 s.assertInScope(c, relUnit, false) 961 962 args := params.RelationUnits{RelationUnits: []params.RelationUnit{ 963 {Relation: "relation-42", Unit: "unit-foo-0"}, 964 {Relation: rel.Tag(), Unit: "unit-wordpress-0"}, 965 {Relation: rel.Tag(), Unit: "unit-wordpress-0"}, 966 {Relation: "relation-42", Unit: "unit-wordpress-0"}, 967 {Relation: "relation-foo", Unit: "unit-wordpress-0"}, 968 {Relation: "service-wordpress", Unit: "unit-foo-0"}, 969 {Relation: "foo", Unit: "bar"}, 970 {Relation: rel.Tag(), Unit: "unit-mysql-0"}, 971 {Relation: rel.Tag(), Unit: "service-wordpress"}, 972 {Relation: rel.Tag(), Unit: "service-mysql"}, 973 {Relation: rel.Tag(), Unit: "user-admin"}, 974 }} 975 result, err := s.uniter.EnterScope(args) 976 c.Assert(err, gc.IsNil) 977 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 978 Results: []params.ErrorResult{ 979 {apiservertesting.ErrUnauthorized}, 980 {nil}, 981 {nil}, 982 {apiservertesting.ErrUnauthorized}, 983 {apiservertesting.ErrUnauthorized}, 984 {apiservertesting.ErrUnauthorized}, 985 {apiservertesting.ErrUnauthorized}, 986 {apiservertesting.ErrUnauthorized}, 987 {apiservertesting.ErrUnauthorized}, 988 {apiservertesting.ErrUnauthorized}, 989 {apiservertesting.ErrUnauthorized}, 990 }, 991 }) 992 993 // Verify the scope changes and settings. 994 s.assertInScope(c, relUnit, true) 995 readSettings, err := relUnit.ReadSettings(s.wordpressUnit.Name()) 996 c.Assert(err, gc.IsNil) 997 c.Assert(readSettings, gc.DeepEquals, map[string]interface{}{ 998 "private-address": "1.2.3.4", 999 }) 1000 } 1001 1002 func (s *uniterSuite) TestLeaveScope(c *gc.C) { 1003 rel := s.addRelation(c, "wordpress", "mysql") 1004 relUnit, err := rel.Unit(s.wordpressUnit) 1005 c.Assert(err, gc.IsNil) 1006 settings := map[string]interface{}{ 1007 "some": "settings", 1008 } 1009 err = relUnit.EnterScope(settings) 1010 c.Assert(err, gc.IsNil) 1011 s.assertInScope(c, relUnit, true) 1012 1013 args := params.RelationUnits{RelationUnits: []params.RelationUnit{ 1014 {Relation: "relation-42", Unit: "unit-foo-0"}, 1015 {Relation: rel.Tag(), Unit: "unit-wordpress-0"}, 1016 {Relation: rel.Tag(), Unit: "unit-wordpress-0"}, 1017 {Relation: "relation-42", Unit: "unit-wordpress-0"}, 1018 {Relation: "relation-foo", Unit: "unit-wordpress-0"}, 1019 {Relation: "service-wordpress", Unit: "unit-foo-0"}, 1020 {Relation: "foo", Unit: "bar"}, 1021 {Relation: rel.Tag(), Unit: "unit-mysql-0"}, 1022 {Relation: rel.Tag(), Unit: "service-wordpress"}, 1023 {Relation: rel.Tag(), Unit: "service-mysql"}, 1024 {Relation: rel.Tag(), Unit: "user-admin"}, 1025 }} 1026 result, err := s.uniter.LeaveScope(args) 1027 c.Assert(err, gc.IsNil) 1028 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1029 Results: []params.ErrorResult{ 1030 {apiservertesting.ErrUnauthorized}, 1031 {nil}, 1032 {nil}, 1033 {apiservertesting.ErrUnauthorized}, 1034 {apiservertesting.ErrUnauthorized}, 1035 {apiservertesting.ErrUnauthorized}, 1036 {apiservertesting.ErrUnauthorized}, 1037 {apiservertesting.ErrUnauthorized}, 1038 {apiservertesting.ErrUnauthorized}, 1039 {apiservertesting.ErrUnauthorized}, 1040 {apiservertesting.ErrUnauthorized}, 1041 }, 1042 }) 1043 1044 // Verify the scope changes. 1045 s.assertInScope(c, relUnit, false) 1046 readSettings, err := relUnit.ReadSettings(s.wordpressUnit.Name()) 1047 c.Assert(err, gc.IsNil) 1048 c.Assert(readSettings, gc.DeepEquals, settings) 1049 } 1050 1051 func (s *uniterSuite) TestJoinedRelations(c *gc.C) { 1052 rel := s.addRelation(c, "wordpress", "mysql") 1053 relUnit, err := rel.Unit(s.wordpressUnit) 1054 c.Assert(err, gc.IsNil) 1055 err = relUnit.EnterScope(nil) 1056 c.Assert(err, gc.IsNil) 1057 1058 args := params.Entities{ 1059 Entities: []params.Entity{ 1060 {s.wordpressUnit.Tag()}, 1061 {s.mysqlUnit.Tag()}, 1062 {"unit-unknown-1"}, 1063 {"service-wordpress"}, 1064 {"machine-0"}, 1065 {rel.Tag()}, 1066 }, 1067 } 1068 expect := params.StringsResults{ 1069 Results: []params.StringsResult{ 1070 {Result: []string{rel.Tag()}}, 1071 {Error: apiservertesting.ErrUnauthorized}, 1072 {Error: apiservertesting.ErrUnauthorized}, 1073 {Error: apiservertesting.ErrUnauthorized}, 1074 {Error: apiservertesting.ErrUnauthorized}, 1075 {Error: apiservertesting.ErrUnauthorized}, 1076 }, 1077 } 1078 check := func() { 1079 result, err := s.uniter.JoinedRelations(args) 1080 c.Assert(err, gc.IsNil) 1081 c.Assert(result, gc.DeepEquals, expect) 1082 } 1083 check() 1084 err = relUnit.PrepareLeaveScope() 1085 c.Assert(err, gc.IsNil) 1086 check() 1087 } 1088 1089 func (s *uniterSuite) TestReadSettings(c *gc.C) { 1090 rel := s.addRelation(c, "wordpress", "mysql") 1091 relUnit, err := rel.Unit(s.wordpressUnit) 1092 c.Assert(err, gc.IsNil) 1093 settings := map[string]interface{}{ 1094 "some": "settings", 1095 } 1096 err = relUnit.EnterScope(settings) 1097 c.Assert(err, gc.IsNil) 1098 s.assertInScope(c, relUnit, true) 1099 1100 args := params.RelationUnits{RelationUnits: []params.RelationUnit{ 1101 {Relation: "relation-42", Unit: "unit-foo-0"}, 1102 {Relation: rel.Tag(), Unit: "unit-wordpress-0"}, 1103 {Relation: rel.Tag(), Unit: "unit-mysql-0"}, 1104 {Relation: "relation-42", Unit: "unit-wordpress-0"}, 1105 {Relation: "relation-foo", Unit: ""}, 1106 {Relation: "service-wordpress", Unit: "unit-foo-0"}, 1107 {Relation: "foo", Unit: "bar"}, 1108 {Relation: rel.Tag(), Unit: "unit-mysql-0"}, 1109 {Relation: rel.Tag(), Unit: "service-wordpress"}, 1110 {Relation: rel.Tag(), Unit: "service-mysql"}, 1111 {Relation: rel.Tag(), Unit: "user-admin"}, 1112 }} 1113 result, err := s.uniter.ReadSettings(args) 1114 c.Assert(err, gc.IsNil) 1115 c.Assert(result, gc.DeepEquals, params.RelationSettingsResults{ 1116 Results: []params.RelationSettingsResult{ 1117 {Error: apiservertesting.ErrUnauthorized}, 1118 {Settings: params.RelationSettings{ 1119 "some": "settings", 1120 }}, 1121 {Error: apiservertesting.ErrUnauthorized}, 1122 {Error: apiservertesting.ErrUnauthorized}, 1123 {Error: apiservertesting.ErrUnauthorized}, 1124 {Error: apiservertesting.ErrUnauthorized}, 1125 {Error: apiservertesting.ErrUnauthorized}, 1126 {Error: apiservertesting.ErrUnauthorized}, 1127 {Error: apiservertesting.ErrUnauthorized}, 1128 {Error: apiservertesting.ErrUnauthorized}, 1129 {Error: apiservertesting.ErrUnauthorized}, 1130 }, 1131 }) 1132 } 1133 1134 func (s *uniterSuite) TestReadSettingsWithNonStringValuesFails(c *gc.C) { 1135 rel := s.addRelation(c, "wordpress", "mysql") 1136 relUnit, err := rel.Unit(s.wordpressUnit) 1137 c.Assert(err, gc.IsNil) 1138 settings := map[string]interface{}{ 1139 "other": "things", 1140 "invalid-bool": false, 1141 } 1142 err = relUnit.EnterScope(settings) 1143 c.Assert(err, gc.IsNil) 1144 s.assertInScope(c, relUnit, true) 1145 1146 args := params.RelationUnits{RelationUnits: []params.RelationUnit{ 1147 {Relation: rel.Tag(), Unit: "unit-wordpress-0"}, 1148 }} 1149 expectErr := `unexpected relation setting "invalid-bool": expected string, got bool` 1150 result, err := s.uniter.ReadSettings(args) 1151 c.Assert(err, gc.IsNil) 1152 c.Assert(result, gc.DeepEquals, params.RelationSettingsResults{ 1153 Results: []params.RelationSettingsResult{ 1154 {Error: ¶ms.Error{Message: expectErr}}, 1155 }, 1156 }) 1157 } 1158 1159 func (s *uniterSuite) TestReadRemoteSettings(c *gc.C) { 1160 rel := s.addRelation(c, "wordpress", "mysql") 1161 relUnit, err := rel.Unit(s.wordpressUnit) 1162 c.Assert(err, gc.IsNil) 1163 settings := map[string]interface{}{ 1164 "some": "settings", 1165 } 1166 err = relUnit.EnterScope(settings) 1167 c.Assert(err, gc.IsNil) 1168 s.assertInScope(c, relUnit, true) 1169 1170 // First test most of the invalid args tests and try to read the 1171 // (unset) remote unit settings. 1172 args := params.RelationUnitPairs{RelationUnitPairs: []params.RelationUnitPair{ 1173 {Relation: "relation-42", LocalUnit: "unit-foo-0", RemoteUnit: "foo"}, 1174 {Relation: rel.Tag(), LocalUnit: "unit-wordpress-0", RemoteUnit: "unit-wordpress-0"}, 1175 {Relation: rel.Tag(), LocalUnit: "unit-wordpress-0", RemoteUnit: "unit-mysql-0"}, 1176 {Relation: "relation-42", LocalUnit: "unit-wordpress-0", RemoteUnit: ""}, 1177 {Relation: "relation-foo", LocalUnit: "", RemoteUnit: ""}, 1178 {Relation: "service-wordpress", LocalUnit: "unit-foo-0", RemoteUnit: "user-admin"}, 1179 {Relation: "foo", LocalUnit: "bar", RemoteUnit: "baz"}, 1180 {Relation: rel.Tag(), LocalUnit: "unit-mysql-0", RemoteUnit: "unit-wordpress-0"}, 1181 {Relation: rel.Tag(), LocalUnit: "service-wordpress", RemoteUnit: "service-mysql"}, 1182 {Relation: rel.Tag(), LocalUnit: "service-mysql", RemoteUnit: "foo"}, 1183 {Relation: rel.Tag(), LocalUnit: "user-admin", RemoteUnit: "unit-wordpress-0"}, 1184 }} 1185 result, err := s.uniter.ReadRemoteSettings(args) 1186 1187 // We don't set the remote unit settings on purpose to test the error. 1188 expectErr := `cannot read settings for unit "mysql/0" in relation "wordpress:db mysql:server": settings not found` 1189 c.Assert(err, gc.IsNil) 1190 c.Assert(result, jc.DeepEquals, params.RelationSettingsResults{ 1191 Results: []params.RelationSettingsResult{ 1192 {Error: apiservertesting.ErrUnauthorized}, 1193 {Error: apiservertesting.ErrUnauthorized}, 1194 {Error: apiservertesting.ServerError(expectErr)}, 1195 {Error: apiservertesting.ErrUnauthorized}, 1196 {Error: apiservertesting.ErrUnauthorized}, 1197 {Error: apiservertesting.ErrUnauthorized}, 1198 {Error: apiservertesting.ErrUnauthorized}, 1199 {Error: apiservertesting.ErrUnauthorized}, 1200 {Error: apiservertesting.ErrUnauthorized}, 1201 {Error: apiservertesting.ErrUnauthorized}, 1202 {Error: apiservertesting.ErrUnauthorized}, 1203 }, 1204 }) 1205 1206 // Now leave the mysqlUnit and re-enter with new settings. 1207 relUnit, err = rel.Unit(s.mysqlUnit) 1208 c.Assert(err, gc.IsNil) 1209 settings = map[string]interface{}{ 1210 "other": "things", 1211 } 1212 err = relUnit.LeaveScope() 1213 c.Assert(err, gc.IsNil) 1214 s.assertInScope(c, relUnit, false) 1215 err = relUnit.EnterScope(settings) 1216 c.Assert(err, gc.IsNil) 1217 s.assertInScope(c, relUnit, true) 1218 1219 // Test the remote unit settings can be read. 1220 args = params.RelationUnitPairs{RelationUnitPairs: []params.RelationUnitPair{{ 1221 Relation: rel.Tag(), 1222 LocalUnit: "unit-wordpress-0", 1223 RemoteUnit: "unit-mysql-0", 1224 }}} 1225 expect := params.RelationSettingsResults{ 1226 Results: []params.RelationSettingsResult{ 1227 {Settings: params.RelationSettings{ 1228 "other": "things", 1229 }}, 1230 }, 1231 } 1232 result, err = s.uniter.ReadRemoteSettings(args) 1233 c.Assert(err, gc.IsNil) 1234 c.Assert(result, gc.DeepEquals, expect) 1235 1236 // Now destroy the remote unit, and check its settings can still be read. 1237 err = s.mysqlUnit.Destroy() 1238 c.Assert(err, gc.IsNil) 1239 err = s.mysqlUnit.EnsureDead() 1240 c.Assert(err, gc.IsNil) 1241 err = s.mysqlUnit.Remove() 1242 c.Assert(err, gc.IsNil) 1243 result, err = s.uniter.ReadRemoteSettings(args) 1244 c.Assert(err, gc.IsNil) 1245 c.Assert(result, gc.DeepEquals, expect) 1246 } 1247 1248 func (s *uniterSuite) TestReadRemoteSettingsWithNonStringValuesFails(c *gc.C) { 1249 rel := s.addRelation(c, "wordpress", "mysql") 1250 relUnit, err := rel.Unit(s.mysqlUnit) 1251 c.Assert(err, gc.IsNil) 1252 settings := map[string]interface{}{ 1253 "other": "things", 1254 "invalid-bool": false, 1255 } 1256 err = relUnit.EnterScope(settings) 1257 c.Assert(err, gc.IsNil) 1258 s.assertInScope(c, relUnit, true) 1259 1260 args := params.RelationUnitPairs{RelationUnitPairs: []params.RelationUnitPair{{ 1261 Relation: rel.Tag(), 1262 LocalUnit: "unit-wordpress-0", 1263 RemoteUnit: "unit-mysql-0", 1264 }}} 1265 expectErr := `unexpected relation setting "invalid-bool": expected string, got bool` 1266 result, err := s.uniter.ReadRemoteSettings(args) 1267 c.Assert(err, gc.IsNil) 1268 c.Assert(result, gc.DeepEquals, params.RelationSettingsResults{ 1269 Results: []params.RelationSettingsResult{ 1270 {Error: ¶ms.Error{Message: expectErr}}, 1271 }, 1272 }) 1273 } 1274 1275 func (s *uniterSuite) TestUpdateSettings(c *gc.C) { 1276 rel := s.addRelation(c, "wordpress", "mysql") 1277 relUnit, err := rel.Unit(s.wordpressUnit) 1278 c.Assert(err, gc.IsNil) 1279 settings := map[string]interface{}{ 1280 "some": "settings", 1281 "other": "stuff", 1282 } 1283 err = relUnit.EnterScope(settings) 1284 s.assertInScope(c, relUnit, true) 1285 1286 newSettings := params.RelationSettings{ 1287 "some": "different", 1288 "other": "", 1289 } 1290 1291 args := params.RelationUnitsSettings{RelationUnits: []params.RelationUnitSettings{ 1292 {Relation: "relation-42", Unit: "unit-foo-0", Settings: nil}, 1293 {Relation: rel.Tag(), Unit: "unit-wordpress-0", Settings: newSettings}, 1294 {Relation: "relation-42", Unit: "unit-wordpress-0", Settings: nil}, 1295 {Relation: "relation-foo", Unit: "unit-wordpress-0", Settings: nil}, 1296 {Relation: "service-wordpress", Unit: "unit-foo-0", Settings: nil}, 1297 {Relation: "foo", Unit: "bar", Settings: nil}, 1298 {Relation: rel.Tag(), Unit: "unit-mysql-0", Settings: nil}, 1299 {Relation: rel.Tag(), Unit: "service-wordpress", Settings: nil}, 1300 {Relation: rel.Tag(), Unit: "service-mysql", Settings: nil}, 1301 {Relation: rel.Tag(), Unit: "user-admin", Settings: nil}, 1302 }} 1303 result, err := s.uniter.UpdateSettings(args) 1304 c.Assert(err, gc.IsNil) 1305 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1306 Results: []params.ErrorResult{ 1307 {apiservertesting.ErrUnauthorized}, 1308 {nil}, 1309 {apiservertesting.ErrUnauthorized}, 1310 {apiservertesting.ErrUnauthorized}, 1311 {apiservertesting.ErrUnauthorized}, 1312 {apiservertesting.ErrUnauthorized}, 1313 {apiservertesting.ErrUnauthorized}, 1314 {apiservertesting.ErrUnauthorized}, 1315 {apiservertesting.ErrUnauthorized}, 1316 {apiservertesting.ErrUnauthorized}, 1317 }, 1318 }) 1319 1320 // Verify the settings were saved. 1321 s.assertInScope(c, relUnit, true) 1322 readSettings, err := relUnit.ReadSettings(s.wordpressUnit.Name()) 1323 c.Assert(err, gc.IsNil) 1324 c.Assert(readSettings, gc.DeepEquals, map[string]interface{}{ 1325 "some": "different", 1326 }) 1327 } 1328 1329 func (s *uniterSuite) TestWatchRelationUnits(c *gc.C) { 1330 // Add a relation between wordpress and mysql and enter scope with 1331 // mysqlUnit. 1332 rel := s.addRelation(c, "wordpress", "mysql") 1333 myRelUnit, err := rel.Unit(s.mysqlUnit) 1334 c.Assert(err, gc.IsNil) 1335 err = myRelUnit.EnterScope(nil) 1336 c.Assert(err, gc.IsNil) 1337 s.assertInScope(c, myRelUnit, true) 1338 1339 c.Assert(s.resources.Count(), gc.Equals, 0) 1340 1341 args := params.RelationUnits{RelationUnits: []params.RelationUnit{ 1342 {Relation: "relation-42", Unit: "unit-foo-0"}, 1343 {Relation: rel.Tag(), Unit: "unit-wordpress-0"}, 1344 {Relation: rel.Tag(), Unit: "unit-mysql-0"}, 1345 {Relation: "relation-42", Unit: "unit-wordpress-0"}, 1346 {Relation: "relation-foo", Unit: ""}, 1347 {Relation: "service-wordpress", Unit: "unit-foo-0"}, 1348 {Relation: "foo", Unit: "bar"}, 1349 {Relation: rel.Tag(), Unit: "unit-mysql-0"}, 1350 {Relation: rel.Tag(), Unit: "service-wordpress"}, 1351 {Relation: rel.Tag(), Unit: "service-mysql"}, 1352 {Relation: rel.Tag(), Unit: "user-admin"}, 1353 }} 1354 result, err := s.uniter.WatchRelationUnits(args) 1355 c.Assert(err, gc.IsNil) 1356 // UnitSettings versions are volatile, so we don't check them. 1357 // We just make sure the keys of the Changed field are as 1358 // expected. 1359 c.Assert(result.Results, gc.HasLen, len(args.RelationUnits)) 1360 mysqlChanges := result.Results[1].Changes 1361 c.Assert(mysqlChanges, gc.NotNil) 1362 changed, ok := mysqlChanges.Changed["mysql/0"] 1363 c.Assert(ok, jc.IsTrue) 1364 expectChanges := params.RelationUnitsChange{ 1365 Changed: map[string]params.UnitSettings{"mysql/0": changed}, 1366 } 1367 c.Assert(result, gc.DeepEquals, params.RelationUnitsWatchResults{ 1368 Results: []params.RelationUnitsWatchResult{ 1369 {Error: apiservertesting.ErrUnauthorized}, 1370 { 1371 RelationUnitsWatcherId: "1", 1372 Changes: expectChanges, 1373 }, 1374 {Error: apiservertesting.ErrUnauthorized}, 1375 {Error: apiservertesting.ErrUnauthorized}, 1376 {Error: apiservertesting.ErrUnauthorized}, 1377 {Error: apiservertesting.ErrUnauthorized}, 1378 {Error: apiservertesting.ErrUnauthorized}, 1379 {Error: apiservertesting.ErrUnauthorized}, 1380 {Error: apiservertesting.ErrUnauthorized}, 1381 {Error: apiservertesting.ErrUnauthorized}, 1382 {Error: apiservertesting.ErrUnauthorized}, 1383 }, 1384 }) 1385 1386 // Verify the resource was registered and stop when done 1387 c.Assert(s.resources.Count(), gc.Equals, 1) 1388 resource := s.resources.Get("1") 1389 defer statetesting.AssertStop(c, resource) 1390 1391 // Check that the Watch has consumed the initial event ("returned" in 1392 // the Watch call) 1393 wc := statetesting.NewRelationUnitsWatcherC(c, s.State, resource.(state.RelationUnitsWatcher)) 1394 wc.AssertNoChange() 1395 1396 // Leave scope with mysqlUnit and check it's detected. 1397 err = myRelUnit.LeaveScope() 1398 c.Assert(err, gc.IsNil) 1399 s.assertInScope(c, myRelUnit, false) 1400 1401 wc.AssertChange(nil, []string{"mysql/0"}) 1402 } 1403 1404 func (s *uniterSuite) TestAPIAddresses(c *gc.C) { 1405 hostPorts := [][]instance.HostPort{{{ 1406 Address: instance.NewAddress("0.1.2.3", instance.NetworkUnknown), 1407 Port: 1234, 1408 }}} 1409 1410 err := s.State.SetAPIHostPorts(hostPorts) 1411 c.Assert(err, gc.IsNil) 1412 1413 result, err := s.uniter.APIAddresses() 1414 c.Assert(err, gc.IsNil) 1415 c.Assert(result, gc.DeepEquals, params.StringsResult{ 1416 Result: []string{"0.1.2.3:1234"}, 1417 }) 1418 } 1419 1420 func (s *uniterSuite) TestGetOwnerTag(c *gc.C) { 1421 tag := s.mysql.Tag() 1422 args := params.Entities{Entities: []params.Entity{ 1423 {Tag: tag}, 1424 }} 1425 result, err := s.uniter.GetOwnerTag(args) 1426 c.Assert(err, gc.IsNil) 1427 c.Assert(result, gc.DeepEquals, params.StringResult{ 1428 Result: "user-admin", 1429 }) 1430 }