github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/apiserver/uniter/uniter_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package uniter_test 5 6 import ( 7 "fmt" 8 "time" 9 10 "github.com/juju/errors" 11 "github.com/juju/names" 12 jc "github.com/juju/testing/checkers" 13 "github.com/juju/utils" 14 gc "gopkg.in/check.v1" 15 "gopkg.in/juju/charm.v6-unstable" 16 17 "github.com/juju/juju/apiserver/common" 18 commontesting "github.com/juju/juju/apiserver/common/testing" 19 "github.com/juju/juju/apiserver/params" 20 apiservertesting "github.com/juju/juju/apiserver/testing" 21 "github.com/juju/juju/apiserver/uniter" 22 "github.com/juju/juju/juju/testing" 23 "github.com/juju/juju/network" 24 "github.com/juju/juju/state" 25 "github.com/juju/juju/state/multiwatcher" 26 statetesting "github.com/juju/juju/state/testing" 27 "github.com/juju/juju/status" 28 coretesting "github.com/juju/juju/testing" 29 "github.com/juju/juju/testing/factory" 30 jujuFactory "github.com/juju/juju/testing/factory" 31 ) 32 33 // uniterSuite implements common testing suite for all API 34 // versions. It's not intended to be used directly or registered as a 35 // suite, but embedded. 36 type uniterSuite struct { 37 testing.JujuConnSuite 38 39 authorizer apiservertesting.FakeAuthorizer 40 resources *common.Resources 41 uniter *uniter.UniterAPIV3 42 43 machine0 *state.Machine 44 machine1 *state.Machine 45 wordpress *state.Service 46 wpCharm *state.Charm 47 mysql *state.Service 48 wordpressUnit *state.Unit 49 mysqlUnit *state.Unit 50 51 meteredService *state.Service 52 meteredCharm *state.Charm 53 meteredUnit *state.Unit 54 } 55 56 var _ = gc.Suite(&uniterSuite{}) 57 58 func (s *uniterSuite) SetUpTest(c *gc.C) { 59 s.JujuConnSuite.SetUpTest(c) 60 61 factory := jujuFactory.NewFactory(s.State) 62 // Create two machines, two services and add a unit to each service. 63 s.machine0 = factory.MakeMachine(c, &jujuFactory.MachineParams{ 64 Series: "quantal", 65 Jobs: []state.MachineJob{state.JobHostUnits, state.JobManageModel}, 66 }) 67 s.machine1 = factory.MakeMachine(c, &jujuFactory.MachineParams{ 68 Series: "quantal", 69 Jobs: []state.MachineJob{state.JobHostUnits}, 70 }) 71 s.wpCharm = factory.MakeCharm(c, &jujuFactory.CharmParams{ 72 Name: "wordpress", 73 URL: "cs:quantal/wordpress-3", 74 }) 75 s.wordpress = factory.MakeService(c, &jujuFactory.ServiceParams{ 76 Name: "wordpress", 77 Charm: s.wpCharm, 78 Creator: s.AdminUserTag(c), 79 }) 80 mysqlCharm := factory.MakeCharm(c, &jujuFactory.CharmParams{ 81 Name: "mysql", 82 }) 83 s.mysql = factory.MakeService(c, &jujuFactory.ServiceParams{ 84 Name: "mysql", 85 Charm: mysqlCharm, 86 Creator: s.AdminUserTag(c), 87 }) 88 s.wordpressUnit = factory.MakeUnit(c, &jujuFactory.UnitParams{ 89 Service: s.wordpress, 90 Machine: s.machine0, 91 }) 92 s.mysqlUnit = factory.MakeUnit(c, &jujuFactory.UnitParams{ 93 Service: s.mysql, 94 Machine: s.machine1, 95 }) 96 97 s.meteredCharm = s.Factory.MakeCharm(c, &jujuFactory.CharmParams{ 98 Name: "metered", 99 URL: "cs:quantal/metered", 100 }) 101 s.meteredService = s.Factory.MakeService(c, &jujuFactory.ServiceParams{ 102 Charm: s.meteredCharm, 103 }) 104 s.meteredUnit = s.Factory.MakeUnit(c, &jujuFactory.UnitParams{ 105 Service: s.meteredService, 106 SetCharmURL: true, 107 }) 108 109 // Create a FakeAuthorizer so we can check permissions, 110 // set up assuming unit 0 has logged in. 111 s.authorizer = apiservertesting.FakeAuthorizer{ 112 Tag: s.wordpressUnit.Tag(), 113 } 114 115 // Create the resource registry separately to track invocations to 116 // Register. 117 s.resources = common.NewResources() 118 s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() }) 119 120 uniterAPIV3, err := uniter.NewUniterAPIV3( 121 s.State, 122 s.resources, 123 s.authorizer, 124 ) 125 c.Assert(err, jc.ErrorIsNil) 126 s.uniter = uniterAPIV3 127 } 128 129 func (s *uniterSuite) TestUniterFailsWithNonUnitAgentUser(c *gc.C) { 130 anAuthorizer := s.authorizer 131 anAuthorizer.Tag = names.NewMachineTag("9") 132 _, err := uniter.NewUniterAPIV3(s.State, s.resources, anAuthorizer) 133 c.Assert(err, gc.NotNil) 134 c.Assert(err, gc.ErrorMatches, "permission denied") 135 } 136 137 func (s *uniterSuite) TestSetStatus(c *gc.C) { 138 err := s.wordpressUnit.SetAgentStatus(status.StatusExecuting, "blah", nil) 139 c.Assert(err, jc.ErrorIsNil) 140 err = s.mysqlUnit.SetAgentStatus(status.StatusExecuting, "foo", nil) 141 c.Assert(err, jc.ErrorIsNil) 142 143 args := params.SetStatus{ 144 Entities: []params.EntityStatusArgs{ 145 {Tag: "unit-mysql-0", Status: status.StatusError, Info: "not really"}, 146 {Tag: "unit-wordpress-0", Status: status.StatusRebooting, Info: "foobar"}, 147 {Tag: "unit-foo-42", Status: status.StatusActive, Info: "blah"}, 148 }} 149 result, err := s.uniter.SetStatus(args) 150 c.Assert(err, jc.ErrorIsNil) 151 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 152 Results: []params.ErrorResult{ 153 {apiservertesting.ErrUnauthorized}, 154 {nil}, 155 {apiservertesting.ErrUnauthorized}, 156 }, 157 }) 158 159 // Verify mysqlUnit - no change. 160 statusInfo, err := s.mysqlUnit.AgentStatus() 161 c.Assert(err, jc.ErrorIsNil) 162 c.Assert(statusInfo.Status, gc.Equals, status.StatusExecuting) 163 c.Assert(statusInfo.Message, gc.Equals, "foo") 164 // ...wordpressUnit is fine though. 165 statusInfo, err = s.wordpressUnit.AgentStatus() 166 c.Assert(err, jc.ErrorIsNil) 167 c.Assert(statusInfo.Status, gc.Equals, status.StatusRebooting) 168 c.Assert(statusInfo.Message, gc.Equals, "foobar") 169 } 170 171 func (s *uniterSuite) TestSetAgentStatus(c *gc.C) { 172 err := s.wordpressUnit.SetAgentStatus(status.StatusExecuting, "blah", nil) 173 c.Assert(err, jc.ErrorIsNil) 174 err = s.mysqlUnit.SetAgentStatus(status.StatusExecuting, "foo", nil) 175 c.Assert(err, jc.ErrorIsNil) 176 177 args := params.SetStatus{ 178 Entities: []params.EntityStatusArgs{ 179 {Tag: "unit-mysql-0", Status: status.StatusError, Info: "not really"}, 180 {Tag: "unit-wordpress-0", Status: status.StatusExecuting, Info: "foobar"}, 181 {Tag: "unit-foo-42", Status: status.StatusRebooting, Info: "blah"}, 182 }} 183 result, err := s.uniter.SetAgentStatus(args) 184 c.Assert(err, jc.ErrorIsNil) 185 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 186 Results: []params.ErrorResult{ 187 {apiservertesting.ErrUnauthorized}, 188 {nil}, 189 {apiservertesting.ErrUnauthorized}, 190 }, 191 }) 192 193 // Verify mysqlUnit - no change. 194 statusInfo, err := s.mysqlUnit.AgentStatus() 195 c.Assert(err, jc.ErrorIsNil) 196 c.Assert(statusInfo.Status, gc.Equals, status.StatusExecuting) 197 c.Assert(statusInfo.Message, gc.Equals, "foo") 198 // ...wordpressUnit is fine though. 199 statusInfo, err = s.wordpressUnit.AgentStatus() 200 c.Assert(err, jc.ErrorIsNil) 201 c.Assert(statusInfo.Status, gc.Equals, status.StatusExecuting) 202 c.Assert(statusInfo.Message, gc.Equals, "foobar") 203 } 204 205 func (s *uniterSuite) TestSetUnitStatus(c *gc.C) { 206 err := s.wordpressUnit.SetStatus(status.StatusActive, "blah", nil) 207 c.Assert(err, jc.ErrorIsNil) 208 err = s.mysqlUnit.SetStatus(status.StatusTerminated, "foo", nil) 209 c.Assert(err, jc.ErrorIsNil) 210 211 args := params.SetStatus{ 212 Entities: []params.EntityStatusArgs{ 213 {Tag: "unit-mysql-0", Status: status.StatusError, Info: "not really"}, 214 {Tag: "unit-wordpress-0", Status: status.StatusTerminated, Info: "foobar"}, 215 {Tag: "unit-foo-42", Status: status.StatusActive, Info: "blah"}, 216 }} 217 result, err := s.uniter.SetUnitStatus(args) 218 c.Assert(err, jc.ErrorIsNil) 219 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 220 Results: []params.ErrorResult{ 221 {apiservertesting.ErrUnauthorized}, 222 {nil}, 223 {apiservertesting.ErrUnauthorized}, 224 }, 225 }) 226 227 // Verify mysqlUnit - no change. 228 statusInfo, err := s.mysqlUnit.Status() 229 c.Assert(err, jc.ErrorIsNil) 230 c.Assert(statusInfo.Status, gc.Equals, status.StatusTerminated) 231 c.Assert(statusInfo.Message, gc.Equals, "foo") 232 // ...wordpressUnit is fine though. 233 statusInfo, err = s.wordpressUnit.Status() 234 c.Assert(err, jc.ErrorIsNil) 235 c.Assert(statusInfo.Status, gc.Equals, status.StatusTerminated) 236 c.Assert(statusInfo.Message, gc.Equals, "foobar") 237 } 238 239 func (s *uniterSuite) TestLife(c *gc.C) { 240 // Add a relation wordpress-mysql. 241 rel := s.addRelation(c, "wordpress", "mysql") 242 relUnit, err := rel.Unit(s.wordpressUnit) 243 c.Assert(err, jc.ErrorIsNil) 244 err = relUnit.EnterScope(nil) 245 c.Assert(err, jc.ErrorIsNil) 246 c.Assert(rel.Life(), gc.Equals, state.Alive) 247 248 // Make the wordpressUnit dead. 249 err = s.wordpressUnit.EnsureDead() 250 c.Assert(err, jc.ErrorIsNil) 251 err = s.wordpressUnit.Refresh() 252 c.Assert(err, jc.ErrorIsNil) 253 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Dead) 254 255 // Add another unit, so the service will stay dying when we 256 // destroy it later. 257 extraUnit, err := s.wordpress.AddUnit() 258 c.Assert(err, jc.ErrorIsNil) 259 c.Assert(extraUnit, gc.NotNil) 260 261 // Make the wordpress service dying. 262 err = s.wordpress.Destroy() 263 c.Assert(err, jc.ErrorIsNil) 264 err = s.wordpress.Refresh() 265 c.Assert(err, jc.ErrorIsNil) 266 c.Assert(s.wordpress.Life(), gc.Equals, state.Dying) 267 268 args := params.Entities{Entities: []params.Entity{ 269 {Tag: "unit-mysql-0"}, 270 {Tag: "unit-wordpress-0"}, 271 {Tag: "unit-foo-42"}, 272 {Tag: "service-mysql"}, 273 {Tag: "service-wordpress"}, 274 {Tag: "machine-0"}, 275 {Tag: "machine-1"}, 276 {Tag: "machine-42"}, 277 {Tag: "service-foo"}, 278 // TODO(dfc) these aren't valid tags any more 279 // but I hope to restore this test when params.Entity takes 280 // tags, not strings, which is coming soon. 281 // {Tag: "just-foo"}, 282 {Tag: rel.Tag().String()}, 283 {Tag: "relation-svc1.rel1#svc2.rel2"}, 284 // {Tag: "relation-blah"}, 285 }} 286 result, err := s.uniter.Life(args) 287 c.Assert(err, jc.ErrorIsNil) 288 c.Assert(result, gc.DeepEquals, params.LifeResults{ 289 Results: []params.LifeResult{ 290 {Error: apiservertesting.ErrUnauthorized}, 291 {Life: "dead"}, 292 {Error: apiservertesting.ErrUnauthorized}, 293 {Error: apiservertesting.ErrUnauthorized}, 294 {Life: "dying"}, 295 {Error: apiservertesting.ErrUnauthorized}, 296 {Error: apiservertesting.ErrUnauthorized}, 297 {Error: apiservertesting.ErrUnauthorized}, 298 {Error: apiservertesting.ErrUnauthorized}, 299 // TODO(dfc) see above 300 // {Error: apiservertesting.ErrUnauthorized}, 301 {Error: apiservertesting.ErrUnauthorized}, 302 {Error: apiservertesting.ErrUnauthorized}, 303 // {Error: apiservertesting.ErrUnauthorized}, 304 }, 305 }) 306 } 307 308 func (s *uniterSuite) TestEnsureDead(c *gc.C) { 309 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive) 310 c.Assert(s.mysqlUnit.Life(), gc.Equals, state.Alive) 311 312 args := params.Entities{Entities: []params.Entity{ 313 {Tag: "unit-mysql-0"}, 314 {Tag: "unit-wordpress-0"}, 315 {Tag: "unit-foo-42"}, 316 }} 317 result, err := s.uniter.EnsureDead(args) 318 c.Assert(err, jc.ErrorIsNil) 319 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 320 Results: []params.ErrorResult{ 321 {apiservertesting.ErrUnauthorized}, 322 {nil}, 323 {apiservertesting.ErrUnauthorized}, 324 }, 325 }) 326 327 err = s.wordpressUnit.Refresh() 328 c.Assert(err, jc.ErrorIsNil) 329 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Dead) 330 err = s.mysqlUnit.Refresh() 331 c.Assert(err, jc.ErrorIsNil) 332 c.Assert(s.mysqlUnit.Life(), gc.Equals, state.Alive) 333 334 // Try it again on a Dead unit; should work. 335 args = params.Entities{ 336 Entities: []params.Entity{{Tag: "unit-wordpress-0"}}, 337 } 338 result, err = s.uniter.EnsureDead(args) 339 c.Assert(err, jc.ErrorIsNil) 340 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 341 Results: []params.ErrorResult{{nil}}, 342 }) 343 344 // Verify Life is unchanged. 345 err = s.wordpressUnit.Refresh() 346 c.Assert(err, jc.ErrorIsNil) 347 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Dead) 348 } 349 350 func (s *uniterSuite) TestWatch(c *gc.C) { 351 c.Assert(s.resources.Count(), gc.Equals, 0) 352 353 args := params.Entities{Entities: []params.Entity{ 354 {Tag: "unit-mysql-0"}, 355 {Tag: "unit-wordpress-0"}, 356 {Tag: "unit-foo-42"}, 357 {Tag: "service-mysql"}, 358 {Tag: "service-wordpress"}, 359 {Tag: "service-foo"}, 360 // TODO(dfc) these aren't valid tags any more 361 // but I hope to restore this test when params.Entity takes 362 // tags, not strings, which is coming soon. 363 // {Tag: "just-foo"}, 364 }} 365 result, err := s.uniter.Watch(args) 366 c.Assert(err, jc.ErrorIsNil) 367 c.Assert(result, gc.DeepEquals, params.NotifyWatchResults{ 368 Results: []params.NotifyWatchResult{ 369 {Error: apiservertesting.ErrUnauthorized}, 370 {NotifyWatcherId: "1"}, 371 {Error: apiservertesting.ErrUnauthorized}, 372 {Error: apiservertesting.ErrUnauthorized}, 373 {NotifyWatcherId: "2"}, 374 {Error: apiservertesting.ErrUnauthorized}, 375 // see above 376 // {Error: apiservertesting.ErrUnauthorized}, 377 }, 378 }) 379 380 // Verify the resource was registered and stop when done 381 c.Assert(s.resources.Count(), gc.Equals, 2) 382 resource1 := s.resources.Get("1") 383 defer statetesting.AssertStop(c, resource1) 384 resource2 := s.resources.Get("2") 385 defer statetesting.AssertStop(c, resource2) 386 387 // Check that the Watch has consumed the initial event ("returned" in 388 // the Watch call) 389 wc := statetesting.NewNotifyWatcherC(c, s.State, resource1.(state.NotifyWatcher)) 390 wc.AssertNoChange() 391 wc = statetesting.NewNotifyWatcherC(c, s.State, resource2.(state.NotifyWatcher)) 392 wc.AssertNoChange() 393 } 394 395 func (s *uniterSuite) TestPublicAddress(c *gc.C) { 396 // Try first without setting an address. 397 args := params.Entities{Entities: []params.Entity{ 398 {Tag: "unit-mysql-0"}, 399 {Tag: "unit-wordpress-0"}, 400 {Tag: "unit-foo-42"}, 401 }} 402 expectErr := ¶ms.Error{ 403 Code: params.CodeNoAddressSet, 404 Message: `"unit-wordpress-0" has no public address set`, 405 } 406 result, err := s.uniter.PublicAddress(args) 407 c.Assert(err, jc.ErrorIsNil) 408 c.Assert(result, gc.DeepEquals, params.StringResults{ 409 Results: []params.StringResult{ 410 {Error: apiservertesting.ErrUnauthorized}, 411 {Error: expectErr}, 412 {Error: apiservertesting.ErrUnauthorized}, 413 }, 414 }) 415 416 // Now set it an try again. 417 err = s.machine0.SetProviderAddresses( 418 network.NewScopedAddress("1.2.3.4", network.ScopePublic), 419 ) 420 c.Assert(err, jc.ErrorIsNil) 421 address, err := s.wordpressUnit.PublicAddress() 422 c.Assert(address.Value, gc.Equals, "1.2.3.4") 423 c.Assert(err, jc.ErrorIsNil) 424 425 result, err = s.uniter.PublicAddress(args) 426 c.Assert(err, jc.ErrorIsNil) 427 c.Assert(result, gc.DeepEquals, params.StringResults{ 428 Results: []params.StringResult{ 429 {Error: apiservertesting.ErrUnauthorized}, 430 {Result: "1.2.3.4"}, 431 {Error: apiservertesting.ErrUnauthorized}, 432 }, 433 }) 434 } 435 436 func (s *uniterSuite) TestPrivateAddress(c *gc.C) { 437 args := params.Entities{Entities: []params.Entity{ 438 {Tag: "unit-mysql-0"}, 439 {Tag: "unit-wordpress-0"}, 440 {Tag: "unit-foo-42"}, 441 }} 442 expectErr := ¶ms.Error{ 443 Code: params.CodeNoAddressSet, 444 Message: `"unit-wordpress-0" has no private address set`, 445 } 446 result, err := s.uniter.PrivateAddress(args) 447 c.Assert(err, jc.ErrorIsNil) 448 c.Assert(result, gc.DeepEquals, params.StringResults{ 449 Results: []params.StringResult{ 450 {Error: apiservertesting.ErrUnauthorized}, 451 {Error: expectErr}, 452 {Error: apiservertesting.ErrUnauthorized}, 453 }, 454 }) 455 456 // Now set it and try again. 457 err = s.machine0.SetProviderAddresses( 458 network.NewScopedAddress("1.2.3.4", network.ScopeCloudLocal), 459 ) 460 c.Assert(err, jc.ErrorIsNil) 461 address, err := s.wordpressUnit.PrivateAddress() 462 c.Assert(address.Value, gc.Equals, "1.2.3.4") 463 c.Assert(err, jc.ErrorIsNil) 464 465 result, err = s.uniter.PrivateAddress(args) 466 c.Assert(err, jc.ErrorIsNil) 467 c.Assert(result, gc.DeepEquals, params.StringResults{ 468 Results: []params.StringResult{ 469 {Error: apiservertesting.ErrUnauthorized}, 470 {Result: "1.2.3.4"}, 471 {Error: apiservertesting.ErrUnauthorized}, 472 }, 473 }) 474 } 475 476 func (s *uniterSuite) TestAvailabilityZone(c *gc.C) { 477 s.PatchValue(uniter.GetZone, func(st *state.State, tag names.Tag) (string, error) { 478 return "a_zone", nil 479 }) 480 481 args := params.Entities{Entities: []params.Entity{ 482 {Tag: "unit-wordpress-0"}, 483 }} 484 result, err := s.uniter.AvailabilityZone(args) 485 c.Assert(err, jc.ErrorIsNil) 486 487 c.Check(result, gc.DeepEquals, params.StringResults{ 488 Results: []params.StringResult{ 489 {Result: "a_zone"}, 490 }, 491 }) 492 } 493 494 func (s *uniterSuite) TestResolved(c *gc.C) { 495 err := s.wordpressUnit.SetResolved(state.ResolvedRetryHooks) 496 c.Assert(err, jc.ErrorIsNil) 497 mode := s.wordpressUnit.Resolved() 498 c.Assert(mode, gc.Equals, state.ResolvedRetryHooks) 499 500 args := params.Entities{Entities: []params.Entity{ 501 {Tag: "unit-mysql-0"}, 502 {Tag: "unit-wordpress-0"}, 503 {Tag: "unit-foo-42"}, 504 }} 505 result, err := s.uniter.Resolved(args) 506 c.Assert(err, jc.ErrorIsNil) 507 c.Assert(result, gc.DeepEquals, params.ResolvedModeResults{ 508 Results: []params.ResolvedModeResult{ 509 {Error: apiservertesting.ErrUnauthorized}, 510 {Mode: params.ResolvedMode(mode)}, 511 {Error: apiservertesting.ErrUnauthorized}, 512 }, 513 }) 514 } 515 516 func (s *uniterSuite) TestClearResolved(c *gc.C) { 517 err := s.wordpressUnit.SetResolved(state.ResolvedRetryHooks) 518 c.Assert(err, jc.ErrorIsNil) 519 mode := s.wordpressUnit.Resolved() 520 c.Assert(mode, gc.Equals, state.ResolvedRetryHooks) 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.ClearResolved(args) 528 c.Assert(err, jc.ErrorIsNil) 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's resolved mode has changed. 538 err = s.wordpressUnit.Refresh() 539 c.Assert(err, jc.ErrorIsNil) 540 mode = s.wordpressUnit.Resolved() 541 c.Assert(mode, gc.Equals, state.ResolvedNone) 542 } 543 544 func (s *uniterSuite) TestGetPrincipal(c *gc.C) { 545 // Add a subordinate to wordpressUnit. 546 _, _, subordinate := s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit) 547 548 principal, ok := subordinate.PrincipalName() 549 c.Assert(principal, gc.Equals, s.wordpressUnit.Name()) 550 c.Assert(ok, jc.IsTrue) 551 552 // First try it as wordpressUnit's agent. 553 args := params.Entities{Entities: []params.Entity{ 554 {Tag: "unit-mysql-0"}, 555 {Tag: "unit-wordpress-0"}, 556 {Tag: subordinate.Tag().String()}, 557 {Tag: "unit-foo-42"}, 558 }} 559 result, err := s.uniter.GetPrincipal(args) 560 c.Assert(err, jc.ErrorIsNil) 561 c.Assert(result, gc.DeepEquals, params.StringBoolResults{ 562 Results: []params.StringBoolResult{ 563 {Error: apiservertesting.ErrUnauthorized}, 564 {Result: "", Ok: false, Error: nil}, 565 {Error: apiservertesting.ErrUnauthorized}, 566 {Error: apiservertesting.ErrUnauthorized}, 567 }, 568 }) 569 570 // Now try as subordinate's agent. 571 subAuthorizer := s.authorizer 572 subAuthorizer.Tag = subordinate.Tag() 573 subUniter, err := uniter.NewUniterAPIV3(s.State, s.resources, subAuthorizer) 574 c.Assert(err, jc.ErrorIsNil) 575 576 result, err = subUniter.GetPrincipal(args) 577 c.Assert(err, jc.ErrorIsNil) 578 c.Assert(result, gc.DeepEquals, params.StringBoolResults{ 579 Results: []params.StringBoolResult{ 580 {Error: apiservertesting.ErrUnauthorized}, 581 {Error: apiservertesting.ErrUnauthorized}, 582 {Result: "unit-wordpress-0", Ok: true, Error: nil}, 583 {Error: apiservertesting.ErrUnauthorized}, 584 }, 585 }) 586 } 587 588 func (s *uniterSuite) TestHasSubordinates(c *gc.C) { 589 // Try first without any subordinates for wordpressUnit. 590 args := params.Entities{Entities: []params.Entity{ 591 {Tag: "unit-mysql-0"}, 592 {Tag: "unit-wordpress-0"}, 593 {Tag: "unit-logging-0"}, 594 {Tag: "unit-foo-42"}, 595 }} 596 result, err := s.uniter.HasSubordinates(args) 597 c.Assert(err, jc.ErrorIsNil) 598 c.Assert(result, gc.DeepEquals, params.BoolResults{ 599 Results: []params.BoolResult{ 600 {Error: apiservertesting.ErrUnauthorized}, 601 {Result: false}, 602 {Error: apiservertesting.ErrUnauthorized}, 603 {Error: apiservertesting.ErrUnauthorized}, 604 }, 605 }) 606 607 // Add two subordinates to wordpressUnit and try again. 608 s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit) 609 s.addRelatedService(c, "wordpress", "monitoring", s.wordpressUnit) 610 611 result, err = s.uniter.HasSubordinates(args) 612 c.Assert(err, jc.ErrorIsNil) 613 c.Assert(result, gc.DeepEquals, params.BoolResults{ 614 Results: []params.BoolResult{ 615 {Error: apiservertesting.ErrUnauthorized}, 616 {Result: true}, 617 {Error: apiservertesting.ErrUnauthorized}, 618 {Error: apiservertesting.ErrUnauthorized}, 619 }, 620 }) 621 } 622 623 func (s *uniterSuite) TestDestroy(c *gc.C) { 624 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive) 625 626 args := params.Entities{Entities: []params.Entity{ 627 {Tag: "unit-mysql-0"}, 628 {Tag: "unit-wordpress-0"}, 629 {Tag: "unit-foo-42"}, 630 }} 631 result, err := s.uniter.Destroy(args) 632 c.Assert(err, jc.ErrorIsNil) 633 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 634 Results: []params.ErrorResult{ 635 {apiservertesting.ErrUnauthorized}, 636 {nil}, 637 {apiservertesting.ErrUnauthorized}, 638 }, 639 }) 640 641 // Verify wordpressUnit is destroyed and removed. 642 err = s.wordpressUnit.Refresh() 643 c.Assert(err, jc.Satisfies, errors.IsNotFound) 644 } 645 646 func (s *uniterSuite) TestDestroyAllSubordinates(c *gc.C) { 647 // Add two subordinates to wordpressUnit. 648 _, _, loggingSub := s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit) 649 _, _, monitoringSub := s.addRelatedService(c, "wordpress", "monitoring", s.wordpressUnit) 650 c.Assert(loggingSub.Life(), gc.Equals, state.Alive) 651 c.Assert(monitoringSub.Life(), gc.Equals, state.Alive) 652 653 err := s.wordpressUnit.Refresh() 654 c.Assert(err, jc.ErrorIsNil) 655 subordinates := s.wordpressUnit.SubordinateNames() 656 c.Assert(subordinates, gc.DeepEquals, []string{"logging/0", "monitoring/0"}) 657 658 args := params.Entities{Entities: []params.Entity{ 659 {Tag: "unit-mysql-0"}, 660 {Tag: "unit-wordpress-0"}, 661 {Tag: "unit-foo-42"}, 662 }} 663 result, err := s.uniter.DestroyAllSubordinates(args) 664 c.Assert(err, jc.ErrorIsNil) 665 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 666 Results: []params.ErrorResult{ 667 {apiservertesting.ErrUnauthorized}, 668 {nil}, 669 {apiservertesting.ErrUnauthorized}, 670 }, 671 }) 672 673 // Verify wordpressUnit's subordinates were destroyed. 674 err = loggingSub.Refresh() 675 c.Assert(err, jc.ErrorIsNil) 676 c.Assert(loggingSub.Life(), gc.Equals, state.Dying) 677 err = monitoringSub.Refresh() 678 c.Assert(err, jc.ErrorIsNil) 679 c.Assert(monitoringSub.Life(), gc.Equals, state.Dying) 680 } 681 682 func (s *uniterSuite) TestCharmURL(c *gc.C) { 683 // Set wordpressUnit's charm URL first. 684 err := s.wordpressUnit.SetCharmURL(s.wpCharm.URL()) 685 c.Assert(err, jc.ErrorIsNil) 686 curl, ok := s.wordpressUnit.CharmURL() 687 c.Assert(curl, gc.DeepEquals, s.wpCharm.URL()) 688 c.Assert(ok, jc.IsTrue) 689 690 // Make sure wordpress service's charm is what we expect. 691 curl, force := s.wordpress.CharmURL() 692 c.Assert(curl, gc.DeepEquals, s.wpCharm.URL()) 693 c.Assert(force, jc.IsFalse) 694 695 args := params.Entities{Entities: []params.Entity{ 696 {Tag: "unit-mysql-0"}, 697 {Tag: "unit-wordpress-0"}, 698 {Tag: "unit-foo-42"}, 699 {Tag: "service-mysql"}, 700 {Tag: "service-wordpress"}, 701 {Tag: "service-foo"}, 702 // TODO(dfc) these aren't valid tags any more 703 // but I hope to restore this test when params.Entity takes 704 // tags, not strings, which is coming soon. 705 // {Tag: "just-foo"}, 706 }} 707 result, err := s.uniter.CharmURL(args) 708 c.Assert(err, jc.ErrorIsNil) 709 c.Assert(result, gc.DeepEquals, params.StringBoolResults{ 710 Results: []params.StringBoolResult{ 711 {Error: apiservertesting.ErrUnauthorized}, 712 {Result: s.wpCharm.String(), Ok: ok}, 713 {Error: apiservertesting.ErrUnauthorized}, 714 {Error: apiservertesting.ErrUnauthorized}, 715 {Result: s.wpCharm.String(), Ok: force}, 716 {Error: apiservertesting.ErrUnauthorized}, 717 // see above 718 // {Error: apiservertesting.ErrUnauthorized}, 719 }, 720 }) 721 } 722 723 func (s *uniterSuite) TestSetCharmURL(c *gc.C) { 724 _, ok := s.wordpressUnit.CharmURL() 725 c.Assert(ok, jc.IsFalse) 726 727 args := params.EntitiesCharmURL{Entities: []params.EntityCharmURL{ 728 {Tag: "unit-mysql-0", CharmURL: "cs:quantal/service-42"}, 729 {Tag: "unit-wordpress-0", CharmURL: s.wpCharm.String()}, 730 {Tag: "unit-foo-42", CharmURL: "cs:quantal/foo-321"}, 731 }} 732 result, err := s.uniter.SetCharmURL(args) 733 c.Assert(err, jc.ErrorIsNil) 734 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 735 Results: []params.ErrorResult{ 736 {apiservertesting.ErrUnauthorized}, 737 {nil}, 738 {apiservertesting.ErrUnauthorized}, 739 }, 740 }) 741 742 // Verify the charm URL was set. 743 err = s.wordpressUnit.Refresh() 744 c.Assert(err, jc.ErrorIsNil) 745 charmUrl, needsUpgrade := s.wordpressUnit.CharmURL() 746 c.Assert(charmUrl, gc.NotNil) 747 c.Assert(charmUrl.String(), gc.Equals, s.wpCharm.String()) 748 c.Assert(needsUpgrade, jc.IsTrue) 749 } 750 751 func (s *uniterSuite) TestCharmModifiedVersion(c *gc.C) { 752 args := params.Entities{Entities: []params.Entity{ 753 {Tag: "service-mysql"}, 754 {Tag: "service-wordpress"}, 755 {Tag: "unit-wordpress-0"}, 756 {Tag: "service-foo"}, 757 }} 758 result, err := s.uniter.CharmModifiedVersion(args) 759 c.Assert(err, jc.ErrorIsNil) 760 c.Assert(result, gc.DeepEquals, params.IntResults{ 761 Results: []params.IntResult{ 762 {Error: apiservertesting.ErrUnauthorized}, 763 {Result: s.wordpress.CharmModifiedVersion()}, 764 {Result: s.wordpress.CharmModifiedVersion()}, 765 {Error: apiservertesting.ErrUnauthorized}, 766 }, 767 }) 768 } 769 770 func (s *uniterSuite) TestOpenPorts(c *gc.C) { 771 openedPorts, err := s.wordpressUnit.OpenedPorts() 772 c.Assert(err, jc.ErrorIsNil) 773 c.Assert(openedPorts, gc.HasLen, 0) 774 775 args := params.EntitiesPortRanges{Entities: []params.EntityPortRange{ 776 {Tag: "unit-mysql-0", Protocol: "tcp", FromPort: 1234, ToPort: 1400}, 777 {Tag: "unit-wordpress-0", Protocol: "udp", FromPort: 4321, ToPort: 5000}, 778 {Tag: "unit-foo-42", Protocol: "tcp", FromPort: 42, ToPort: 42}, 779 }} 780 result, err := s.uniter.OpenPorts(args) 781 c.Assert(err, jc.ErrorIsNil) 782 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 783 Results: []params.ErrorResult{ 784 {apiservertesting.ErrUnauthorized}, 785 {nil}, 786 {apiservertesting.ErrUnauthorized}, 787 }, 788 }) 789 790 // Verify the wordpressUnit's port is opened. 791 openedPorts, err = s.wordpressUnit.OpenedPorts() 792 c.Assert(err, jc.ErrorIsNil) 793 c.Assert(openedPorts, gc.DeepEquals, []network.PortRange{ 794 {Protocol: "udp", FromPort: 4321, ToPort: 5000}, 795 }) 796 } 797 798 func (s *uniterSuite) TestClosePorts(c *gc.C) { 799 // Open port udp:4321 in advance on wordpressUnit. 800 err := s.wordpressUnit.OpenPorts("udp", 4321, 5000) 801 c.Assert(err, jc.ErrorIsNil) 802 openedPorts, err := s.wordpressUnit.OpenedPorts() 803 c.Assert(err, jc.ErrorIsNil) 804 c.Assert(openedPorts, gc.DeepEquals, []network.PortRange{ 805 {Protocol: "udp", FromPort: 4321, ToPort: 5000}, 806 }) 807 808 args := params.EntitiesPortRanges{Entities: []params.EntityPortRange{ 809 {Tag: "unit-mysql-0", Protocol: "tcp", FromPort: 1234, ToPort: 1400}, 810 {Tag: "unit-wordpress-0", Protocol: "udp", FromPort: 4321, ToPort: 5000}, 811 {Tag: "unit-foo-42", Protocol: "tcp", FromPort: 42, ToPort: 42}, 812 }} 813 result, err := s.uniter.ClosePorts(args) 814 c.Assert(err, jc.ErrorIsNil) 815 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 816 Results: []params.ErrorResult{ 817 {apiservertesting.ErrUnauthorized}, 818 {nil}, 819 {apiservertesting.ErrUnauthorized}, 820 }, 821 }) 822 823 // Verify the wordpressUnit's port is closed. 824 openedPorts, err = s.wordpressUnit.OpenedPorts() 825 c.Assert(err, jc.ErrorIsNil) 826 c.Assert(openedPorts, gc.HasLen, 0) 827 } 828 829 func (s *uniterSuite) TestWatchConfigSettings(c *gc.C) { 830 err := s.wordpressUnit.SetCharmURL(s.wpCharm.URL()) 831 c.Assert(err, jc.ErrorIsNil) 832 833 c.Assert(s.resources.Count(), gc.Equals, 0) 834 835 args := params.Entities{Entities: []params.Entity{ 836 {Tag: "unit-mysql-0"}, 837 {Tag: "unit-wordpress-0"}, 838 {Tag: "unit-foo-42"}, 839 }} 840 result, err := s.uniter.WatchConfigSettings(args) 841 c.Assert(err, jc.ErrorIsNil) 842 c.Assert(result, gc.DeepEquals, params.NotifyWatchResults{ 843 Results: []params.NotifyWatchResult{ 844 {Error: apiservertesting.ErrUnauthorized}, 845 {NotifyWatcherId: "1"}, 846 {Error: apiservertesting.ErrUnauthorized}, 847 }, 848 }) 849 850 // Verify the resource was registered and stop when done 851 c.Assert(s.resources.Count(), gc.Equals, 1) 852 resource := s.resources.Get("1") 853 defer statetesting.AssertStop(c, resource) 854 855 // Check that the Watch has consumed the initial event ("returned" in 856 // the Watch call) 857 wc := statetesting.NewNotifyWatcherC(c, s.State, resource.(state.NotifyWatcher)) 858 wc.AssertNoChange() 859 } 860 861 func (s *uniterSuite) TestWatchActionNotifications(c *gc.C) { 862 err := s.wordpressUnit.SetCharmURL(s.wpCharm.URL()) 863 c.Assert(err, jc.ErrorIsNil) 864 865 c.Assert(s.resources.Count(), gc.Equals, 0) 866 867 args := params.Entities{Entities: []params.Entity{ 868 {Tag: "unit-mysql-0"}, 869 {Tag: "unit-wordpress-0"}, 870 {Tag: "unit-foo-42"}, 871 }} 872 result, err := s.uniter.WatchActionNotifications(args) 873 c.Assert(err, jc.ErrorIsNil) 874 c.Assert(result, gc.DeepEquals, params.StringsWatchResults{ 875 Results: []params.StringsWatchResult{ 876 {Error: apiservertesting.ErrUnauthorized}, 877 {StringsWatcherId: "1"}, 878 {Error: apiservertesting.ErrUnauthorized}, 879 }, 880 }) 881 882 // Verify the resource was registered and stop when done 883 c.Assert(s.resources.Count(), gc.Equals, 1) 884 resource := s.resources.Get("1") 885 defer statetesting.AssertStop(c, resource) 886 887 // Check that the Watch has consumed the initial event ("returned" in 888 // the Watch call) 889 wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher)) 890 wc.AssertNoChange() 891 892 addedAction, err := s.wordpressUnit.AddAction("fakeaction", nil) 893 894 wc.AssertChange(addedAction.Id()) 895 wc.AssertNoChange() 896 } 897 898 func (s *uniterSuite) TestWatchPreexistingActions(c *gc.C) { 899 err := s.wordpressUnit.SetCharmURL(s.wpCharm.URL()) 900 c.Assert(err, jc.ErrorIsNil) 901 902 c.Assert(s.resources.Count(), gc.Equals, 0) 903 904 action1, err := s.wordpressUnit.AddAction("fakeaction", nil) 905 c.Assert(err, jc.ErrorIsNil) 906 action2, err := s.wordpressUnit.AddAction("fakeaction", nil) 907 c.Assert(err, jc.ErrorIsNil) 908 909 args := params.Entities{Entities: []params.Entity{ 910 {Tag: "unit-wordpress-0"}, 911 }} 912 913 s.State.StartSync() 914 results, err := s.uniter.WatchActionNotifications(args) 915 c.Assert(err, jc.ErrorIsNil) 916 917 checkUnorderedActionIdsEqual(c, []string{action1.Id(), action2.Id()}, results) 918 919 // Verify the resource was registered and stop when done 920 c.Assert(s.resources.Count(), gc.Equals, 1) 921 resource := s.resources.Get("1") 922 defer statetesting.AssertStop(c, resource) 923 924 // Check that the Watch has consumed the initial event ("returned" in 925 // the Watch call) 926 wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher)) 927 wc.AssertNoChange() 928 929 addedAction, err := s.wordpressUnit.AddAction("fakeaction", nil) 930 c.Assert(err, jc.ErrorIsNil) 931 wc.AssertChange(addedAction.Id()) 932 wc.AssertNoChange() 933 } 934 935 func (s *uniterSuite) TestWatchActionNotificationsMalformedTag(c *gc.C) { 936 args := params.Entities{Entities: []params.Entity{ 937 {Tag: "ewenit-mysql-0"}, 938 }} 939 results, err := s.uniter.WatchActionNotifications(args) 940 c.Assert(err, jc.ErrorIsNil) 941 c.Assert(results, gc.NotNil) 942 c.Assert(len(results.Results), gc.Equals, 1) 943 result := results.Results[0] 944 c.Assert(result.Error, gc.NotNil) 945 c.Assert(result.Error.Message, gc.Equals, `invalid actionreceiver tag "ewenit-mysql-0"`) 946 } 947 948 func (s *uniterSuite) TestWatchActionNotificationsMalformedUnitName(c *gc.C) { 949 args := params.Entities{Entities: []params.Entity{ 950 {Tag: "unit-mysql-01"}, 951 }} 952 results, err := s.uniter.WatchActionNotifications(args) 953 c.Assert(err, jc.ErrorIsNil) 954 c.Assert(results, gc.NotNil) 955 c.Assert(len(results.Results), gc.Equals, 1) 956 result := results.Results[0] 957 c.Assert(result.Error, gc.NotNil) 958 c.Assert(result.Error.Message, gc.Equals, `invalid actionreceiver tag "unit-mysql-01"`) 959 } 960 961 func (s *uniterSuite) TestWatchActionNotificationsNotUnit(c *gc.C) { 962 action, err := s.mysqlUnit.AddAction("fakeaction", nil) 963 c.Assert(err, jc.ErrorIsNil) 964 args := params.Entities{Entities: []params.Entity{ 965 {Tag: action.Tag().String()}, 966 }} 967 results, err := s.uniter.WatchActionNotifications(args) 968 c.Assert(err, jc.ErrorIsNil) 969 c.Assert(results, gc.NotNil) 970 c.Assert(len(results.Results), gc.Equals, 1) 971 result := results.Results[0] 972 c.Assert(result.Error, gc.NotNil) 973 c.Assert(result.Error.Message, gc.Equals, `invalid actionreceiver tag "action-`+action.Id()+`"`) 974 } 975 976 func (s *uniterSuite) TestWatchActionNotificationsPermissionDenied(c *gc.C) { 977 args := params.Entities{Entities: []params.Entity{ 978 {Tag: "unit-nonexistentgarbage-0"}, 979 }} 980 results, err := s.uniter.WatchActionNotifications(args) 981 c.Assert(err, jc.ErrorIsNil) 982 c.Assert(results, gc.NotNil) 983 c.Assert(len(results.Results), gc.Equals, 1) 984 result := results.Results[0] 985 c.Assert(result.Error, gc.NotNil) 986 c.Assert(result.Error.Message, gc.Equals, "permission denied") 987 } 988 989 func (s *uniterSuite) TestConfigSettings(c *gc.C) { 990 err := s.wordpressUnit.SetCharmURL(s.wpCharm.URL()) 991 c.Assert(err, jc.ErrorIsNil) 992 settings, err := s.wordpressUnit.ConfigSettings() 993 c.Assert(err, jc.ErrorIsNil) 994 c.Assert(settings, gc.DeepEquals, charm.Settings{"blog-title": "My Title"}) 995 996 args := params.Entities{Entities: []params.Entity{ 997 {Tag: "unit-mysql-0"}, 998 {Tag: "unit-wordpress-0"}, 999 {Tag: "unit-foo-42"}, 1000 }} 1001 result, err := s.uniter.ConfigSettings(args) 1002 c.Assert(err, jc.ErrorIsNil) 1003 c.Assert(result, gc.DeepEquals, params.ConfigSettingsResults{ 1004 Results: []params.ConfigSettingsResult{ 1005 {Error: apiservertesting.ErrUnauthorized}, 1006 {Settings: params.ConfigSettings{"blog-title": "My Title"}}, 1007 {Error: apiservertesting.ErrUnauthorized}, 1008 }, 1009 }) 1010 } 1011 1012 func (s *uniterSuite) TestWatchServiceRelations(c *gc.C) { 1013 c.Assert(s.resources.Count(), gc.Equals, 0) 1014 1015 args := params.Entities{Entities: []params.Entity{ 1016 {Tag: "service-mysql"}, 1017 {Tag: "service-wordpress"}, 1018 {Tag: "service-foo"}, 1019 }} 1020 result, err := s.uniter.WatchServiceRelations(args) 1021 s.assertOneStringsWatcher(c, result, err) 1022 } 1023 1024 func (s *uniterSuite) TestCharmArchiveSha256(c *gc.C) { 1025 dummyCharm := s.AddTestingCharm(c, "dummy") 1026 1027 args := params.CharmURLs{URLs: []params.CharmURL{ 1028 {URL: "something-invalid"}, 1029 {URL: s.wpCharm.String()}, 1030 {URL: dummyCharm.String()}, 1031 }} 1032 result, err := s.uniter.CharmArchiveSha256(args) 1033 c.Assert(err, jc.ErrorIsNil) 1034 c.Assert(result, gc.DeepEquals, params.StringResults{ 1035 Results: []params.StringResult{ 1036 {Error: apiservertesting.ErrUnauthorized}, 1037 {Result: s.wpCharm.BundleSha256()}, 1038 {Result: dummyCharm.BundleSha256()}, 1039 }, 1040 }) 1041 } 1042 1043 func (s *uniterSuite) TestCharmArchiveURLs(c *gc.C) { 1044 dummyCharm := s.AddTestingCharm(c, "dummy") 1045 1046 hostPorts := [][]network.HostPort{ 1047 network.AddressesWithPort([]network.Address{ 1048 network.NewScopedAddress("1.2.3.4", network.ScopePublic), 1049 network.NewScopedAddress("0.1.2.3", network.ScopeCloudLocal), 1050 }, 1234), 1051 network.AddressesWithPort([]network.Address{ 1052 network.NewScopedAddress("1.2.3.5", network.ScopePublic), 1053 }, 1234), 1054 } 1055 err := s.State.SetAPIHostPorts(hostPorts) 1056 c.Assert(err, jc.ErrorIsNil) 1057 1058 args := params.CharmURLs{URLs: []params.CharmURL{ 1059 {URL: "something-invalid!"}, 1060 {URL: s.wpCharm.String()}, 1061 {URL: dummyCharm.String()}, 1062 }} 1063 result, err := s.uniter.CharmArchiveURLs(args) 1064 c.Assert(err, jc.ErrorIsNil) 1065 1066 wordpressURLs := []string{ 1067 fmt.Sprintf("https://0.1.2.3:1234/model/%s/charms?file=%%2A&url=cs%%3Aquantal%%2Fwordpress-3", coretesting.ModelTag.Id()), 1068 fmt.Sprintf("https://1.2.3.5:1234/model/%s/charms?file=%%2A&url=cs%%3Aquantal%%2Fwordpress-3", coretesting.ModelTag.Id()), 1069 } 1070 dummyURLs := []string{ 1071 fmt.Sprintf("https://0.1.2.3:1234/model/%s/charms?file=%%2A&url=local%%3Aquantal%%2Fdummy-1", coretesting.ModelTag.Id()), 1072 fmt.Sprintf("https://1.2.3.5:1234/model/%s/charms?file=%%2A&url=local%%3Aquantal%%2Fdummy-1", coretesting.ModelTag.Id()), 1073 } 1074 1075 c.Assert(result, jc.DeepEquals, params.StringsResults{ 1076 Results: []params.StringsResult{ 1077 {Error: apiservertesting.ErrUnauthorized}, 1078 {Result: wordpressURLs}, 1079 {Result: dummyURLs}, 1080 }, 1081 }) 1082 } 1083 1084 func (s *uniterSuite) TestCurrentModel(c *gc.C) { 1085 env, err := s.State.Model() 1086 c.Assert(err, jc.ErrorIsNil) 1087 1088 result, err := s.uniter.CurrentModel() 1089 c.Assert(err, jc.ErrorIsNil) 1090 expected := params.ModelResult{ 1091 Name: env.Name(), 1092 UUID: env.UUID(), 1093 } 1094 c.Assert(result, gc.DeepEquals, expected) 1095 } 1096 1097 func (s *uniterSuite) TestActions(c *gc.C) { 1098 var actionTests = []struct { 1099 description string 1100 action params.ActionResult 1101 }{{ 1102 description: "A simple action.", 1103 action: params.ActionResult{ 1104 Action: ¶ms.Action{ 1105 Name: "fakeaction", 1106 Parameters: map[string]interface{}{ 1107 "outfile": "foo.txt", 1108 }}, 1109 }, 1110 }, { 1111 description: "An action with nested parameters.", 1112 action: params.ActionResult{ 1113 Action: ¶ms.Action{ 1114 Name: "fakeaction", 1115 Parameters: map[string]interface{}{ 1116 "outfile": "foo.bz2", 1117 "compression": map[string]interface{}{ 1118 "kind": "bzip", 1119 "quality": 5, 1120 }, 1121 }}, 1122 }, 1123 }} 1124 1125 for i, actionTest := range actionTests { 1126 c.Logf("test %d: %s", i, actionTest.description) 1127 1128 a, err := s.wordpressUnit.AddAction( 1129 actionTest.action.Action.Name, 1130 actionTest.action.Action.Parameters) 1131 c.Assert(err, jc.ErrorIsNil) 1132 c.Assert(names.IsValidAction(a.Id()), gc.Equals, true) 1133 actionTag := names.NewActionTag(a.Id()) 1134 c.Assert(a.ActionTag(), gc.Equals, actionTag) 1135 1136 args := params.Entities{ 1137 Entities: []params.Entity{{ 1138 Tag: actionTag.String(), 1139 }}, 1140 } 1141 results, err := s.uniter.Actions(args) 1142 c.Assert(err, jc.ErrorIsNil) 1143 c.Assert(results.Results, gc.HasLen, 1) 1144 1145 actionsQueryResult := results.Results[0] 1146 1147 c.Assert(actionsQueryResult, jc.DeepEquals, actionTest.action) 1148 } 1149 } 1150 1151 func (s *uniterSuite) TestActionsNotPresent(c *gc.C) { 1152 uuid, err := utils.NewUUID() 1153 c.Assert(err, jc.ErrorIsNil) 1154 args := params.Entities{ 1155 Entities: []params.Entity{{ 1156 Tag: names.NewActionTag(uuid.String()).String(), 1157 }}, 1158 } 1159 results, err := s.uniter.Actions(args) 1160 c.Assert(err, jc.ErrorIsNil) 1161 1162 c.Assert(results.Results, gc.HasLen, 1) 1163 actionsQueryResult := results.Results[0] 1164 c.Assert(actionsQueryResult.Error, gc.NotNil) 1165 c.Assert(actionsQueryResult.Error, gc.ErrorMatches, `action "[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}" not found`) 1166 } 1167 1168 func (s *uniterSuite) TestActionsWrongUnit(c *gc.C) { 1169 // Action doesn't match unit. 1170 mysqlUnitAuthorizer := apiservertesting.FakeAuthorizer{ 1171 Tag: s.mysqlUnit.Tag(), 1172 } 1173 mysqlUnitFacade, err := uniter.NewUniterAPIV3(s.State, s.resources, mysqlUnitAuthorizer) 1174 c.Assert(err, jc.ErrorIsNil) 1175 1176 action, err := s.wordpressUnit.AddAction("fakeaction", nil) 1177 c.Assert(err, jc.ErrorIsNil) 1178 args := params.Entities{ 1179 Entities: []params.Entity{{ 1180 Tag: action.Tag().String(), 1181 }}, 1182 } 1183 actions, err := mysqlUnitFacade.Actions(args) 1184 c.Assert(err, jc.ErrorIsNil) 1185 c.Assert(len(actions.Results), gc.Equals, 1) 1186 c.Assert(actions.Results[0].Error, jc.Satisfies, params.IsCodeUnauthorized) 1187 } 1188 1189 func (s *uniterSuite) TestActionsPermissionDenied(c *gc.C) { 1190 action, err := s.mysqlUnit.AddAction("fakeaction", nil) 1191 c.Assert(err, jc.ErrorIsNil) 1192 args := params.Entities{ 1193 Entities: []params.Entity{{ 1194 Tag: action.Tag().String(), 1195 }}, 1196 } 1197 actions, err := s.uniter.Actions(args) 1198 c.Assert(err, jc.ErrorIsNil) 1199 c.Assert(len(actions.Results), gc.Equals, 1) 1200 c.Assert(actions.Results[0].Error, jc.Satisfies, params.IsCodeUnauthorized) 1201 } 1202 1203 func (s *uniterSuite) TestFinishActionsSuccess(c *gc.C) { 1204 testName := "fakeaction" 1205 testOutput := map[string]interface{}{"output": "completed fakeaction successfully"} 1206 1207 results, err := s.wordpressUnit.CompletedActions() 1208 c.Assert(err, jc.ErrorIsNil) 1209 c.Assert(results, gc.DeepEquals, ([]state.Action)(nil)) 1210 1211 action, err := s.wordpressUnit.AddAction(testName, nil) 1212 c.Assert(err, jc.ErrorIsNil) 1213 1214 actionResults := params.ActionExecutionResults{ 1215 Results: []params.ActionExecutionResult{{ 1216 ActionTag: action.ActionTag().String(), 1217 Status: params.ActionCompleted, 1218 Results: testOutput, 1219 }}, 1220 } 1221 res, err := s.uniter.FinishActions(actionResults) 1222 c.Assert(err, jc.ErrorIsNil) 1223 c.Assert(res, gc.DeepEquals, params.ErrorResults{Results: []params.ErrorResult{{Error: nil}}}) 1224 1225 results, err = s.wordpressUnit.CompletedActions() 1226 c.Assert(err, jc.ErrorIsNil) 1227 c.Assert(len(results), gc.Equals, 1) 1228 c.Assert(results[0].Status(), gc.Equals, state.ActionCompleted) 1229 res2, errstr := results[0].Results() 1230 c.Assert(errstr, gc.Equals, "") 1231 c.Assert(res2, gc.DeepEquals, testOutput) 1232 c.Assert(results[0].Name(), gc.Equals, testName) 1233 } 1234 1235 func (s *uniterSuite) TestFinishActionsFailure(c *gc.C) { 1236 testName := "fakeaction" 1237 testError := "fakeaction was a dismal failure" 1238 1239 results, err := s.wordpressUnit.CompletedActions() 1240 c.Assert(err, jc.ErrorIsNil) 1241 c.Assert(results, gc.DeepEquals, ([]state.Action)(nil)) 1242 1243 action, err := s.wordpressUnit.AddAction(testName, nil) 1244 c.Assert(err, jc.ErrorIsNil) 1245 1246 actionResults := params.ActionExecutionResults{ 1247 Results: []params.ActionExecutionResult{{ 1248 ActionTag: action.ActionTag().String(), 1249 Status: params.ActionFailed, 1250 Results: nil, 1251 Message: testError, 1252 }}, 1253 } 1254 res, err := s.uniter.FinishActions(actionResults) 1255 c.Assert(err, jc.ErrorIsNil) 1256 c.Assert(res, gc.DeepEquals, params.ErrorResults{Results: []params.ErrorResult{{Error: nil}}}) 1257 1258 results, err = s.wordpressUnit.CompletedActions() 1259 c.Assert(err, jc.ErrorIsNil) 1260 c.Assert(len(results), gc.Equals, 1) 1261 c.Assert(results[0].Status(), gc.Equals, state.ActionFailed) 1262 res2, errstr := results[0].Results() 1263 c.Assert(errstr, gc.Equals, testError) 1264 c.Assert(res2, gc.DeepEquals, map[string]interface{}{}) 1265 c.Assert(results[0].Name(), gc.Equals, testName) 1266 } 1267 1268 func (s *uniterSuite) TestFinishActionsAuthAccess(c *gc.C) { 1269 good, err := s.wordpressUnit.AddAction("fakeaction", nil) 1270 c.Assert(err, jc.ErrorIsNil) 1271 1272 bad, err := s.mysqlUnit.AddAction("fakeaction", nil) 1273 c.Assert(err, jc.ErrorIsNil) 1274 1275 var tests = []struct { 1276 actionTag names.ActionTag 1277 err error 1278 }{ 1279 {actionTag: good.ActionTag(), err: nil}, 1280 {actionTag: bad.ActionTag(), err: common.ErrPerm}, 1281 } 1282 1283 // Queue up actions from tests 1284 actionResults := params.ActionExecutionResults{Results: make([]params.ActionExecutionResult, len(tests))} 1285 for i, test := range tests { 1286 actionResults.Results[i] = params.ActionExecutionResult{ 1287 ActionTag: test.actionTag.String(), 1288 Status: params.ActionCompleted, 1289 Results: map[string]interface{}{}, 1290 } 1291 } 1292 1293 // Invoke FinishActions 1294 res, err := s.uniter.FinishActions(actionResults) 1295 c.Assert(err, jc.ErrorIsNil) 1296 1297 // Verify permissions errors for actions queued on different unit 1298 for i, result := range res.Results { 1299 expected := tests[i].err 1300 if expected != nil { 1301 c.Assert(result.Error, gc.NotNil) 1302 c.Assert(result.Error.Error(), gc.Equals, expected.Error()) 1303 } else { 1304 c.Assert(result.Error, gc.IsNil) 1305 } 1306 } 1307 } 1308 1309 func (s *uniterSuite) TestBeginActions(c *gc.C) { 1310 ten_seconds_ago := time.Now().Add(-10 * time.Second) 1311 good, err := s.wordpressUnit.AddAction("fakeaction", nil) 1312 c.Assert(err, jc.ErrorIsNil) 1313 1314 running, err := s.wordpressUnit.RunningActions() 1315 c.Assert(err, jc.ErrorIsNil) 1316 c.Assert(len(running), gc.Equals, 0, gc.Commentf("expected no running actions, got %d", len(running))) 1317 1318 args := params.Entities{Entities: []params.Entity{{Tag: good.ActionTag().String()}}} 1319 res, err := s.uniter.BeginActions(args) 1320 c.Assert(err, jc.ErrorIsNil) 1321 c.Assert(len(res.Results), gc.Equals, 1) 1322 c.Assert(res.Results[0].Error, gc.IsNil) 1323 1324 running, err = s.wordpressUnit.RunningActions() 1325 c.Assert(err, jc.ErrorIsNil) 1326 c.Assert(len(running), gc.Equals, 1, gc.Commentf("expected one running action, got %d", len(running))) 1327 c.Assert(running[0].ActionTag(), gc.Equals, good.ActionTag()) 1328 enqueued, started := running[0].Enqueued(), running[0].Started() 1329 c.Assert(ten_seconds_ago.Before(enqueued), jc.IsTrue, gc.Commentf("enqueued time should be after 10 seconds ago")) 1330 c.Assert(ten_seconds_ago.Before(started), jc.IsTrue, gc.Commentf("started time should be after 10 seconds ago")) 1331 c.Assert(started.After(enqueued) || started.Equal(enqueued), jc.IsTrue, gc.Commentf("started should be after or equal to enqueued time")) 1332 } 1333 1334 func (s *uniterSuite) TestRelation(c *gc.C) { 1335 rel := s.addRelation(c, "wordpress", "mysql") 1336 wpEp, err := rel.Endpoint("wordpress") 1337 c.Assert(err, jc.ErrorIsNil) 1338 1339 args := params.RelationUnits{RelationUnits: []params.RelationUnit{ 1340 {Relation: "relation-42", Unit: "unit-foo-0"}, 1341 {Relation: rel.Tag().String(), Unit: "unit-wordpress-0"}, 1342 {Relation: rel.Tag().String(), Unit: "unit-mysql-0"}, 1343 {Relation: rel.Tag().String(), Unit: "unit-foo-0"}, 1344 {Relation: "relation-blah", Unit: "unit-wordpress-0"}, 1345 {Relation: "service-foo", Unit: "user-foo"}, 1346 {Relation: "foo", Unit: "bar"}, 1347 {Relation: "unit-wordpress-0", Unit: rel.Tag().String()}, 1348 }} 1349 result, err := s.uniter.Relation(args) 1350 c.Assert(err, jc.ErrorIsNil) 1351 c.Assert(result, gc.DeepEquals, params.RelationResults{ 1352 Results: []params.RelationResult{ 1353 {Error: apiservertesting.ErrUnauthorized}, 1354 { 1355 Id: rel.Id(), 1356 Key: rel.String(), 1357 Life: params.Life(rel.Life().String()), 1358 Endpoint: multiwatcher.Endpoint{ 1359 ServiceName: wpEp.ServiceName, 1360 Relation: wpEp.Relation, 1361 }, 1362 }, 1363 {Error: apiservertesting.ErrUnauthorized}, 1364 {Error: apiservertesting.ErrUnauthorized}, 1365 {Error: apiservertesting.ErrUnauthorized}, 1366 {Error: apiservertesting.ErrUnauthorized}, 1367 {Error: apiservertesting.ErrUnauthorized}, 1368 {Error: apiservertesting.ErrUnauthorized}, 1369 }, 1370 }) 1371 } 1372 1373 func (s *uniterSuite) TestRelationById(c *gc.C) { 1374 rel := s.addRelation(c, "wordpress", "mysql") 1375 c.Assert(rel.Id(), gc.Equals, 0) 1376 wpEp, err := rel.Endpoint("wordpress") 1377 c.Assert(err, jc.ErrorIsNil) 1378 1379 // Add another relation to mysql service, so we can see we can't 1380 // get it. 1381 otherRel, _, _ := s.addRelatedService(c, "mysql", "logging", s.mysqlUnit) 1382 1383 args := params.RelationIds{ 1384 RelationIds: []int{-1, rel.Id(), otherRel.Id(), 42, 234}, 1385 } 1386 result, err := s.uniter.RelationById(args) 1387 c.Assert(err, jc.ErrorIsNil) 1388 c.Assert(result, gc.DeepEquals, params.RelationResults{ 1389 Results: []params.RelationResult{ 1390 {Error: apiservertesting.ErrUnauthorized}, 1391 { 1392 Id: rel.Id(), 1393 Key: rel.String(), 1394 Life: params.Life(rel.Life().String()), 1395 Endpoint: multiwatcher.Endpoint{ 1396 ServiceName: wpEp.ServiceName, 1397 Relation: wpEp.Relation, 1398 }, 1399 }, 1400 {Error: apiservertesting.ErrUnauthorized}, 1401 {Error: apiservertesting.ErrUnauthorized}, 1402 {Error: apiservertesting.ErrUnauthorized}, 1403 }, 1404 }) 1405 } 1406 1407 func (s *uniterSuite) TestProviderType(c *gc.C) { 1408 cfg, err := s.State.ModelConfig() 1409 c.Assert(err, jc.ErrorIsNil) 1410 1411 result, err := s.uniter.ProviderType() 1412 c.Assert(err, jc.ErrorIsNil) 1413 c.Assert(result, gc.DeepEquals, params.StringResult{Result: cfg.Type()}) 1414 } 1415 1416 func (s *uniterSuite) TestEnterScope(c *gc.C) { 1417 // Set wordpressUnit's private address first. 1418 err := s.machine0.SetProviderAddresses( 1419 network.NewScopedAddress("1.2.3.4", network.ScopeCloudLocal), 1420 ) 1421 c.Assert(err, jc.ErrorIsNil) 1422 1423 rel := s.addRelation(c, "wordpress", "mysql") 1424 relUnit, err := rel.Unit(s.wordpressUnit) 1425 c.Assert(err, jc.ErrorIsNil) 1426 s.assertInScope(c, relUnit, false) 1427 1428 args := params.RelationUnits{RelationUnits: []params.RelationUnit{ 1429 {Relation: "relation-42", Unit: "unit-foo-0"}, 1430 {Relation: rel.Tag().String(), Unit: "unit-wordpress-0"}, 1431 {Relation: rel.Tag().String(), Unit: "unit-wordpress-0"}, 1432 {Relation: "relation-42", Unit: "unit-wordpress-0"}, 1433 {Relation: "relation-foo", Unit: "unit-wordpress-0"}, 1434 {Relation: "service-wordpress", Unit: "unit-foo-0"}, 1435 {Relation: "foo", Unit: "bar"}, 1436 {Relation: rel.Tag().String(), Unit: "unit-mysql-0"}, 1437 {Relation: rel.Tag().String(), Unit: "service-wordpress"}, 1438 {Relation: rel.Tag().String(), Unit: "service-mysql"}, 1439 {Relation: rel.Tag().String(), Unit: "user-foo"}, 1440 }} 1441 result, err := s.uniter.EnterScope(args) 1442 c.Assert(err, jc.ErrorIsNil) 1443 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1444 Results: []params.ErrorResult{ 1445 {apiservertesting.ErrUnauthorized}, 1446 {nil}, 1447 {nil}, 1448 {apiservertesting.ErrUnauthorized}, 1449 {apiservertesting.ErrUnauthorized}, 1450 {apiservertesting.ErrUnauthorized}, 1451 {apiservertesting.ErrUnauthorized}, 1452 {apiservertesting.ErrUnauthorized}, 1453 {apiservertesting.ErrUnauthorized}, 1454 {apiservertesting.ErrUnauthorized}, 1455 {apiservertesting.ErrUnauthorized}, 1456 }, 1457 }) 1458 1459 // Verify the scope changes and settings. 1460 s.assertInScope(c, relUnit, true) 1461 readSettings, err := relUnit.ReadSettings(s.wordpressUnit.Name()) 1462 c.Assert(err, jc.ErrorIsNil) 1463 c.Assert(readSettings, gc.DeepEquals, map[string]interface{}{ 1464 "private-address": "1.2.3.4", 1465 }) 1466 } 1467 1468 func (s *uniterSuite) TestLeaveScope(c *gc.C) { 1469 rel := s.addRelation(c, "wordpress", "mysql") 1470 relUnit, err := rel.Unit(s.wordpressUnit) 1471 c.Assert(err, jc.ErrorIsNil) 1472 settings := map[string]interface{}{ 1473 "some": "settings", 1474 } 1475 err = relUnit.EnterScope(settings) 1476 c.Assert(err, jc.ErrorIsNil) 1477 s.assertInScope(c, relUnit, true) 1478 1479 args := params.RelationUnits{RelationUnits: []params.RelationUnit{ 1480 {Relation: "relation-42", Unit: "unit-foo-0"}, 1481 {Relation: rel.Tag().String(), Unit: "unit-wordpress-0"}, 1482 {Relation: rel.Tag().String(), Unit: "unit-wordpress-0"}, 1483 {Relation: "relation-42", Unit: "unit-wordpress-0"}, 1484 {Relation: "relation-foo", Unit: "unit-wordpress-0"}, 1485 {Relation: "service-wordpress", Unit: "unit-foo-0"}, 1486 {Relation: "foo", Unit: "bar"}, 1487 {Relation: rel.Tag().String(), Unit: "unit-mysql-0"}, 1488 {Relation: rel.Tag().String(), Unit: "service-wordpress"}, 1489 {Relation: rel.Tag().String(), Unit: "service-mysql"}, 1490 {Relation: rel.Tag().String(), Unit: "user-foo"}, 1491 }} 1492 result, err := s.uniter.LeaveScope(args) 1493 c.Assert(err, jc.ErrorIsNil) 1494 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1495 Results: []params.ErrorResult{ 1496 {apiservertesting.ErrUnauthorized}, 1497 {nil}, 1498 {nil}, 1499 {apiservertesting.ErrUnauthorized}, 1500 {apiservertesting.ErrUnauthorized}, 1501 {apiservertesting.ErrUnauthorized}, 1502 {apiservertesting.ErrUnauthorized}, 1503 {apiservertesting.ErrUnauthorized}, 1504 {apiservertesting.ErrUnauthorized}, 1505 {apiservertesting.ErrUnauthorized}, 1506 {apiservertesting.ErrUnauthorized}, 1507 }, 1508 }) 1509 1510 // Verify the scope changes. 1511 s.assertInScope(c, relUnit, false) 1512 readSettings, err := relUnit.ReadSettings(s.wordpressUnit.Name()) 1513 c.Assert(err, jc.ErrorIsNil) 1514 c.Assert(readSettings, gc.DeepEquals, settings) 1515 } 1516 1517 func (s *uniterSuite) TestJoinedRelations(c *gc.C) { 1518 rel := s.addRelation(c, "wordpress", "mysql") 1519 relUnit, err := rel.Unit(s.wordpressUnit) 1520 c.Assert(err, jc.ErrorIsNil) 1521 err = relUnit.EnterScope(nil) 1522 c.Assert(err, jc.ErrorIsNil) 1523 1524 args := params.Entities{ 1525 Entities: []params.Entity{ 1526 {s.wordpressUnit.Tag().String()}, 1527 {s.mysqlUnit.Tag().String()}, 1528 {"unit-unknown-1"}, 1529 {"service-wordpress"}, 1530 {"machine-0"}, 1531 {rel.Tag().String()}, 1532 }, 1533 } 1534 expect := params.StringsResults{ 1535 Results: []params.StringsResult{ 1536 {Result: []string{rel.Tag().String()}}, 1537 {Error: apiservertesting.ErrUnauthorized}, 1538 {Error: apiservertesting.ErrUnauthorized}, 1539 {Error: apiservertesting.ErrUnauthorized}, 1540 {Error: apiservertesting.ErrUnauthorized}, 1541 {Error: apiservertesting.ErrUnauthorized}, 1542 }, 1543 } 1544 check := func() { 1545 result, err := s.uniter.JoinedRelations(args) 1546 c.Assert(err, jc.ErrorIsNil) 1547 c.Assert(result, gc.DeepEquals, expect) 1548 } 1549 check() 1550 err = relUnit.PrepareLeaveScope() 1551 c.Assert(err, jc.ErrorIsNil) 1552 check() 1553 } 1554 1555 func (s *uniterSuite) TestReadSettings(c *gc.C) { 1556 rel := s.addRelation(c, "wordpress", "mysql") 1557 relUnit, err := rel.Unit(s.wordpressUnit) 1558 c.Assert(err, jc.ErrorIsNil) 1559 settings := map[string]interface{}{ 1560 "some": "settings", 1561 } 1562 err = relUnit.EnterScope(settings) 1563 c.Assert(err, jc.ErrorIsNil) 1564 s.assertInScope(c, relUnit, true) 1565 1566 args := params.RelationUnits{RelationUnits: []params.RelationUnit{ 1567 {Relation: "relation-42", Unit: "unit-foo-0"}, 1568 {Relation: rel.Tag().String(), Unit: "unit-wordpress-0"}, 1569 {Relation: rel.Tag().String(), Unit: "unit-mysql-0"}, 1570 {Relation: "relation-42", Unit: "unit-wordpress-0"}, 1571 {Relation: "relation-foo", Unit: ""}, 1572 {Relation: "service-wordpress", Unit: "unit-foo-0"}, 1573 {Relation: "foo", Unit: "bar"}, 1574 {Relation: rel.Tag().String(), Unit: "unit-mysql-0"}, 1575 {Relation: rel.Tag().String(), Unit: "service-wordpress"}, 1576 {Relation: rel.Tag().String(), Unit: "service-mysql"}, 1577 {Relation: rel.Tag().String(), Unit: "user-foo"}, 1578 }} 1579 result, err := s.uniter.ReadSettings(args) 1580 c.Assert(err, jc.ErrorIsNil) 1581 c.Assert(result, gc.DeepEquals, params.SettingsResults{ 1582 Results: []params.SettingsResult{ 1583 {Error: apiservertesting.ErrUnauthorized}, 1584 {Settings: params.Settings{ 1585 "some": "settings", 1586 }}, 1587 {Error: apiservertesting.ErrUnauthorized}, 1588 {Error: apiservertesting.ErrUnauthorized}, 1589 {Error: apiservertesting.ErrUnauthorized}, 1590 {Error: apiservertesting.ErrUnauthorized}, 1591 {Error: apiservertesting.ErrUnauthorized}, 1592 {Error: apiservertesting.ErrUnauthorized}, 1593 {Error: apiservertesting.ErrUnauthorized}, 1594 {Error: apiservertesting.ErrUnauthorized}, 1595 {Error: apiservertesting.ErrUnauthorized}, 1596 }, 1597 }) 1598 } 1599 1600 func (s *uniterSuite) TestReadSettingsWithNonStringValuesFails(c *gc.C) { 1601 rel := s.addRelation(c, "wordpress", "mysql") 1602 relUnit, err := rel.Unit(s.wordpressUnit) 1603 c.Assert(err, jc.ErrorIsNil) 1604 settings := map[string]interface{}{ 1605 "other": "things", 1606 "invalid-bool": false, 1607 } 1608 err = relUnit.EnterScope(settings) 1609 c.Assert(err, jc.ErrorIsNil) 1610 s.assertInScope(c, relUnit, true) 1611 1612 args := params.RelationUnits{RelationUnits: []params.RelationUnit{ 1613 {Relation: rel.Tag().String(), Unit: "unit-wordpress-0"}, 1614 }} 1615 expectErr := `unexpected relation setting "invalid-bool": expected string, got bool` 1616 result, err := s.uniter.ReadSettings(args) 1617 c.Assert(err, jc.ErrorIsNil) 1618 c.Assert(result, gc.DeepEquals, params.SettingsResults{ 1619 Results: []params.SettingsResult{ 1620 {Error: ¶ms.Error{Message: expectErr}}, 1621 }, 1622 }) 1623 } 1624 1625 func (s *uniterSuite) TestReadRemoteSettings(c *gc.C) { 1626 rel := s.addRelation(c, "wordpress", "mysql") 1627 relUnit, err := rel.Unit(s.wordpressUnit) 1628 c.Assert(err, jc.ErrorIsNil) 1629 settings := map[string]interface{}{ 1630 "some": "settings", 1631 } 1632 err = relUnit.EnterScope(settings) 1633 c.Assert(err, jc.ErrorIsNil) 1634 s.assertInScope(c, relUnit, true) 1635 1636 // First test most of the invalid args tests and try to read the 1637 // (unset) remote unit settings. 1638 args := params.RelationUnitPairs{RelationUnitPairs: []params.RelationUnitPair{ 1639 {Relation: "relation-42", LocalUnit: "unit-foo-0", RemoteUnit: "foo"}, 1640 {Relation: rel.Tag().String(), LocalUnit: "unit-wordpress-0", RemoteUnit: "unit-wordpress-0"}, 1641 {Relation: rel.Tag().String(), LocalUnit: "unit-wordpress-0", RemoteUnit: "unit-mysql-0"}, 1642 {Relation: "relation-42", LocalUnit: "unit-wordpress-0", RemoteUnit: ""}, 1643 {Relation: "relation-foo", LocalUnit: "", RemoteUnit: ""}, 1644 {Relation: "service-wordpress", LocalUnit: "unit-foo-0", RemoteUnit: "user-foo"}, 1645 {Relation: "foo", LocalUnit: "bar", RemoteUnit: "baz"}, 1646 {Relation: rel.Tag().String(), LocalUnit: "unit-mysql-0", RemoteUnit: "unit-wordpress-0"}, 1647 {Relation: rel.Tag().String(), LocalUnit: "service-wordpress", RemoteUnit: "service-mysql"}, 1648 {Relation: rel.Tag().String(), LocalUnit: "service-mysql", RemoteUnit: "foo"}, 1649 {Relation: rel.Tag().String(), LocalUnit: "user-foo", RemoteUnit: "unit-wordpress-0"}, 1650 }} 1651 result, err := s.uniter.ReadRemoteSettings(args) 1652 1653 // We don't set the remote unit settings on purpose to test the error. 1654 expectErr := `cannot read settings for unit "mysql/0" in relation "wordpress:db mysql:server": settings` 1655 c.Assert(err, jc.ErrorIsNil) 1656 c.Assert(result, jc.DeepEquals, params.SettingsResults{ 1657 Results: []params.SettingsResult{ 1658 {Error: apiservertesting.ErrUnauthorized}, 1659 {Error: apiservertesting.ErrUnauthorized}, 1660 {Error: apiservertesting.NotFoundError(expectErr)}, 1661 {Error: apiservertesting.ErrUnauthorized}, 1662 {Error: apiservertesting.ErrUnauthorized}, 1663 {Error: apiservertesting.ErrUnauthorized}, 1664 {Error: apiservertesting.ErrUnauthorized}, 1665 {Error: apiservertesting.ErrUnauthorized}, 1666 {Error: apiservertesting.ErrUnauthorized}, 1667 {Error: apiservertesting.ErrUnauthorized}, 1668 {Error: apiservertesting.ErrUnauthorized}, 1669 }, 1670 }) 1671 1672 // Now leave the mysqlUnit and re-enter with new settings. 1673 relUnit, err = rel.Unit(s.mysqlUnit) 1674 c.Assert(err, jc.ErrorIsNil) 1675 settings = map[string]interface{}{ 1676 "other": "things", 1677 } 1678 err = relUnit.LeaveScope() 1679 c.Assert(err, jc.ErrorIsNil) 1680 s.assertInScope(c, relUnit, false) 1681 err = relUnit.EnterScope(settings) 1682 c.Assert(err, jc.ErrorIsNil) 1683 s.assertInScope(c, relUnit, true) 1684 1685 // Test the remote unit settings can be read. 1686 args = params.RelationUnitPairs{RelationUnitPairs: []params.RelationUnitPair{{ 1687 Relation: rel.Tag().String(), 1688 LocalUnit: "unit-wordpress-0", 1689 RemoteUnit: "unit-mysql-0", 1690 }}} 1691 expect := params.SettingsResults{ 1692 Results: []params.SettingsResult{ 1693 {Settings: params.Settings{ 1694 "other": "things", 1695 }}, 1696 }, 1697 } 1698 result, err = s.uniter.ReadRemoteSettings(args) 1699 c.Assert(err, jc.ErrorIsNil) 1700 c.Assert(result, gc.DeepEquals, expect) 1701 1702 // Now destroy the remote unit, and check its settings can still be read. 1703 err = s.mysqlUnit.Destroy() 1704 c.Assert(err, jc.ErrorIsNil) 1705 err = s.mysqlUnit.EnsureDead() 1706 c.Assert(err, jc.ErrorIsNil) 1707 err = s.mysqlUnit.Remove() 1708 c.Assert(err, jc.ErrorIsNil) 1709 result, err = s.uniter.ReadRemoteSettings(args) 1710 c.Assert(err, jc.ErrorIsNil) 1711 c.Assert(result, gc.DeepEquals, expect) 1712 } 1713 1714 func (s *uniterSuite) TestReadRemoteSettingsWithNonStringValuesFails(c *gc.C) { 1715 rel := s.addRelation(c, "wordpress", "mysql") 1716 relUnit, err := rel.Unit(s.mysqlUnit) 1717 c.Assert(err, jc.ErrorIsNil) 1718 settings := map[string]interface{}{ 1719 "other": "things", 1720 "invalid-bool": false, 1721 } 1722 err = relUnit.EnterScope(settings) 1723 c.Assert(err, jc.ErrorIsNil) 1724 s.assertInScope(c, relUnit, true) 1725 1726 args := params.RelationUnitPairs{RelationUnitPairs: []params.RelationUnitPair{{ 1727 Relation: rel.Tag().String(), 1728 LocalUnit: "unit-wordpress-0", 1729 RemoteUnit: "unit-mysql-0", 1730 }}} 1731 expectErr := `unexpected relation setting "invalid-bool": expected string, got bool` 1732 result, err := s.uniter.ReadRemoteSettings(args) 1733 c.Assert(err, jc.ErrorIsNil) 1734 c.Assert(result, gc.DeepEquals, params.SettingsResults{ 1735 Results: []params.SettingsResult{ 1736 {Error: ¶ms.Error{Message: expectErr}}, 1737 }, 1738 }) 1739 } 1740 1741 func (s *uniterSuite) TestUpdateSettings(c *gc.C) { 1742 rel := s.addRelation(c, "wordpress", "mysql") 1743 relUnit, err := rel.Unit(s.wordpressUnit) 1744 c.Assert(err, jc.ErrorIsNil) 1745 settings := map[string]interface{}{ 1746 "some": "settings", 1747 "other": "stuff", 1748 } 1749 err = relUnit.EnterScope(settings) 1750 s.assertInScope(c, relUnit, true) 1751 1752 newSettings := params.Settings{ 1753 "some": "different", 1754 "other": "", 1755 } 1756 1757 args := params.RelationUnitsSettings{RelationUnits: []params.RelationUnitSettings{ 1758 {Relation: "relation-42", Unit: "unit-foo-0", Settings: nil}, 1759 {Relation: rel.Tag().String(), Unit: "unit-wordpress-0", Settings: newSettings}, 1760 {Relation: "relation-42", Unit: "unit-wordpress-0", Settings: nil}, 1761 {Relation: "relation-foo", Unit: "unit-wordpress-0", Settings: nil}, 1762 {Relation: "service-wordpress", Unit: "unit-foo-0", Settings: nil}, 1763 {Relation: "foo", Unit: "bar", Settings: nil}, 1764 {Relation: rel.Tag().String(), Unit: "unit-mysql-0", Settings: nil}, 1765 {Relation: rel.Tag().String(), Unit: "service-wordpress", Settings: nil}, 1766 {Relation: rel.Tag().String(), Unit: "service-mysql", Settings: nil}, 1767 {Relation: rel.Tag().String(), Unit: "user-foo", Settings: nil}, 1768 }} 1769 result, err := s.uniter.UpdateSettings(args) 1770 c.Assert(err, jc.ErrorIsNil) 1771 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1772 Results: []params.ErrorResult{ 1773 {apiservertesting.ErrUnauthorized}, 1774 {nil}, 1775 {apiservertesting.ErrUnauthorized}, 1776 {apiservertesting.ErrUnauthorized}, 1777 {apiservertesting.ErrUnauthorized}, 1778 {apiservertesting.ErrUnauthorized}, 1779 {apiservertesting.ErrUnauthorized}, 1780 {apiservertesting.ErrUnauthorized}, 1781 {apiservertesting.ErrUnauthorized}, 1782 {apiservertesting.ErrUnauthorized}, 1783 }, 1784 }) 1785 1786 // Verify the settings were saved. 1787 s.assertInScope(c, relUnit, true) 1788 readSettings, err := relUnit.ReadSettings(s.wordpressUnit.Name()) 1789 c.Assert(err, jc.ErrorIsNil) 1790 c.Assert(readSettings, gc.DeepEquals, map[string]interface{}{ 1791 "some": "different", 1792 }) 1793 } 1794 1795 func (s *uniterSuite) TestWatchRelationUnits(c *gc.C) { 1796 // Add a relation between wordpress and mysql and enter scope with 1797 // mysqlUnit. 1798 rel := s.addRelation(c, "wordpress", "mysql") 1799 myRelUnit, err := rel.Unit(s.mysqlUnit) 1800 c.Assert(err, jc.ErrorIsNil) 1801 err = myRelUnit.EnterScope(nil) 1802 c.Assert(err, jc.ErrorIsNil) 1803 s.assertInScope(c, myRelUnit, true) 1804 1805 c.Assert(s.resources.Count(), gc.Equals, 0) 1806 1807 args := params.RelationUnits{RelationUnits: []params.RelationUnit{ 1808 {Relation: "relation-42", Unit: "unit-foo-0"}, 1809 {Relation: rel.Tag().String(), Unit: "unit-wordpress-0"}, 1810 {Relation: rel.Tag().String(), Unit: "unit-mysql-0"}, 1811 {Relation: "relation-42", Unit: "unit-wordpress-0"}, 1812 {Relation: "relation-foo", Unit: ""}, 1813 {Relation: "service-wordpress", Unit: "unit-foo-0"}, 1814 {Relation: "foo", Unit: "bar"}, 1815 {Relation: rel.Tag().String(), Unit: "unit-mysql-0"}, 1816 {Relation: rel.Tag().String(), Unit: "service-wordpress"}, 1817 {Relation: rel.Tag().String(), Unit: "service-mysql"}, 1818 {Relation: rel.Tag().String(), Unit: "user-foo"}, 1819 }} 1820 result, err := s.uniter.WatchRelationUnits(args) 1821 c.Assert(err, jc.ErrorIsNil) 1822 // UnitSettings versions are volatile, so we don't check them. 1823 // We just make sure the keys of the Changed field are as 1824 // expected. 1825 c.Assert(result.Results, gc.HasLen, len(args.RelationUnits)) 1826 mysqlChanges := result.Results[1].Changes 1827 c.Assert(mysqlChanges, gc.NotNil) 1828 changed, ok := mysqlChanges.Changed["mysql/0"] 1829 c.Assert(ok, jc.IsTrue) 1830 expectChanges := params.RelationUnitsChange{ 1831 Changed: map[string]params.UnitSettings{ 1832 "mysql/0": params.UnitSettings{changed.Version}, 1833 }, 1834 } 1835 c.Assert(result, gc.DeepEquals, params.RelationUnitsWatchResults{ 1836 Results: []params.RelationUnitsWatchResult{ 1837 {Error: apiservertesting.ErrUnauthorized}, 1838 { 1839 RelationUnitsWatcherId: "1", 1840 Changes: expectChanges, 1841 }, 1842 {Error: apiservertesting.ErrUnauthorized}, 1843 {Error: apiservertesting.ErrUnauthorized}, 1844 {Error: apiservertesting.ErrUnauthorized}, 1845 {Error: apiservertesting.ErrUnauthorized}, 1846 {Error: apiservertesting.ErrUnauthorized}, 1847 {Error: apiservertesting.ErrUnauthorized}, 1848 {Error: apiservertesting.ErrUnauthorized}, 1849 {Error: apiservertesting.ErrUnauthorized}, 1850 {Error: apiservertesting.ErrUnauthorized}, 1851 }, 1852 }) 1853 1854 // Verify the resource was registered and stop when done 1855 c.Assert(s.resources.Count(), gc.Equals, 1) 1856 resource := s.resources.Get("1") 1857 defer statetesting.AssertStop(c, resource) 1858 1859 // Check that the Watch has consumed the initial event ("returned" in 1860 // the Watch call) 1861 wc := statetesting.NewRelationUnitsWatcherC(c, s.State, resource.(state.RelationUnitsWatcher)) 1862 wc.AssertNoChange() 1863 1864 // Leave scope with mysqlUnit and check it's detected. 1865 err = myRelUnit.LeaveScope() 1866 c.Assert(err, jc.ErrorIsNil) 1867 s.assertInScope(c, myRelUnit, false) 1868 1869 wc.AssertChange(nil, []string{"mysql/0"}) 1870 } 1871 1872 func (s *uniterSuite) TestAPIAddresses(c *gc.C) { 1873 hostPorts := [][]network.HostPort{ 1874 network.NewHostPorts(1234, "0.1.2.3"), 1875 } 1876 err := s.State.SetAPIHostPorts(hostPorts) 1877 c.Assert(err, jc.ErrorIsNil) 1878 1879 result, err := s.uniter.APIAddresses() 1880 c.Assert(err, jc.ErrorIsNil) 1881 c.Assert(result, gc.DeepEquals, params.StringsResult{ 1882 Result: []string{"0.1.2.3:1234"}, 1883 }) 1884 } 1885 1886 func (s *uniterSuite) TestWatchUnitAddresses(c *gc.C) { 1887 c.Assert(s.resources.Count(), gc.Equals, 0) 1888 1889 args := params.Entities{Entities: []params.Entity{ 1890 {Tag: "unit-mysql-0"}, 1891 {Tag: "unit-wordpress-0"}, 1892 {Tag: "unit-foo-42"}, 1893 {Tag: "machine-0"}, 1894 {Tag: "service-wordpress"}, 1895 }} 1896 result, err := s.uniter.WatchUnitAddresses(args) 1897 c.Assert(err, jc.ErrorIsNil) 1898 c.Assert(result, gc.DeepEquals, params.NotifyWatchResults{ 1899 Results: []params.NotifyWatchResult{ 1900 {Error: apiservertesting.ErrUnauthorized}, 1901 {NotifyWatcherId: "1"}, 1902 {Error: apiservertesting.ErrUnauthorized}, 1903 {Error: apiservertesting.ErrUnauthorized}, 1904 {Error: apiservertesting.ErrUnauthorized}, 1905 }, 1906 }) 1907 1908 // Verify the resource was registered and stop when done 1909 c.Assert(s.resources.Count(), gc.Equals, 1) 1910 resource := s.resources.Get("1") 1911 defer statetesting.AssertStop(c, resource) 1912 1913 // Check that the Watch has consumed the initial event ("returned" in 1914 // the Watch call) 1915 wc := statetesting.NewNotifyWatcherC(c, s.State, resource.(state.NotifyWatcher)) 1916 wc.AssertNoChange() 1917 } 1918 1919 func (s *uniterSuite) TestGetMeterStatusUnauthenticated(c *gc.C) { 1920 args := params.Entities{Entities: []params.Entity{{s.mysqlUnit.Tag().String()}}} 1921 result, err := s.uniter.GetMeterStatus(args) 1922 c.Assert(err, jc.ErrorIsNil) 1923 c.Assert(result.Results, gc.HasLen, 1) 1924 c.Assert(result.Results[0].Error, gc.ErrorMatches, "permission denied") 1925 c.Assert(result.Results[0].Code, gc.Equals, "") 1926 c.Assert(result.Results[0].Info, gc.Equals, "") 1927 } 1928 1929 func (s *uniterSuite) TestGetMeterStatusBadTag(c *gc.C) { 1930 tags := []string{ 1931 "user-admin", 1932 "unit-nosuchunit", 1933 "thisisnotatag", 1934 "machine-0", 1935 "model-blah", 1936 } 1937 args := params.Entities{Entities: make([]params.Entity, len(tags))} 1938 for i, tag := range tags { 1939 args.Entities[i] = params.Entity{Tag: tag} 1940 } 1941 result, err := s.uniter.GetMeterStatus(args) 1942 c.Assert(err, jc.ErrorIsNil) 1943 c.Assert(result.Results, gc.HasLen, len(tags)) 1944 for i, result := range result.Results { 1945 c.Logf("checking result %d", i) 1946 c.Assert(result.Code, gc.Equals, "") 1947 c.Assert(result.Info, gc.Equals, "") 1948 c.Assert(result.Error, gc.ErrorMatches, "permission denied") 1949 } 1950 } 1951 1952 func (s *uniterSuite) assertOneStringsWatcher(c *gc.C, result params.StringsWatchResults, err error) { 1953 c.Assert(err, jc.ErrorIsNil) 1954 c.Assert(result.Results, gc.HasLen, 3) 1955 c.Assert(result.Results[0].Error, gc.DeepEquals, apiservertesting.ErrUnauthorized) 1956 c.Assert(result.Results[1].StringsWatcherId, gc.Equals, "1") 1957 c.Assert(result.Results[1].Changes, gc.NotNil) 1958 c.Assert(result.Results[1].Error, gc.IsNil) 1959 c.Assert(result.Results[2].Error, gc.DeepEquals, apiservertesting.ErrUnauthorized) 1960 1961 // Verify the resource was registered and stop when done 1962 c.Assert(s.resources.Count(), gc.Equals, 1) 1963 resource := s.resources.Get("1") 1964 defer statetesting.AssertStop(c, resource) 1965 1966 // Check that the Watch has consumed the initial event ("returned" in 1967 // the Watch call) 1968 wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher)) 1969 wc.AssertNoChange() 1970 } 1971 1972 func (s *uniterSuite) assertInScope(c *gc.C, relUnit *state.RelationUnit, inScope bool) { 1973 ok, err := relUnit.InScope() 1974 c.Assert(err, jc.ErrorIsNil) 1975 c.Assert(ok, gc.Equals, inScope) 1976 } 1977 1978 func (s *uniterSuite) addRelation(c *gc.C, first, second string) *state.Relation { 1979 eps, err := s.State.InferEndpoints(first, second) 1980 c.Assert(err, jc.ErrorIsNil) 1981 rel, err := s.State.AddRelation(eps...) 1982 c.Assert(err, jc.ErrorIsNil) 1983 return rel 1984 } 1985 1986 func (s *uniterSuite) addRelatedService(c *gc.C, firstSvc, relatedSvc string, unit *state.Unit) (*state.Relation, *state.Service, *state.Unit) { 1987 relatedService := s.AddTestingService(c, relatedSvc, s.AddTestingCharm(c, relatedSvc)) 1988 rel := s.addRelation(c, firstSvc, relatedSvc) 1989 relUnit, err := rel.Unit(unit) 1990 c.Assert(err, jc.ErrorIsNil) 1991 err = relUnit.EnterScope(nil) 1992 c.Assert(err, jc.ErrorIsNil) 1993 relatedUnit, err := s.State.Unit(relatedSvc + "/0") 1994 c.Assert(err, jc.ErrorIsNil) 1995 return rel, relatedService, relatedUnit 1996 } 1997 1998 func (s *uniterSuite) TestRequestReboot(c *gc.C) { 1999 args := params.Entities{Entities: []params.Entity{ 2000 {Tag: s.machine0.Tag().String()}, 2001 {Tag: s.machine1.Tag().String()}, 2002 {Tag: "bogus"}, 2003 {Tag: "nasty-tag"}, 2004 }} 2005 errResult, err := s.uniter.RequestReboot(args) 2006 c.Assert(err, jc.ErrorIsNil) 2007 c.Assert(errResult, gc.DeepEquals, params.ErrorResults{ 2008 Results: []params.ErrorResult{ 2009 {Error: nil}, 2010 {Error: apiservertesting.ErrUnauthorized}, 2011 {Error: apiservertesting.ErrUnauthorized}, 2012 {Error: apiservertesting.ErrUnauthorized}, 2013 }}) 2014 2015 rFlag, err := s.machine0.GetRebootFlag() 2016 c.Assert(err, jc.ErrorIsNil) 2017 c.Assert(rFlag, jc.IsTrue) 2018 2019 rFlag, err = s.machine1.GetRebootFlag() 2020 c.Assert(err, jc.ErrorIsNil) 2021 c.Assert(rFlag, jc.IsFalse) 2022 } 2023 2024 func checkUnorderedActionIdsEqual(c *gc.C, ids []string, results params.StringsWatchResults) { 2025 c.Assert(results, gc.NotNil) 2026 content := results.Results 2027 c.Assert(len(content), gc.Equals, 1) 2028 result := content[0] 2029 c.Assert(result.StringsWatcherId, gc.Equals, "1") 2030 obtainedIds := map[string]int{} 2031 expectedIds := map[string]int{} 2032 for _, id := range ids { 2033 expectedIds[id]++ 2034 } 2035 // The count of each ID that has been seen. 2036 for _, change := range result.Changes { 2037 obtainedIds[change]++ 2038 } 2039 c.Check(obtainedIds, jc.DeepEquals, expectedIds) 2040 } 2041 2042 func (s *uniterSuite) TestStorageAttachments(c *gc.C) { 2043 // We need to set up a unit that has storage metadata defined. 2044 ch := s.AddTestingCharm(c, "storage-block") 2045 sCons := map[string]state.StorageConstraints{ 2046 "data": {Pool: "", Size: 1024, Count: 1}, 2047 } 2048 service := s.AddTestingServiceWithStorage(c, "storage-block", ch, sCons) 2049 unit, err := service.AddUnit() 2050 c.Assert(err, jc.ErrorIsNil) 2051 err = s.State.AssignUnit(unit, state.AssignCleanEmpty) 2052 c.Assert(err, jc.ErrorIsNil) 2053 assignedMachineId, err := unit.AssignedMachineId() 2054 c.Assert(err, jc.ErrorIsNil) 2055 machine, err := s.State.Machine(assignedMachineId) 2056 c.Assert(err, jc.ErrorIsNil) 2057 2058 volumeAttachments, err := machine.VolumeAttachments() 2059 c.Assert(err, jc.ErrorIsNil) 2060 c.Assert(volumeAttachments, gc.HasLen, 1) 2061 2062 err = machine.SetProvisioned("inst-id", "fake_nonce", nil) 2063 c.Assert(err, jc.ErrorIsNil) 2064 2065 err = s.State.SetVolumeInfo( 2066 volumeAttachments[0].Volume(), 2067 state.VolumeInfo{VolumeId: "vol-123", Size: 456}, 2068 ) 2069 c.Assert(err, jc.ErrorIsNil) 2070 2071 err = s.State.SetVolumeAttachmentInfo( 2072 machine.MachineTag(), 2073 volumeAttachments[0].Volume(), 2074 state.VolumeAttachmentInfo{DeviceName: "xvdf1"}, 2075 ) 2076 c.Assert(err, jc.ErrorIsNil) 2077 2078 password, err := utils.RandomPassword() 2079 err = unit.SetPassword(password) 2080 c.Assert(err, jc.ErrorIsNil) 2081 st := s.OpenAPIAs(c, unit.Tag(), password) 2082 uniter, err := st.Uniter() 2083 c.Assert(err, jc.ErrorIsNil) 2084 2085 attachments, err := uniter.UnitStorageAttachments(unit.UnitTag()) 2086 c.Assert(err, jc.ErrorIsNil) 2087 c.Assert(attachments, gc.DeepEquals, []params.StorageAttachmentId{{ 2088 StorageTag: "storage-data-0", 2089 UnitTag: unit.Tag().String(), 2090 }}) 2091 } 2092 2093 func (s *uniterSuite) TestUnitStatus(c *gc.C) { 2094 err := s.wordpressUnit.SetStatus(status.StatusMaintenance, "blah", nil) 2095 c.Assert(err, jc.ErrorIsNil) 2096 err = s.mysqlUnit.SetStatus(status.StatusTerminated, "foo", nil) 2097 c.Assert(err, jc.ErrorIsNil) 2098 2099 args := params.Entities{ 2100 Entities: []params.Entity{ 2101 {Tag: "unit-mysql-0"}, 2102 {Tag: "unit-wordpress-0"}, 2103 {Tag: "unit-foo-42"}, 2104 {Tag: "machine-1"}, 2105 {Tag: "invalid"}, 2106 }} 2107 result, err := s.uniter.UnitStatus(args) 2108 c.Assert(err, jc.ErrorIsNil) 2109 // Zero out the updated timestamps so we can easily check the results. 2110 for i, statusResult := range result.Results { 2111 r := statusResult 2112 if r.Status != "" { 2113 c.Assert(r.Since, gc.NotNil) 2114 } 2115 r.Since = nil 2116 result.Results[i] = r 2117 } 2118 c.Assert(result, gc.DeepEquals, params.StatusResults{ 2119 Results: []params.StatusResult{ 2120 {Error: apiservertesting.ErrUnauthorized}, 2121 {Status: status.StatusMaintenance, Info: "blah", Data: map[string]interface{}{}}, 2122 {Error: apiservertesting.ErrUnauthorized}, 2123 {Error: apiservertesting.ErrUnauthorized}, 2124 {Error: apiservertesting.ServerError(`"invalid" is not a valid tag`)}, 2125 }, 2126 }) 2127 } 2128 2129 func (s *uniterSuite) TestServiceOwner(c *gc.C) { 2130 args := params.Entities{Entities: []params.Entity{ 2131 {Tag: "unit-mysql-0"}, 2132 {Tag: "service-wordpress"}, 2133 {Tag: "unit-wordpress-0"}, 2134 {Tag: "unit-foo-42"}, 2135 {Tag: "machine-0"}, 2136 {Tag: "service-foo"}, 2137 }} 2138 result, err := s.uniter.ServiceOwner(args) 2139 c.Assert(err, jc.ErrorIsNil) 2140 c.Assert(result, jc.DeepEquals, params.StringResults{ 2141 Results: []params.StringResult{ 2142 {Error: apiservertesting.ErrUnauthorized}, 2143 {Result: s.AdminUserTag(c).String()}, 2144 {Error: apiservertesting.ErrUnauthorized}, 2145 {Error: apiservertesting.ErrUnauthorized}, 2146 {Error: apiservertesting.ErrUnauthorized}, 2147 {Error: apiservertesting.ErrUnauthorized}, 2148 }, 2149 }) 2150 } 2151 2152 func (s *uniterSuite) TestAssignedMachine(c *gc.C) { 2153 args := params.Entities{Entities: []params.Entity{ 2154 {Tag: "unit-mysql-0"}, 2155 {Tag: "unit-wordpress-0"}, 2156 {Tag: "unit-foo-42"}, 2157 {Tag: "service-mysql"}, 2158 {Tag: "service-wordpress"}, 2159 {Tag: "machine-0"}, 2160 {Tag: "machine-1"}, 2161 {Tag: "machine-42"}, 2162 {Tag: "service-foo"}, 2163 {Tag: "relation-svc1.rel1#svc2.rel2"}, 2164 }} 2165 result, err := s.uniter.AssignedMachine(args) 2166 c.Assert(err, jc.ErrorIsNil) 2167 c.Assert(result, jc.DeepEquals, params.StringResults{ 2168 Results: []params.StringResult{ 2169 {Error: apiservertesting.ErrUnauthorized}, 2170 {Result: "machine-0"}, 2171 {Error: apiservertesting.ErrUnauthorized}, 2172 {Error: apiservertesting.ErrUnauthorized}, 2173 {Error: apiservertesting.ErrUnauthorized}, 2174 {Error: apiservertesting.ErrUnauthorized}, 2175 {Error: apiservertesting.ErrUnauthorized}, 2176 {Error: apiservertesting.ErrUnauthorized}, 2177 {Error: apiservertesting.ErrUnauthorized}, 2178 {Error: apiservertesting.ErrUnauthorized}, 2179 }, 2180 }) 2181 } 2182 2183 func (s *uniterSuite) TestAllMachinePorts(c *gc.C) { 2184 // Verify no ports are opened yet on the machine or unit. 2185 machinePorts, err := s.machine0.AllPorts() 2186 c.Assert(err, jc.ErrorIsNil) 2187 c.Assert(machinePorts, gc.HasLen, 0) 2188 unitPorts, err := s.wordpressUnit.OpenedPorts() 2189 c.Assert(err, jc.ErrorIsNil) 2190 c.Assert(unitPorts, gc.HasLen, 0) 2191 2192 // Add another mysql unit on machine 0. 2193 mysqlUnit1, err := s.mysql.AddUnit() 2194 c.Assert(err, jc.ErrorIsNil) 2195 err = mysqlUnit1.AssignToMachine(s.machine0) 2196 c.Assert(err, jc.ErrorIsNil) 2197 2198 // Open some ports on both units. 2199 err = s.wordpressUnit.OpenPorts("tcp", 100, 200) 2200 c.Assert(err, jc.ErrorIsNil) 2201 err = s.wordpressUnit.OpenPorts("udp", 10, 20) 2202 c.Assert(err, jc.ErrorIsNil) 2203 err = mysqlUnit1.OpenPorts("tcp", 201, 250) 2204 c.Assert(err, jc.ErrorIsNil) 2205 err = mysqlUnit1.OpenPorts("udp", 1, 8) 2206 c.Assert(err, jc.ErrorIsNil) 2207 2208 args := params.Entities{Entities: []params.Entity{ 2209 {Tag: "unit-mysql-0"}, 2210 {Tag: "machine-0"}, 2211 {Tag: "machine-1"}, 2212 {Tag: "unit-foo-42"}, 2213 {Tag: "machine-42"}, 2214 {Tag: "service-wordpress"}, 2215 }} 2216 expectPorts := []params.MachinePortRange{ 2217 {UnitTag: "unit-wordpress-0", PortRange: params.PortRange{100, 200, "tcp"}}, 2218 {UnitTag: "unit-mysql-1", PortRange: params.PortRange{201, 250, "tcp"}}, 2219 {UnitTag: "unit-mysql-1", PortRange: params.PortRange{1, 8, "udp"}}, 2220 {UnitTag: "unit-wordpress-0", PortRange: params.PortRange{10, 20, "udp"}}, 2221 } 2222 result, err := s.uniter.AllMachinePorts(args) 2223 c.Assert(err, jc.ErrorIsNil) 2224 c.Assert(result, gc.DeepEquals, params.MachinePortsResults{ 2225 Results: []params.MachinePortsResult{ 2226 {Error: apiservertesting.ErrUnauthorized}, 2227 {Ports: expectPorts}, 2228 {Error: apiservertesting.ErrUnauthorized}, 2229 {Error: apiservertesting.ErrUnauthorized}, 2230 {Error: apiservertesting.ErrUnauthorized}, 2231 {Error: apiservertesting.ErrUnauthorized}, 2232 }, 2233 }) 2234 } 2235 2236 type unitMetricBatchesSuite struct { 2237 uniterSuite 2238 *commontesting.ModelWatcherTest 2239 uniter *uniter.UniterAPIV3 2240 } 2241 2242 var _ = gc.Suite(&unitMetricBatchesSuite{}) 2243 2244 func (s *unitMetricBatchesSuite) SetUpTest(c *gc.C) { 2245 s.uniterSuite.SetUpTest(c) 2246 2247 meteredAuthorizer := apiservertesting.FakeAuthorizer{ 2248 Tag: s.meteredUnit.Tag(), 2249 } 2250 var err error 2251 s.uniter, err = uniter.NewUniterAPIV3( 2252 s.State, 2253 s.resources, 2254 meteredAuthorizer, 2255 ) 2256 c.Assert(err, jc.ErrorIsNil) 2257 2258 s.ModelWatcherTest = commontesting.NewModelWatcherTest( 2259 s.uniter, 2260 s.State, 2261 s.resources, 2262 commontesting.NoSecrets, 2263 ) 2264 } 2265 2266 func (s *unitMetricBatchesSuite) TestAddMetricsBatch(c *gc.C) { 2267 metrics := []params.Metric{{Key: "pings", Value: "5", Time: time.Now().UTC()}} 2268 uuid := utils.MustNewUUID().String() 2269 2270 result, err := s.uniter.AddMetricBatches(params.MetricBatchParams{ 2271 Batches: []params.MetricBatchParam{{ 2272 Tag: s.meteredUnit.Tag().String(), 2273 Batch: params.MetricBatch{ 2274 UUID: uuid, 2275 CharmURL: s.meteredCharm.URL().String(), 2276 Created: time.Now(), 2277 Metrics: metrics, 2278 }}}}, 2279 ) 2280 2281 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 2282 Results: []params.ErrorResult{{nil}}, 2283 }) 2284 c.Assert(err, jc.ErrorIsNil) 2285 2286 batch, err := s.State.MetricBatch(uuid) 2287 c.Assert(err, jc.ErrorIsNil) 2288 c.Assert(batch.UUID(), gc.Equals, uuid) 2289 c.Assert(batch.CharmURL(), gc.Equals, s.meteredCharm.URL().String()) 2290 c.Assert(batch.Unit(), gc.Equals, s.meteredUnit.Name()) 2291 storedMetrics := batch.Metrics() 2292 c.Assert(storedMetrics, gc.HasLen, 1) 2293 c.Assert(storedMetrics[0].Key, gc.Equals, metrics[0].Key) 2294 c.Assert(storedMetrics[0].Value, gc.Equals, metrics[0].Value) 2295 } 2296 2297 func (s *unitMetricBatchesSuite) TestAddMetricsBatchNoCharmURL(c *gc.C) { 2298 metrics := []params.Metric{{Key: "pings", Value: "5", Time: time.Now().UTC()}} 2299 uuid := utils.MustNewUUID().String() 2300 2301 result, err := s.uniter.AddMetricBatches(params.MetricBatchParams{ 2302 Batches: []params.MetricBatchParam{{ 2303 Tag: s.meteredUnit.Tag().String(), 2304 Batch: params.MetricBatch{ 2305 UUID: uuid, 2306 CharmURL: s.meteredCharm.URL().String(), 2307 Created: time.Now(), 2308 Metrics: metrics, 2309 }}}}) 2310 2311 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 2312 Results: []params.ErrorResult{{nil}}, 2313 }) 2314 c.Assert(err, jc.ErrorIsNil) 2315 2316 batch, err := s.State.MetricBatch(uuid) 2317 c.Assert(err, jc.ErrorIsNil) 2318 c.Assert(batch.UUID(), gc.Equals, uuid) 2319 c.Assert(batch.CharmURL(), gc.Equals, s.meteredCharm.URL().String()) 2320 c.Assert(batch.Unit(), gc.Equals, s.meteredUnit.Name()) 2321 storedMetrics := batch.Metrics() 2322 c.Assert(storedMetrics, gc.HasLen, 1) 2323 c.Assert(storedMetrics[0].Key, gc.Equals, metrics[0].Key) 2324 c.Assert(storedMetrics[0].Value, gc.Equals, metrics[0].Value) 2325 } 2326 2327 func (s *unitMetricBatchesSuite) TestAddMetricsBatchDiffTag(c *gc.C) { 2328 unit2 := s.Factory.MakeUnit(c, &factory.UnitParams{Service: s.meteredService, SetCharmURL: true}) 2329 2330 metrics := []params.Metric{{Key: "pings", Value: "5", Time: time.Now().UTC()}} 2331 uuid := utils.MustNewUUID().String() 2332 2333 tests := []struct { 2334 about string 2335 tag string 2336 expect string 2337 }{{ 2338 about: "different unit", 2339 tag: unit2.Tag().String(), 2340 expect: "permission denied", 2341 }, { 2342 about: "user tag", 2343 tag: names.NewLocalUserTag("admin").String(), 2344 expect: `"user-admin@local" is not a valid unit tag`, 2345 }, { 2346 about: "machine tag", 2347 tag: names.NewMachineTag("0").String(), 2348 expect: `"machine-0" is not a valid unit tag`, 2349 }} 2350 2351 for i, test := range tests { 2352 c.Logf("test %d: %s", i, test.about) 2353 result, err := s.uniter.AddMetricBatches(params.MetricBatchParams{ 2354 Batches: []params.MetricBatchParam{{ 2355 Tag: test.tag, 2356 Batch: params.MetricBatch{ 2357 UUID: uuid, 2358 CharmURL: "", 2359 Created: time.Now(), 2360 Metrics: metrics, 2361 }}}}) 2362 2363 if test.expect == "" { 2364 c.Assert(result.OneError(), jc.ErrorIsNil) 2365 } else { 2366 c.Assert(result.OneError(), gc.ErrorMatches, test.expect) 2367 } 2368 c.Assert(err, jc.ErrorIsNil) 2369 2370 _, err = s.State.MetricBatch(uuid) 2371 c.Assert(err, jc.Satisfies, errors.IsNotFound) 2372 } 2373 } 2374 2375 type uniterNetworkConfigSuite struct { 2376 base uniterSuite // not embedded so it doesn't run all tests. 2377 } 2378 2379 var _ = gc.Suite(&uniterNetworkConfigSuite{}) 2380 2381 func (s *uniterNetworkConfigSuite) SetUpSuite(c *gc.C) { 2382 s.base.SetUpSuite(c) 2383 } 2384 2385 func (s *uniterNetworkConfigSuite) TearDownSuite(c *gc.C) { 2386 s.base.TearDownSuite(c) 2387 } 2388 2389 func (s *uniterNetworkConfigSuite) SetUpTest(c *gc.C) { 2390 s.base.JujuConnSuite.SetUpTest(c) 2391 2392 // Add the spaces and subnets used by the test. 2393 subnetInfos := []state.SubnetInfo{{ 2394 CIDR: "8.8.0.0/16", 2395 SpaceName: "public", 2396 }, { 2397 CIDR: "10.0.0.0/24", 2398 SpaceName: "internal", 2399 }} 2400 for _, info := range subnetInfos { 2401 _, err := s.base.State.AddSpace(info.SpaceName, "", nil, false) 2402 c.Assert(err, jc.ErrorIsNil) 2403 _, err = s.base.State.AddSubnet(info) 2404 c.Assert(err, jc.ErrorIsNil) 2405 } 2406 2407 s.base.machine0 = s.addProvisionedMachineWithDevicesAndAddresses(c, 10) 2408 2409 factory := jujuFactory.NewFactory(s.base.State) 2410 s.base.wpCharm = factory.MakeCharm(c, &jujuFactory.CharmParams{ 2411 Name: "wordpress-extra-bindings", 2412 URL: "cs:quantal/wordpress-extra-bindings-4", 2413 }) 2414 var err error 2415 s.base.wordpress, err = s.base.State.AddService(state.AddServiceArgs{ 2416 Name: "wordpress", 2417 Charm: s.base.wpCharm, 2418 Owner: s.base.AdminUserTag(c).String(), 2419 EndpointBindings: map[string]string{ 2420 "db": "internal", // relation name 2421 "admin-api": "public", // extra-binding name 2422 }, 2423 }) 2424 c.Assert(err, jc.ErrorIsNil) 2425 s.base.wordpressUnit = factory.MakeUnit(c, &jujuFactory.UnitParams{ 2426 Service: s.base.wordpress, 2427 Machine: s.base.machine0, 2428 }) 2429 2430 s.base.machine1 = s.addProvisionedMachineWithDevicesAndAddresses(c, 20) 2431 2432 mysqlCharm := factory.MakeCharm(c, &jujuFactory.CharmParams{ 2433 Name: "mysql", 2434 }) 2435 s.base.mysql = factory.MakeService(c, &jujuFactory.ServiceParams{ 2436 Name: "mysql", 2437 Charm: mysqlCharm, 2438 Creator: s.base.AdminUserTag(c), 2439 }) 2440 s.base.wordpressUnit = factory.MakeUnit(c, &jujuFactory.UnitParams{ 2441 Service: s.base.wordpress, 2442 Machine: s.base.machine0, 2443 }) 2444 s.base.mysqlUnit = factory.MakeUnit(c, &jujuFactory.UnitParams{ 2445 Service: s.base.mysql, 2446 Machine: s.base.machine1, 2447 }) 2448 2449 // Create the resource registry separately to track invocations to 2450 // Register. 2451 s.base.resources = common.NewResources() 2452 s.base.AddCleanup(func(_ *gc.C) { s.base.resources.StopAll() }) 2453 2454 s.setupUniterAPIForUnit(c, s.base.wordpressUnit) 2455 } 2456 2457 func (s *uniterNetworkConfigSuite) addProvisionedMachineWithDevicesAndAddresses(c *gc.C, addrSuffix int) *state.Machine { 2458 machine, err := s.base.State.AddMachine("quantal", state.JobHostUnits) 2459 c.Assert(err, jc.ErrorIsNil) 2460 devicesArgs, devicesAddrs := s.makeMachineDevicesAndAddressesArgs(addrSuffix) 2461 err = machine.SetInstanceInfo("i-am", "fake_nonce", nil, devicesArgs, devicesAddrs, nil, nil) 2462 c.Assert(err, jc.ErrorIsNil) 2463 2464 machineAddrs, err := machine.AllAddresses() 2465 c.Assert(err, jc.ErrorIsNil) 2466 2467 netAddrs := make([]network.Address, len(machineAddrs)) 2468 for i, addr := range machineAddrs { 2469 netAddrs[i] = network.NewAddress(addr.Value()) 2470 } 2471 err = machine.SetProviderAddresses(netAddrs...) 2472 c.Assert(err, jc.ErrorIsNil) 2473 2474 return machine 2475 } 2476 2477 func (s *uniterNetworkConfigSuite) makeMachineDevicesAndAddressesArgs(addrSuffix int) ([]state.LinkLayerDeviceArgs, []state.LinkLayerDeviceAddress) { 2478 return []state.LinkLayerDeviceArgs{{ 2479 Name: "eth0", 2480 Type: state.EthernetDevice, 2481 }, { 2482 Name: "eth0.100", 2483 Type: state.VLAN_8021QDevice, 2484 ParentName: "eth0", 2485 }, { 2486 Name: "eth1", 2487 Type: state.EthernetDevice, 2488 }, { 2489 Name: "eth1.100", 2490 Type: state.VLAN_8021QDevice, 2491 ParentName: "eth1", 2492 }}, 2493 []state.LinkLayerDeviceAddress{{ 2494 DeviceName: "eth0", 2495 ConfigMethod: state.StaticAddress, 2496 CIDRAddress: fmt.Sprintf("8.8.8.%d/16", addrSuffix), 2497 }, { 2498 DeviceName: "eth0.100", 2499 ConfigMethod: state.StaticAddress, 2500 CIDRAddress: fmt.Sprintf("10.0.0.%d/24", addrSuffix), 2501 }, { 2502 DeviceName: "eth1", 2503 ConfigMethod: state.StaticAddress, 2504 CIDRAddress: fmt.Sprintf("8.8.4.%d/16", addrSuffix), 2505 }, { 2506 DeviceName: "eth1.100", 2507 ConfigMethod: state.StaticAddress, 2508 CIDRAddress: fmt.Sprintf("10.0.0.%d/24", addrSuffix+1), 2509 }} 2510 } 2511 2512 func (s *uniterNetworkConfigSuite) TearDownTest(c *gc.C) { 2513 s.base.JujuConnSuite.TearDownTest(c) 2514 } 2515 2516 func (s *uniterNetworkConfigSuite) setupUniterAPIForUnit(c *gc.C, givenUnit *state.Unit) { 2517 // Create a FakeAuthorizer so we can check permissions, set up assuming the 2518 // given unit agent has logged in. 2519 s.base.authorizer = apiservertesting.FakeAuthorizer{ 2520 Tag: givenUnit.Tag(), 2521 } 2522 2523 var err error 2524 s.base.uniter, err = uniter.NewUniterAPIV3( 2525 s.base.State, 2526 s.base.resources, 2527 s.base.authorizer, 2528 ) 2529 c.Assert(err, jc.ErrorIsNil) 2530 } 2531 2532 func (s *uniterNetworkConfigSuite) TestNetworkConfigPermissions(c *gc.C) { 2533 s.addRelationAndAssertInScope(c) 2534 2535 args := params.UnitsNetworkConfig{Args: []params.UnitNetworkConfig{ 2536 {BindingName: "foo", UnitTag: "unit-foo-0"}, 2537 {BindingName: "db-client", UnitTag: "invalid"}, 2538 {BindingName: "juju-info", UnitTag: "unit-mysql-0"}, 2539 {BindingName: "", UnitTag: s.base.wordpressUnit.Tag().String()}, 2540 {BindingName: "unknown", UnitTag: s.base.wordpressUnit.Tag().String()}, 2541 }} 2542 2543 result, err := s.base.uniter.NetworkConfig(args) 2544 c.Assert(err, jc.ErrorIsNil) 2545 c.Assert(result, jc.DeepEquals, params.UnitNetworkConfigResults{ 2546 Results: []params.UnitNetworkConfigResult{ 2547 {Error: apiservertesting.ErrUnauthorized}, 2548 {Error: apiservertesting.ServerError(`"invalid" is not a valid tag`)}, 2549 {Error: apiservertesting.ErrUnauthorized}, 2550 {Error: apiservertesting.ServerError(`binding name cannot be empty`)}, 2551 {Error: apiservertesting.ServerError(`binding name "unknown" not defined by the unit's charm`)}, 2552 }, 2553 }) 2554 } 2555 2556 func (s *uniterNetworkConfigSuite) addRelationAndAssertInScope(c *gc.C) { 2557 // Add a relation between wordpress and mysql and enter scope with 2558 // mysqlUnit. 2559 rel := s.base.addRelation(c, "wordpress", "mysql") 2560 wpRelUnit, err := rel.Unit(s.base.wordpressUnit) 2561 c.Assert(err, jc.ErrorIsNil) 2562 err = wpRelUnit.EnterScope(nil) 2563 c.Assert(err, jc.ErrorIsNil) 2564 s.base.assertInScope(c, wpRelUnit, true) 2565 } 2566 2567 func (s *uniterNetworkConfigSuite) TestNetworkConfigForExplicitlyBoundEndpoint(c *gc.C) { 2568 s.addRelationAndAssertInScope(c) 2569 2570 args := params.UnitsNetworkConfig{Args: []params.UnitNetworkConfig{ 2571 {BindingName: "db", UnitTag: s.base.wordpressUnit.Tag().String()}, 2572 {BindingName: "admin-api", UnitTag: s.base.wordpressUnit.Tag().String()}, 2573 }} 2574 2575 // For the relation "wordpress:db mysql:server" we expect to see only 2576 // addresses bound to the "internal" space, where the "db" endpoint itself 2577 // is bound to. 2578 expectedConfigWithRelationName := []params.NetworkConfig{ 2579 {Address: "10.0.0.10"}, 2580 {Address: "10.0.0.11"}, 2581 } 2582 // For the "admin-api" extra-binding we expect to see only addresses from 2583 // the "public" space. 2584 expectedConfigWithExtraBindingName := []params.NetworkConfig{ 2585 {Address: "8.8.8.10"}, 2586 {Address: "8.8.4.10"}, 2587 } 2588 2589 result, err := s.base.uniter.NetworkConfig(args) 2590 c.Assert(err, jc.ErrorIsNil) 2591 c.Assert(result, jc.DeepEquals, params.UnitNetworkConfigResults{ 2592 Results: []params.UnitNetworkConfigResult{ 2593 {Config: expectedConfigWithRelationName}, 2594 {Config: expectedConfigWithExtraBindingName}, 2595 }, 2596 }) 2597 } 2598 2599 func (s *uniterNetworkConfigSuite) TestNetworkConfigForImplicitlyBoundEndpoint(c *gc.C) { 2600 // Since wordpressUnit has explicit binding for "db", switch the API to 2601 // mysqlUnit and check "mysql:server" uses the machine preferred private 2602 // address. 2603 s.setupUniterAPIForUnit(c, s.base.mysqlUnit) 2604 rel := s.base.addRelation(c, "mysql", "wordpress") 2605 mysqlRelUnit, err := rel.Unit(s.base.mysqlUnit) 2606 c.Assert(err, jc.ErrorIsNil) 2607 err = mysqlRelUnit.EnterScope(nil) 2608 c.Assert(err, jc.ErrorIsNil) 2609 s.base.assertInScope(c, mysqlRelUnit, true) 2610 2611 args := params.UnitsNetworkConfig{Args: []params.UnitNetworkConfig{ 2612 {BindingName: "server", UnitTag: s.base.mysqlUnit.Tag().String()}, 2613 }} 2614 2615 privateAddress, err := s.base.machine1.PrivateAddress() 2616 c.Assert(err, jc.ErrorIsNil) 2617 2618 expectedConfig := []params.NetworkConfig{{Address: privateAddress.Value}} 2619 2620 result, err := s.base.uniter.NetworkConfig(args) 2621 c.Assert(err, jc.ErrorIsNil) 2622 c.Assert(result, jc.DeepEquals, params.UnitNetworkConfigResults{ 2623 Results: []params.UnitNetworkConfigResult{ 2624 {Config: expectedConfig}, 2625 }, 2626 }) 2627 }