github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/state_test.go (about) 1 // Copyright 2012-2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_test 5 6 import ( 7 "fmt" 8 "sort" 9 "strconv" 10 "time" 11 12 "github.com/juju/errors" 13 "github.com/juju/loggo" 14 "github.com/juju/replicaset" 15 gitjujutesting "github.com/juju/testing" 16 jc "github.com/juju/testing/checkers" 17 "github.com/juju/txn" 18 "github.com/juju/utils" 19 "github.com/juju/utils/arch" 20 "github.com/juju/utils/clock" 21 "github.com/juju/utils/series" 22 "github.com/juju/version" 23 gc "gopkg.in/check.v1" 24 "gopkg.in/juju/charm.v6-unstable" 25 "gopkg.in/juju/names.v2" 26 "gopkg.in/mgo.v2/bson" 27 mgotxn "gopkg.in/mgo.v2/txn" 28 29 "github.com/juju/juju/agent" 30 "github.com/juju/juju/cloud" 31 "github.com/juju/juju/constraints" 32 "github.com/juju/juju/environs/config" 33 "github.com/juju/juju/instance" 34 "github.com/juju/juju/mongo" 35 "github.com/juju/juju/mongo/mongotest" 36 "github.com/juju/juju/network" 37 "github.com/juju/juju/permission" 38 "github.com/juju/juju/state" 39 "github.com/juju/juju/state/multiwatcher" 40 statetesting "github.com/juju/juju/state/testing" 41 "github.com/juju/juju/status" 42 "github.com/juju/juju/storage" 43 "github.com/juju/juju/storage/poolmanager" 44 "github.com/juju/juju/storage/provider" 45 "github.com/juju/juju/testing" 46 "github.com/juju/juju/testing/factory" 47 jujuversion "github.com/juju/juju/version" 48 ) 49 50 var goodPassword = "foo-12345678901234567890" 51 var alternatePassword = "bar-12345678901234567890" 52 53 // preventUnitDestroyRemove sets a non-pending status on the unit, and hence 54 // prevents it from being unceremoniously removed from state on Destroy. This 55 // is useful because several tests go through a unit's lifecycle step by step, 56 // asserting the behaviour of a given method in each state, and the unit quick- 57 // remove change caused many of these to fail. 58 func preventUnitDestroyRemove(c *gc.C, u *state.Unit) { 59 now := time.Now() 60 sInfo := status.StatusInfo{ 61 Status: status.Idle, 62 Message: "", 63 Since: &now, 64 } 65 err := u.SetAgentStatus(sInfo) 66 c.Assert(err, jc.ErrorIsNil) 67 } 68 69 type StateSuite struct { 70 ConnSuite 71 } 72 73 var _ = gc.Suite(&StateSuite{}) 74 75 func (s *StateSuite) SetUpTest(c *gc.C) { 76 s.ConnSuite.SetUpTest(c) 77 s.policy.GetConstraintsValidator = func() (constraints.Validator, error) { 78 validator := constraints.NewValidator() 79 validator.RegisterConflicts([]string{constraints.InstanceType}, []string{constraints.Mem}) 80 validator.RegisterUnsupported([]string{constraints.CpuPower}) 81 return validator, nil 82 } 83 } 84 85 func (s *StateSuite) TestIsController(c *gc.C) { 86 c.Assert(s.State.IsController(), jc.IsTrue) 87 st2 := s.Factory.MakeModel(c, nil) 88 defer st2.Close() 89 c.Assert(st2.IsController(), jc.IsFalse) 90 } 91 92 func (s *StateSuite) TestUserModelNameIndex(c *gc.C) { 93 index := state.UserModelNameIndex("BoB", "testing") 94 c.Assert(index, gc.Equals, "bob:testing") 95 } 96 97 func (s *StateSuite) TestDocID(c *gc.C) { 98 id := "wordpress" 99 docID := state.DocID(s.State, id) 100 c.Assert(docID, gc.Equals, s.State.ModelUUID()+":"+id) 101 102 // Ensure that the prefix isn't added if it's already there. 103 docID2 := state.DocID(s.State, docID) 104 c.Assert(docID2, gc.Equals, docID) 105 } 106 107 func (s *StateSuite) TestLocalID(c *gc.C) { 108 id := s.State.ModelUUID() + ":wordpress" 109 localID := state.LocalID(s.State, id) 110 c.Assert(localID, gc.Equals, "wordpress") 111 } 112 113 func (s *StateSuite) TestIDHelpersAreReversible(c *gc.C) { 114 id := "wordpress" 115 docID := state.DocID(s.State, id) 116 localID := state.LocalID(s.State, docID) 117 c.Assert(localID, gc.Equals, id) 118 } 119 120 func (s *StateSuite) TestStrictLocalID(c *gc.C) { 121 id := state.DocID(s.State, "wordpress") 122 localID, err := state.StrictLocalID(s.State, id) 123 c.Assert(localID, gc.Equals, "wordpress") 124 c.Assert(err, jc.ErrorIsNil) 125 } 126 127 func (s *StateSuite) TestStrictLocalIDWithWrongPrefix(c *gc.C) { 128 localID, err := state.StrictLocalID(s.State, "foo:wordpress") 129 c.Assert(localID, gc.Equals, "") 130 c.Assert(err, gc.ErrorMatches, `unexpected id: "foo:wordpress"`) 131 } 132 133 func (s *StateSuite) TestStrictLocalIDWithNoPrefix(c *gc.C) { 134 localID, err := state.StrictLocalID(s.State, "wordpress") 135 c.Assert(localID, gc.Equals, "") 136 c.Assert(err, gc.ErrorMatches, `unexpected id: "wordpress"`) 137 } 138 139 func (s *StateSuite) TestDialAgain(c *gc.C) { 140 // Ensure idempotent operations on Dial are working fine. 141 for i := 0; i < 2; i++ { 142 st, err := state.Open(s.modelTag, s.State.ControllerTag(), statetesting.NewMongoInfo(), mongotest.DialOpts(), nil) 143 c.Assert(err, jc.ErrorIsNil) 144 c.Assert(st.Close(), gc.IsNil) 145 } 146 } 147 148 func (s *StateSuite) TestOpenRequiresExtantModelTag(c *gc.C) { 149 uuid := utils.MustNewUUID() 150 tag := names.NewModelTag(uuid.String()) 151 st, err := state.Open(tag, s.State.ControllerTag(), statetesting.NewMongoInfo(), mongotest.DialOpts(), nil) 152 if !c.Check(st, gc.IsNil) { 153 c.Check(st.Close(), jc.ErrorIsNil) 154 } 155 expect := fmt.Sprintf("cannot read model %s: model not found", uuid) 156 c.Check(err, gc.ErrorMatches, expect) 157 } 158 159 func (s *StateSuite) TestOpenSetsModelTag(c *gc.C) { 160 st, err := state.Open(s.modelTag, s.State.ControllerTag(), statetesting.NewMongoInfo(), mongotest.DialOpts(), nil) 161 c.Assert(err, jc.ErrorIsNil) 162 defer st.Close() 163 164 c.Assert(st.ModelTag(), gc.Equals, s.modelTag) 165 } 166 167 func (s *StateSuite) TestModelUUID(c *gc.C) { 168 c.Assert(s.State.ModelUUID(), gc.Equals, s.modelTag.Id()) 169 } 170 171 func (s *StateSuite) TestNoModelDocs(c *gc.C) { 172 c.Assert(s.State.EnsureModelRemoved(), gc.ErrorMatches, 173 fmt.Sprintf("found documents for model with uuid %s: 1 constraints doc, 2 leases doc, 1 modelusers doc, 1 settings doc, 1 statuses doc", s.State.ModelUUID())) 174 } 175 176 func (s *StateSuite) TestMongoSession(c *gc.C) { 177 session := s.State.MongoSession() 178 c.Assert(session.Ping(), gc.IsNil) 179 } 180 181 func (s *StateSuite) TestWatch(c *gc.C) { 182 // The allWatcher infrastructure is comprehensively tested 183 // elsewhere. This just ensures things are hooked up correctly in 184 // State.Watch() 185 186 w := s.State.Watch() 187 defer w.Stop() 188 deltasC := makeMultiwatcherOutput(w) 189 s.State.StartSync() 190 191 select { 192 case deltas := <-deltasC: 193 // The Watch() call results in an empty "change" reflecting 194 // the initially empty model. 195 c.Assert(deltas, gc.HasLen, 0) 196 case <-time.After(testing.LongWait): 197 c.Fatal("timed out") 198 } 199 200 m := s.Factory.MakeMachine(c, nil) // Generate event 201 s.State.StartSync() 202 203 select { 204 case deltas := <-deltasC: 205 c.Assert(deltas, gc.HasLen, 1) 206 info := deltas[0].Entity.(*multiwatcher.MachineInfo) 207 c.Assert(info.ModelUUID, gc.Equals, s.State.ModelUUID()) 208 c.Assert(info.Id, gc.Equals, m.Id()) 209 case <-time.After(testing.LongWait): 210 c.Fatal("timed out") 211 } 212 } 213 214 func makeMultiwatcherOutput(w *state.Multiwatcher) chan []multiwatcher.Delta { 215 deltasC := make(chan []multiwatcher.Delta) 216 go func() { 217 for { 218 deltas, err := w.Next() 219 if err != nil { 220 return 221 } 222 deltasC <- deltas 223 } 224 }() 225 return deltasC 226 } 227 228 func (s *StateSuite) TestWatchAllModels(c *gc.C) { 229 // The allModelWatcher infrastructure is comprehensively tested 230 // elsewhere. This just ensures things are hooked up correctly in 231 // State.WatchAllModels() 232 233 w := s.State.WatchAllModels() 234 defer w.Stop() 235 deltasC := makeMultiwatcherOutput(w) 236 237 m := s.Factory.MakeMachine(c, nil) 238 239 envSeen := false 240 machineSeen := false 241 timeout := time.After(testing.LongWait) 242 for !envSeen || !machineSeen { 243 select { 244 case deltas := <-deltasC: 245 for _, delta := range deltas { 246 switch e := delta.Entity.(type) { 247 case *multiwatcher.ModelInfo: 248 c.Assert(e.ModelUUID, gc.Equals, s.State.ModelUUID()) 249 envSeen = true 250 case *multiwatcher.MachineInfo: 251 c.Assert(e.ModelUUID, gc.Equals, s.State.ModelUUID()) 252 c.Assert(e.Id, gc.Equals, m.Id()) 253 machineSeen = true 254 } 255 } 256 case <-timeout: 257 c.Fatal("timed out") 258 } 259 } 260 c.Assert(envSeen, jc.IsTrue) 261 c.Assert(machineSeen, jc.IsTrue) 262 } 263 264 type MultiEnvStateSuite struct { 265 ConnSuite 266 OtherState *state.State 267 } 268 269 func (s *MultiEnvStateSuite) SetUpTest(c *gc.C) { 270 s.ConnSuite.SetUpTest(c) 271 s.policy.GetConstraintsValidator = func() (constraints.Validator, error) { 272 validator := constraints.NewValidator() 273 validator.RegisterConflicts([]string{constraints.InstanceType}, []string{constraints.Mem}) 274 validator.RegisterUnsupported([]string{constraints.CpuPower}) 275 return validator, nil 276 } 277 s.OtherState = s.Factory.MakeModel(c, nil) 278 } 279 280 func (s *MultiEnvStateSuite) TearDownTest(c *gc.C) { 281 if s.OtherState != nil { 282 s.OtherState.Close() 283 } 284 s.ConnSuite.TearDownTest(c) 285 } 286 287 func (s *MultiEnvStateSuite) Reset(c *gc.C) { 288 s.TearDownTest(c) 289 s.SetUpTest(c) 290 } 291 292 var _ = gc.Suite(&MultiEnvStateSuite{}) 293 294 func (s *MultiEnvStateSuite) TestWatchTwoEnvironments(c *gc.C) { 295 for i, test := range []struct { 296 about string 297 getWatcher func(*state.State) interface{} 298 setUpState func(*state.State) (assertChanges bool) 299 triggerEvent func(*state.State) 300 }{ 301 { 302 about: "machines", 303 getWatcher: func(st *state.State) interface{} { 304 return st.WatchModelMachines() 305 }, 306 triggerEvent: func(st *state.State) { 307 f := factory.NewFactory(st) 308 m := f.MakeMachine(c, nil) 309 c.Assert(m.Id(), gc.Equals, "0") 310 }, 311 }, 312 { 313 about: "containers", 314 getWatcher: func(st *state.State) interface{} { 315 f := factory.NewFactory(st) 316 m := f.MakeMachine(c, nil) 317 c.Assert(m.Id(), gc.Equals, "0") 318 return m.WatchAllContainers() 319 }, 320 triggerEvent: func(st *state.State) { 321 m, err := st.Machine("0") 322 _, err = st.AddMachineInsideMachine( 323 state.MachineTemplate{ 324 Series: "trusty", 325 Jobs: []state.MachineJob{state.JobHostUnits}, 326 }, 327 m.Id(), 328 instance.KVM, 329 ) 330 c.Assert(err, jc.ErrorIsNil) 331 }, 332 }, { 333 about: "lxd only containers", 334 getWatcher: func(st *state.State) interface{} { 335 f := factory.NewFactory(st) 336 m := f.MakeMachine(c, nil) 337 c.Assert(m.Id(), gc.Equals, "0") 338 return m.WatchContainers(instance.LXD) 339 }, 340 triggerEvent: func(st *state.State) { 341 m, err := st.Machine("0") 342 c.Assert(err, jc.ErrorIsNil) 343 _, err = st.AddMachineInsideMachine( 344 state.MachineTemplate{ 345 Series: "trusty", 346 Jobs: []state.MachineJob{state.JobHostUnits}, 347 }, 348 m.Id(), 349 instance.LXD, 350 ) 351 c.Assert(err, jc.ErrorIsNil) 352 }, 353 }, { 354 about: "units", 355 getWatcher: func(st *state.State) interface{} { 356 f := factory.NewFactory(st) 357 m := f.MakeMachine(c, nil) 358 c.Assert(m.Id(), gc.Equals, "0") 359 return m.WatchUnits() 360 }, 361 triggerEvent: func(st *state.State) { 362 m, err := st.Machine("0") 363 c.Assert(err, jc.ErrorIsNil) 364 f := factory.NewFactory(st) 365 f.MakeUnit(c, &factory.UnitParams{Machine: m}) 366 }, 367 }, { 368 about: "applications", 369 getWatcher: func(st *state.State) interface{} { 370 return st.WatchServices() 371 }, 372 triggerEvent: func(st *state.State) { 373 f := factory.NewFactory(st) 374 f.MakeApplication(c, nil) 375 }, 376 }, { 377 about: "relations", 378 getWatcher: func(st *state.State) interface{} { 379 f := factory.NewFactory(st) 380 wordpressCharm := f.MakeCharm(c, &factory.CharmParams{Name: "wordpress"}) 381 wordpress := f.MakeApplication(c, &factory.ApplicationParams{Name: "wordpress", Charm: wordpressCharm}) 382 return wordpress.WatchRelations() 383 }, 384 setUpState: func(st *state.State) bool { 385 f := factory.NewFactory(st) 386 mysqlCharm := f.MakeCharm(c, &factory.CharmParams{Name: "mysql"}) 387 f.MakeApplication(c, &factory.ApplicationParams{Name: "mysql", Charm: mysqlCharm}) 388 return false 389 }, 390 triggerEvent: func(st *state.State) { 391 eps, err := st.InferEndpoints("wordpress", "mysql") 392 c.Assert(err, jc.ErrorIsNil) 393 _, err = st.AddRelation(eps...) 394 c.Assert(err, jc.ErrorIsNil) 395 }, 396 }, { 397 about: "open ports", 398 getWatcher: func(st *state.State) interface{} { 399 return st.WatchOpenedPorts() 400 }, 401 setUpState: func(st *state.State) bool { 402 f := factory.NewFactory(st) 403 mysql := f.MakeApplication(c, &factory.ApplicationParams{Name: "mysql"}) 404 f.MakeUnit(c, &factory.UnitParams{Application: mysql}) 405 return false 406 }, 407 triggerEvent: func(st *state.State) { 408 u, err := st.Unit("mysql/0") 409 c.Assert(err, jc.ErrorIsNil) 410 err = u.OpenPorts("TCP", 100, 200) 411 c.Assert(err, jc.ErrorIsNil) 412 }, 413 }, { 414 about: "cleanups", 415 getWatcher: func(st *state.State) interface{} { 416 return st.WatchCleanups() 417 }, 418 setUpState: func(st *state.State) bool { 419 f := factory.NewFactory(st) 420 wordpressCharm := f.MakeCharm(c, &factory.CharmParams{Name: "wordpress"}) 421 f.MakeApplication(c, &factory.ApplicationParams{Name: "wordpress", Charm: wordpressCharm}) 422 mysqlCharm := f.MakeCharm(c, &factory.CharmParams{Name: "mysql"}) 423 f.MakeApplication(c, &factory.ApplicationParams{Name: "mysql", Charm: mysqlCharm}) 424 425 // add and destroy a relation, so there is something to cleanup. 426 eps, err := st.InferEndpoints("wordpress", "mysql") 427 c.Assert(err, jc.ErrorIsNil) 428 r := f.MakeRelation(c, &factory.RelationParams{Endpoints: eps}) 429 err = r.Destroy() 430 c.Assert(err, jc.ErrorIsNil) 431 432 return false 433 }, 434 triggerEvent: func(st *state.State) { 435 err := st.Cleanup() 436 c.Assert(err, jc.ErrorIsNil) 437 }, 438 }, { 439 about: "reboots", 440 getWatcher: func(st *state.State) interface{} { 441 f := factory.NewFactory(st) 442 m := f.MakeMachine(c, &factory.MachineParams{}) 443 c.Assert(m.Id(), gc.Equals, "0") 444 w := m.WatchForRebootEvent() 445 return w 446 }, 447 triggerEvent: func(st *state.State) { 448 m, err := st.Machine("0") 449 c.Assert(err, jc.ErrorIsNil) 450 err = m.SetRebootFlag(true) 451 c.Assert(err, jc.ErrorIsNil) 452 }, 453 }, { 454 about: "block devices", 455 getWatcher: func(st *state.State) interface{} { 456 f := factory.NewFactory(st) 457 m := f.MakeMachine(c, &factory.MachineParams{}) 458 c.Assert(m.Id(), gc.Equals, "0") 459 return st.WatchBlockDevices(m.MachineTag()) 460 }, 461 setUpState: func(st *state.State) bool { 462 m, err := st.Machine("0") 463 c.Assert(err, jc.ErrorIsNil) 464 sdb := state.BlockDeviceInfo{DeviceName: "sdb"} 465 err = m.SetMachineBlockDevices(sdb) 466 c.Assert(err, jc.ErrorIsNil) 467 return false 468 }, 469 triggerEvent: func(st *state.State) { 470 m, err := st.Machine("0") 471 c.Assert(err, jc.ErrorIsNil) 472 sdb := state.BlockDeviceInfo{DeviceName: "sdb", Label: "fatty"} 473 err = m.SetMachineBlockDevices(sdb) 474 c.Assert(err, jc.ErrorIsNil) 475 }, 476 }, { 477 about: "statuses", 478 getWatcher: func(st *state.State) interface{} { 479 m, err := st.AddMachine("trusty", state.JobHostUnits) 480 c.Assert(err, jc.ErrorIsNil) 481 c.Assert(m.Id(), gc.Equals, "0") 482 return m.Watch() 483 }, 484 setUpState: func(st *state.State) bool { 485 m, err := st.Machine("0") 486 c.Assert(err, jc.ErrorIsNil) 487 m.SetProvisioned("inst-id", "fake_nonce", nil) 488 return false 489 }, 490 triggerEvent: func(st *state.State) { 491 m, err := st.Machine("0") 492 c.Assert(err, jc.ErrorIsNil) 493 494 now := time.Now() 495 sInfo := status.StatusInfo{ 496 Status: status.Error, 497 Message: "some status", 498 Since: &now, 499 } 500 err = m.SetStatus(sInfo) 501 c.Assert(err, jc.ErrorIsNil) 502 }, 503 }, { 504 about: "settings", 505 getWatcher: func(st *state.State) interface{} { 506 return st.WatchServices() 507 }, 508 setUpState: func(st *state.State) bool { 509 f := factory.NewFactory(st) 510 wordpressCharm := f.MakeCharm(c, &factory.CharmParams{Name: "wordpress"}) 511 f.MakeApplication(c, &factory.ApplicationParams{Name: "wordpress", Charm: wordpressCharm}) 512 return false 513 }, 514 triggerEvent: func(st *state.State) { 515 svc, err := st.Application("wordpress") 516 c.Assert(err, jc.ErrorIsNil) 517 518 err = svc.UpdateConfigSettings(charm.Settings{"blog-title": "awesome"}) 519 c.Assert(err, jc.ErrorIsNil) 520 }, 521 }, { 522 about: "action status", 523 getWatcher: func(st *state.State) interface{} { 524 f := factory.NewFactory(st) 525 dummyCharm := f.MakeCharm(c, &factory.CharmParams{Name: "dummy"}) 526 service := f.MakeApplication(c, &factory.ApplicationParams{Name: "dummy", Charm: dummyCharm}) 527 528 unit, err := service.AddUnit() 529 c.Assert(err, jc.ErrorIsNil) 530 return unit.WatchActionNotifications() 531 }, 532 triggerEvent: func(st *state.State) { 533 unit, err := st.Unit("dummy/0") 534 c.Assert(err, jc.ErrorIsNil) 535 _, err = unit.AddAction("snapshot", nil) 536 c.Assert(err, jc.ErrorIsNil) 537 }, 538 }, { 539 about: "min units", 540 getWatcher: func(st *state.State) interface{} { 541 return st.WatchMinUnits() 542 }, 543 setUpState: func(st *state.State) bool { 544 f := factory.NewFactory(st) 545 wordpressCharm := f.MakeCharm(c, &factory.CharmParams{Name: "wordpress"}) 546 _ = f.MakeApplication(c, &factory.ApplicationParams{Name: "wordpress", Charm: wordpressCharm}) 547 return false 548 }, 549 triggerEvent: func(st *state.State) { 550 wordpress, err := st.Application("wordpress") 551 c.Assert(err, jc.ErrorIsNil) 552 err = wordpress.SetMinUnits(2) 553 c.Assert(err, jc.ErrorIsNil) 554 }, 555 }, 556 } { 557 c.Logf("Test %d: %s", i, test.about) 558 func() { 559 getTestWatcher := func(st *state.State) TestWatcherC { 560 var wc interface{} 561 switch w := test.getWatcher(st).(type) { 562 case statetesting.StringsWatcher: 563 wc = statetesting.NewStringsWatcherC(c, st, w) 564 swc := wc.(statetesting.StringsWatcherC) 565 // consume initial event 566 swc.AssertChange() 567 swc.AssertNoChange() 568 case statetesting.NotifyWatcher: 569 wc = statetesting.NewNotifyWatcherC(c, st, w) 570 nwc := wc.(statetesting.NotifyWatcherC) 571 // consume initial event 572 nwc.AssertOneChange() 573 default: 574 c.Fatalf("unknown watcher type %T", w) 575 } 576 return TestWatcherC{ 577 c: c, 578 State: st, 579 Watcher: wc, 580 } 581 } 582 583 checkIsolationForEnv := func(w1, w2 TestWatcherC) { 584 c.Logf("Making changes to model %s", w1.State.ModelUUID()) 585 // switch on type of watcher here 586 if test.setUpState != nil { 587 588 assertChanges := test.setUpState(w1.State) 589 if assertChanges { 590 // Consume events from setup. 591 w1.AssertChanges() 592 w1.AssertNoChange() 593 w2.AssertNoChange() 594 } 595 } 596 test.triggerEvent(w1.State) 597 w1.AssertChanges() 598 w1.AssertNoChange() 599 w2.AssertNoChange() 600 } 601 602 wc1 := getTestWatcher(s.State) 603 defer wc1.Stop() 604 wc2 := getTestWatcher(s.OtherState) 605 defer wc2.Stop() 606 wc2.AssertNoChange() 607 wc1.AssertNoChange() 608 checkIsolationForEnv(wc1, wc2) 609 checkIsolationForEnv(wc2, wc1) 610 }() 611 s.Reset(c) 612 } 613 } 614 615 type TestWatcherC struct { 616 c *gc.C 617 State *state.State 618 Watcher interface{} 619 } 620 621 func (tw *TestWatcherC) AssertChanges() { 622 switch wc := tw.Watcher.(type) { 623 case statetesting.StringsWatcherC: 624 wc.AssertChanges() 625 case statetesting.NotifyWatcherC: 626 wc.AssertOneChange() 627 default: 628 tw.c.Fatalf("unknown watcher type %T", wc) 629 } 630 } 631 632 func (tw *TestWatcherC) AssertNoChange() { 633 switch wc := tw.Watcher.(type) { 634 case statetesting.StringsWatcherC: 635 wc.AssertNoChange() 636 case statetesting.NotifyWatcherC: 637 wc.AssertNoChange() 638 default: 639 tw.c.Fatalf("unknown watcher type %T", wc) 640 } 641 } 642 643 func (tw *TestWatcherC) Stop() { 644 switch wc := tw.Watcher.(type) { 645 case statetesting.StringsWatcherC: 646 statetesting.AssertStop(tw.c, wc.Watcher) 647 case statetesting.NotifyWatcherC: 648 statetesting.AssertStop(tw.c, wc.Watcher) 649 default: 650 tw.c.Fatalf("unknown watcher type %T", wc) 651 } 652 } 653 654 func (s *StateSuite) TestAddresses(c *gc.C) { 655 var err error 656 machines := make([]*state.Machine, 4) 657 machines[0], err = s.State.AddMachine("quantal", state.JobManageModel, state.JobHostUnits) 658 c.Assert(err, jc.ErrorIsNil) 659 machines[1], err = s.State.AddMachine("quantal", state.JobHostUnits) 660 c.Assert(err, jc.ErrorIsNil) 661 changes, err := s.State.EnableHA(3, constraints.Value{}, "quantal", nil) 662 c.Assert(err, jc.ErrorIsNil) 663 c.Assert(changes.Added, gc.HasLen, 3) 664 665 machines[2], err = s.State.Machine("2") 666 c.Assert(err, jc.ErrorIsNil) 667 machines[3], err = s.State.Machine("3") 668 c.Assert(err, jc.ErrorIsNil) 669 670 for i, m := range machines { 671 err := m.SetProviderAddresses(network.Address{ 672 Type: network.IPv4Address, 673 Scope: network.ScopeCloudLocal, 674 Value: fmt.Sprintf("10.0.0.%d", i), 675 }, network.Address{ 676 Type: network.IPv6Address, 677 Scope: network.ScopeCloudLocal, 678 Value: "::1", 679 }, network.Address{ 680 Type: network.IPv4Address, 681 Scope: network.ScopeMachineLocal, 682 Value: "127.0.0.1", 683 }, network.Address{ 684 Type: network.IPv4Address, 685 Scope: network.ScopePublic, 686 Value: "5.4.3.2", 687 }) 688 c.Assert(err, jc.ErrorIsNil) 689 } 690 cfg, err := s.State.ControllerConfig() 691 c.Assert(err, jc.ErrorIsNil) 692 693 addrs, err := s.State.Addresses() 694 c.Assert(err, jc.ErrorIsNil) 695 c.Assert(addrs, gc.HasLen, 3) 696 c.Assert(addrs, jc.SameContents, []string{ 697 fmt.Sprintf("10.0.0.0:%d", cfg.StatePort()), 698 fmt.Sprintf("10.0.0.2:%d", cfg.StatePort()), 699 fmt.Sprintf("10.0.0.3:%d", cfg.StatePort()), 700 }) 701 702 addrs, err = s.State.APIAddressesFromMachines() 703 c.Assert(err, jc.ErrorIsNil) 704 c.Assert(addrs, gc.HasLen, 3) 705 c.Assert(addrs, jc.SameContents, []string{ 706 fmt.Sprintf("10.0.0.0:%d", cfg.APIPort()), 707 fmt.Sprintf("10.0.0.2:%d", cfg.APIPort()), 708 fmt.Sprintf("10.0.0.3:%d", cfg.APIPort()), 709 }) 710 } 711 712 func (s *StateSuite) TestPing(c *gc.C) { 713 c.Assert(s.State.Ping(), gc.IsNil) 714 gitjujutesting.MgoServer.Restart() 715 c.Assert(s.State.Ping(), gc.NotNil) 716 } 717 718 func (s *StateSuite) TestIsNotFound(c *gc.C) { 719 err1 := fmt.Errorf("unrelated error") 720 err2 := errors.NotFoundf("foo") 721 c.Assert(err1, gc.Not(jc.Satisfies), errors.IsNotFound) 722 c.Assert(err2, jc.Satisfies, errors.IsNotFound) 723 } 724 725 func (s *StateSuite) AssertMachineCount(c *gc.C, expect int) { 726 ms, err := s.State.AllMachines() 727 c.Assert(err, jc.ErrorIsNil) 728 c.Assert(len(ms), gc.Equals, expect) 729 } 730 731 var jobStringTests = []struct { 732 job state.MachineJob 733 s string 734 }{ 735 {state.JobHostUnits, "JobHostUnits"}, 736 {state.JobManageModel, "JobManageModel"}, 737 {0, "<unknown job 0>"}, 738 {5, "<unknown job 5>"}, 739 } 740 741 func (s *StateSuite) TestJobString(c *gc.C) { 742 for _, t := range jobStringTests { 743 c.Check(t.job.String(), gc.Equals, t.s) 744 } 745 } 746 747 func (s *StateSuite) TestAddMachineErrors(c *gc.C) { 748 _, err := s.State.AddMachine("") 749 c.Assert(err, gc.ErrorMatches, "cannot add a new machine: no series specified") 750 _, err = s.State.AddMachine("quantal") 751 c.Assert(err, gc.ErrorMatches, "cannot add a new machine: no jobs specified") 752 _, err = s.State.AddMachine("quantal", state.JobHostUnits, state.JobHostUnits) 753 c.Assert(err, gc.ErrorMatches, "cannot add a new machine: duplicate job: .*") 754 } 755 756 func (s *StateSuite) TestAddMachine(c *gc.C) { 757 allJobs := []state.MachineJob{ 758 state.JobHostUnits, 759 state.JobManageModel, 760 } 761 m0, err := s.State.AddMachine("quantal", allJobs...) 762 c.Assert(err, jc.ErrorIsNil) 763 check := func(m *state.Machine, id, series string, jobs []state.MachineJob) { 764 c.Assert(m.Id(), gc.Equals, id) 765 c.Assert(m.Series(), gc.Equals, series) 766 c.Assert(m.Jobs(), gc.DeepEquals, jobs) 767 s.assertMachineContainers(c, m, nil) 768 } 769 check(m0, "0", "quantal", allJobs) 770 m0, err = s.State.Machine("0") 771 c.Assert(err, jc.ErrorIsNil) 772 check(m0, "0", "quantal", allJobs) 773 774 oneJob := []state.MachineJob{state.JobHostUnits} 775 m1, err := s.State.AddMachine("blahblah", oneJob...) 776 c.Assert(err, jc.ErrorIsNil) 777 check(m1, "1", "blahblah", oneJob) 778 779 m1, err = s.State.Machine("1") 780 c.Assert(err, jc.ErrorIsNil) 781 check(m1, "1", "blahblah", oneJob) 782 783 m, err := s.State.AllMachines() 784 c.Assert(err, jc.ErrorIsNil) 785 c.Assert(m, gc.HasLen, 2) 786 check(m[0], "0", "quantal", allJobs) 787 check(m[1], "1", "blahblah", oneJob) 788 789 st2 := s.Factory.MakeModel(c, nil) 790 defer st2.Close() 791 _, err = st2.AddMachine("quantal", state.JobManageModel) 792 c.Assert(err, gc.ErrorMatches, "cannot add a new machine: controller jobs specified but not allowed") 793 } 794 795 func (s *StateSuite) TestAddMachines(c *gc.C) { 796 oneJob := []state.MachineJob{state.JobHostUnits} 797 cons := constraints.MustParse("mem=4G") 798 hc := instance.MustParseHardware("mem=2G") 799 machineTemplate := state.MachineTemplate{ 800 Series: "precise", 801 Constraints: cons, 802 HardwareCharacteristics: hc, 803 InstanceId: "inst-id", 804 Nonce: "nonce", 805 Jobs: oneJob, 806 } 807 machines, err := s.State.AddMachines(machineTemplate) 808 c.Assert(err, jc.ErrorIsNil) 809 c.Assert(machines, gc.HasLen, 1) 810 m, err := s.State.Machine(machines[0].Id()) 811 c.Assert(err, jc.ErrorIsNil) 812 instId, err := m.InstanceId() 813 c.Assert(err, jc.ErrorIsNil) 814 c.Assert(string(instId), gc.Equals, "inst-id") 815 c.Assert(m.CheckProvisioned("nonce"), jc.IsTrue) 816 c.Assert(m.Series(), gc.Equals, "precise") 817 mcons, err := m.Constraints() 818 c.Assert(err, jc.ErrorIsNil) 819 c.Assert(mcons, gc.DeepEquals, cons) 820 mhc, err := m.HardwareCharacteristics() 821 c.Assert(err, jc.ErrorIsNil) 822 c.Assert(*mhc, gc.DeepEquals, hc) 823 instId, err = m.InstanceId() 824 c.Assert(err, jc.ErrorIsNil) 825 c.Assert(string(instId), gc.Equals, "inst-id") 826 } 827 828 func (s *StateSuite) TestAddMachinesEnvironmentDying(c *gc.C) { 829 env, err := s.State.Model() 830 c.Assert(err, jc.ErrorIsNil) 831 err = env.Destroy() 832 c.Assert(err, jc.ErrorIsNil) 833 // Check that machines cannot be added if the model is initially Dying. 834 _, err = s.State.AddMachine("quantal", state.JobHostUnits) 835 c.Assert(err, gc.ErrorMatches, `cannot add a new machine: model "testenv" is no longer alive`) 836 } 837 838 func (s *StateSuite) TestAddMachinesEnvironmentDyingAfterInitial(c *gc.C) { 839 env, err := s.State.Model() 840 c.Assert(err, jc.ErrorIsNil) 841 // Check that machines cannot be added if the model is initially 842 // Alive but set to Dying immediately before the transaction is run. 843 defer state.SetBeforeHooks(c, s.State, func() { 844 c.Assert(env.Life(), gc.Equals, state.Alive) 845 c.Assert(env.Destroy(), gc.IsNil) 846 }).Check() 847 _, err = s.State.AddMachine("quantal", state.JobHostUnits) 848 c.Assert(err, gc.ErrorMatches, `cannot add a new machine: model "testenv" is no longer alive`) 849 } 850 851 func (s *StateSuite) TestAddMachinesEnvironmentMigrating(c *gc.C) { 852 model, err := s.State.Model() 853 c.Assert(err, jc.ErrorIsNil) 854 err = model.SetMigrationMode(state.MigrationModeExporting) 855 c.Assert(err, jc.ErrorIsNil) 856 // Check that machines cannot be added if the model is initially Dying. 857 _, err = s.State.AddMachine("quantal", state.JobHostUnits) 858 c.Assert(err, gc.ErrorMatches, `cannot add a new machine: model "testenv" is being migrated`) 859 } 860 861 func (s *StateSuite) TestAddMachineExtraConstraints(c *gc.C) { 862 err := s.State.SetModelConstraints(constraints.MustParse("mem=4G")) 863 c.Assert(err, jc.ErrorIsNil) 864 oneJob := []state.MachineJob{state.JobHostUnits} 865 extraCons := constraints.MustParse("cores=4") 866 m, err := s.State.AddOneMachine(state.MachineTemplate{ 867 Series: "quantal", 868 Constraints: extraCons, 869 Jobs: oneJob, 870 }) 871 c.Assert(err, jc.ErrorIsNil) 872 c.Assert(m.Id(), gc.Equals, "0") 873 c.Assert(m.Series(), gc.Equals, "quantal") 874 c.Assert(m.Jobs(), gc.DeepEquals, oneJob) 875 expectedCons := constraints.MustParse("cores=4 mem=4G") 876 mcons, err := m.Constraints() 877 c.Assert(err, jc.ErrorIsNil) 878 c.Assert(mcons, gc.DeepEquals, expectedCons) 879 } 880 881 func (s *StateSuite) TestAddMachineWithVolumes(c *gc.C) { 882 pm := poolmanager.New(state.NewStateSettings(s.State), provider.CommonStorageProviders()) 883 _, err := pm.Create("loop-pool", provider.LoopProviderType, map[string]interface{}{}) 884 c.Assert(err, jc.ErrorIsNil) 885 886 oneJob := []state.MachineJob{state.JobHostUnits} 887 cons := constraints.MustParse("mem=4G") 888 hc := instance.MustParseHardware("mem=2G") 889 890 volume0 := state.VolumeParams{ 891 Pool: "loop-pool", 892 Size: 123, 893 } 894 volume1 := state.VolumeParams{ 895 Pool: "", // use default 896 Size: 456, 897 } 898 volumeAttachment0 := state.VolumeAttachmentParams{} 899 volumeAttachment1 := state.VolumeAttachmentParams{ 900 ReadOnly: true, 901 } 902 903 machineTemplate := state.MachineTemplate{ 904 Series: "precise", 905 Constraints: cons, 906 HardwareCharacteristics: hc, 907 InstanceId: "inst-id", 908 Nonce: "nonce", 909 Jobs: oneJob, 910 Volumes: []state.MachineVolumeParams{{ 911 volume0, volumeAttachment0, 912 }, { 913 volume1, volumeAttachment1, 914 }}, 915 } 916 machines, err := s.State.AddMachines(machineTemplate) 917 c.Assert(err, jc.ErrorIsNil) 918 c.Assert(machines, gc.HasLen, 1) 919 m, err := s.State.Machine(machines[0].Id()) 920 c.Assert(err, jc.ErrorIsNil) 921 922 // When adding the machine, the default pool should 923 // have been set on the volume params. 924 machineTemplate.Volumes[1].Volume.Pool = "loop" 925 926 volumeAttachments, err := s.State.MachineVolumeAttachments(m.MachineTag()) 927 c.Assert(err, jc.ErrorIsNil) 928 c.Assert(volumeAttachments, gc.HasLen, 2) 929 if volumeAttachments[0].Volume() == names.NewVolumeTag(m.Id()+"/1") { 930 va := volumeAttachments 931 va[0], va[1] = va[1], va[0] 932 } 933 for i, att := range volumeAttachments { 934 _, err = att.Info() 935 c.Assert(err, jc.Satisfies, errors.IsNotProvisioned) 936 attachmentParams, ok := att.Params() 937 c.Assert(ok, jc.IsTrue) 938 c.Check(attachmentParams, gc.Equals, machineTemplate.Volumes[i].Attachment) 939 volume, err := s.State.Volume(att.Volume()) 940 c.Assert(err, jc.ErrorIsNil) 941 _, err = volume.Info() 942 c.Assert(err, jc.Satisfies, errors.IsNotProvisioned) 943 volumeParams, ok := volume.Params() 944 c.Assert(ok, jc.IsTrue) 945 c.Check(volumeParams, gc.Equals, machineTemplate.Volumes[i].Volume) 946 } 947 } 948 949 func (s *StateSuite) assertMachineContainers(c *gc.C, m *state.Machine, containers []string) { 950 mc, err := m.Containers() 951 c.Assert(err, jc.ErrorIsNil) 952 c.Assert(mc, gc.DeepEquals, containers) 953 } 954 955 func (s *StateSuite) TestAddContainerToNewMachine(c *gc.C) { 956 oneJob := []state.MachineJob{state.JobHostUnits} 957 958 template := state.MachineTemplate{ 959 Series: "quantal", 960 Jobs: oneJob, 961 } 962 parentTemplate := state.MachineTemplate{ 963 Series: "raring", 964 Jobs: oneJob, 965 } 966 m, err := s.State.AddMachineInsideNewMachine(template, parentTemplate, instance.LXD) 967 c.Assert(err, jc.ErrorIsNil) 968 c.Assert(m.Id(), gc.Equals, "0/lxd/0") 969 c.Assert(m.Series(), gc.Equals, "quantal") 970 c.Assert(m.ContainerType(), gc.Equals, instance.LXD) 971 mcons, err := m.Constraints() 972 c.Assert(err, jc.ErrorIsNil) 973 c.Assert(&mcons, jc.Satisfies, constraints.IsEmpty) 974 c.Assert(m.Jobs(), gc.DeepEquals, oneJob) 975 976 m, err = s.State.Machine("0") 977 c.Assert(err, jc.ErrorIsNil) 978 s.assertMachineContainers(c, m, []string{"0/lxd/0"}) 979 c.Assert(m.Series(), gc.Equals, "raring") 980 981 m, err = s.State.Machine("0/lxd/0") 982 c.Assert(err, jc.ErrorIsNil) 983 s.assertMachineContainers(c, m, nil) 984 c.Assert(m.Jobs(), gc.DeepEquals, oneJob) 985 } 986 987 func (s *StateSuite) TestAddContainerToExistingMachine(c *gc.C) { 988 oneJob := []state.MachineJob{state.JobHostUnits} 989 m0, err := s.State.AddMachine("quantal", oneJob...) 990 c.Assert(err, jc.ErrorIsNil) 991 m1, err := s.State.AddMachine("quantal", oneJob...) 992 c.Assert(err, jc.ErrorIsNil) 993 994 // Add first container. 995 m, err := s.State.AddMachineInsideMachine(state.MachineTemplate{ 996 Series: "quantal", 997 Jobs: []state.MachineJob{state.JobHostUnits}, 998 }, "1", instance.LXD) 999 c.Assert(err, jc.ErrorIsNil) 1000 c.Assert(m.Id(), gc.Equals, "1/lxd/0") 1001 c.Assert(m.Series(), gc.Equals, "quantal") 1002 c.Assert(m.ContainerType(), gc.Equals, instance.LXD) 1003 mcons, err := m.Constraints() 1004 c.Assert(err, jc.ErrorIsNil) 1005 c.Assert(&mcons, jc.Satisfies, constraints.IsEmpty) 1006 c.Assert(m.Jobs(), gc.DeepEquals, oneJob) 1007 s.assertMachineContainers(c, m1, []string{"1/lxd/0"}) 1008 1009 s.assertMachineContainers(c, m0, nil) 1010 s.assertMachineContainers(c, m1, []string{"1/lxd/0"}) 1011 m, err = s.State.Machine("1/lxd/0") 1012 c.Assert(err, jc.ErrorIsNil) 1013 s.assertMachineContainers(c, m, nil) 1014 1015 // Add second container. 1016 m, err = s.State.AddMachineInsideMachine(state.MachineTemplate{ 1017 Series: "quantal", 1018 Jobs: []state.MachineJob{state.JobHostUnits}, 1019 }, "1", instance.LXD) 1020 c.Assert(err, jc.ErrorIsNil) 1021 c.Assert(m.Id(), gc.Equals, "1/lxd/1") 1022 c.Assert(m.Series(), gc.Equals, "quantal") 1023 c.Assert(m.ContainerType(), gc.Equals, instance.LXD) 1024 c.Assert(m.Jobs(), gc.DeepEquals, oneJob) 1025 s.assertMachineContainers(c, m1, []string{"1/lxd/0", "1/lxd/1"}) 1026 } 1027 1028 func (s *StateSuite) TestAddContainerToMachineWithKnownSupportedContainers(c *gc.C) { 1029 oneJob := []state.MachineJob{state.JobHostUnits} 1030 host, err := s.State.AddMachine("quantal", oneJob...) 1031 c.Assert(err, jc.ErrorIsNil) 1032 err = host.SetSupportedContainers([]instance.ContainerType{instance.KVM}) 1033 c.Assert(err, jc.ErrorIsNil) 1034 1035 m, err := s.State.AddMachineInsideMachine(state.MachineTemplate{ 1036 Series: "quantal", 1037 Jobs: []state.MachineJob{state.JobHostUnits}, 1038 }, "0", instance.KVM) 1039 c.Assert(err, jc.ErrorIsNil) 1040 c.Assert(m.Id(), gc.Equals, "0/kvm/0") 1041 s.assertMachineContainers(c, host, []string{"0/kvm/0"}) 1042 } 1043 1044 func (s *StateSuite) TestAddInvalidContainerToMachineWithKnownSupportedContainers(c *gc.C) { 1045 oneJob := []state.MachineJob{state.JobHostUnits} 1046 host, err := s.State.AddMachine("quantal", oneJob...) 1047 c.Assert(err, jc.ErrorIsNil) 1048 err = host.SetSupportedContainers([]instance.ContainerType{instance.KVM}) 1049 c.Assert(err, jc.ErrorIsNil) 1050 1051 _, err = s.State.AddMachineInsideMachine(state.MachineTemplate{ 1052 Series: "quantal", 1053 Jobs: []state.MachineJob{state.JobHostUnits}, 1054 }, "0", instance.LXD) 1055 c.Assert(err, gc.ErrorMatches, "cannot add a new machine: machine 0 cannot host lxd containers") 1056 s.assertMachineContainers(c, host, nil) 1057 } 1058 1059 func (s *StateSuite) TestAddContainerToMachineSupportingNoContainers(c *gc.C) { 1060 oneJob := []state.MachineJob{state.JobHostUnits} 1061 host, err := s.State.AddMachine("quantal", oneJob...) 1062 c.Assert(err, jc.ErrorIsNil) 1063 err = host.SupportsNoContainers() 1064 c.Assert(err, jc.ErrorIsNil) 1065 1066 _, err = s.State.AddMachineInsideMachine(state.MachineTemplate{ 1067 Series: "quantal", 1068 Jobs: []state.MachineJob{state.JobHostUnits}, 1069 }, "0", instance.LXD) 1070 c.Assert(err, gc.ErrorMatches, "cannot add a new machine: machine 0 cannot host lxd containers") 1071 s.assertMachineContainers(c, host, nil) 1072 } 1073 1074 func (s *StateSuite) TestInvalidAddMachineParams(c *gc.C) { 1075 instIdTemplate := state.MachineTemplate{ 1076 Series: "quantal", 1077 Jobs: []state.MachineJob{state.JobHostUnits}, 1078 InstanceId: "i-foo", 1079 } 1080 normalTemplate := state.MachineTemplate{ 1081 Series: "quantal", 1082 Jobs: []state.MachineJob{state.JobHostUnits}, 1083 } 1084 _, err := s.State.AddMachineInsideMachine(instIdTemplate, "0", instance.LXD) 1085 c.Check(err, gc.ErrorMatches, "cannot add a new machine: cannot specify instance id for a new container") 1086 1087 _, err = s.State.AddMachineInsideNewMachine(instIdTemplate, normalTemplate, instance.LXD) 1088 c.Check(err, gc.ErrorMatches, "cannot add a new machine: cannot specify instance id for a new container") 1089 1090 _, err = s.State.AddMachineInsideNewMachine(normalTemplate, instIdTemplate, instance.LXD) 1091 c.Check(err, gc.ErrorMatches, "cannot add a new machine: cannot specify instance id for a new container") 1092 1093 _, err = s.State.AddOneMachine(instIdTemplate) 1094 c.Check(err, gc.ErrorMatches, "cannot add a new machine: cannot add a machine with an instance id and no nonce") 1095 1096 _, err = s.State.AddOneMachine(state.MachineTemplate{ 1097 Series: "quantal", 1098 Jobs: []state.MachineJob{state.JobHostUnits, state.JobHostUnits}, 1099 InstanceId: "i-foo", 1100 Nonce: "nonce", 1101 }) 1102 c.Check(err, gc.ErrorMatches, fmt.Sprintf("cannot add a new machine: duplicate job: %s", state.JobHostUnits)) 1103 1104 noSeriesTemplate := state.MachineTemplate{ 1105 Jobs: []state.MachineJob{state.JobHostUnits, state.JobHostUnits}, 1106 } 1107 _, err = s.State.AddOneMachine(noSeriesTemplate) 1108 c.Check(err, gc.ErrorMatches, "cannot add a new machine: no series specified") 1109 1110 _, err = s.State.AddMachineInsideNewMachine(noSeriesTemplate, normalTemplate, instance.LXD) 1111 c.Check(err, gc.ErrorMatches, "cannot add a new machine: no series specified") 1112 1113 _, err = s.State.AddMachineInsideNewMachine(normalTemplate, noSeriesTemplate, instance.LXD) 1114 c.Check(err, gc.ErrorMatches, "cannot add a new machine: no series specified") 1115 1116 _, err = s.State.AddMachineInsideMachine(noSeriesTemplate, "0", instance.LXD) 1117 c.Check(err, gc.ErrorMatches, "cannot add a new machine: no series specified") 1118 } 1119 1120 func (s *StateSuite) TestAddContainerErrors(c *gc.C) { 1121 template := state.MachineTemplate{ 1122 Series: "quantal", 1123 Jobs: []state.MachineJob{state.JobHostUnits}, 1124 } 1125 _, err := s.State.AddMachineInsideMachine(template, "10", instance.LXD) 1126 c.Assert(err, gc.ErrorMatches, "cannot add a new machine: machine 10 not found") 1127 _, err = s.State.AddMachineInsideMachine(template, "10", "") 1128 c.Assert(err, gc.ErrorMatches, "cannot add a new machine: no container type specified") 1129 } 1130 1131 func (s *StateSuite) TestInjectMachineErrors(c *gc.C) { 1132 injectMachine := func(series string, instanceId instance.Id, nonce string, jobs ...state.MachineJob) error { 1133 _, err := s.State.AddOneMachine(state.MachineTemplate{ 1134 Series: series, 1135 Jobs: jobs, 1136 InstanceId: instanceId, 1137 Nonce: nonce, 1138 }) 1139 return err 1140 } 1141 err := injectMachine("", "i-minvalid", agent.BootstrapNonce, state.JobHostUnits) 1142 c.Assert(err, gc.ErrorMatches, "cannot add a new machine: no series specified") 1143 err = injectMachine("quantal", "", agent.BootstrapNonce, state.JobHostUnits) 1144 c.Assert(err, gc.ErrorMatches, "cannot add a new machine: cannot specify a nonce without an instance id") 1145 err = injectMachine("quantal", "i-minvalid", "", state.JobHostUnits) 1146 c.Assert(err, gc.ErrorMatches, "cannot add a new machine: cannot add a machine with an instance id and no nonce") 1147 err = injectMachine("quantal", agent.BootstrapNonce, "i-mlazy") 1148 c.Assert(err, gc.ErrorMatches, "cannot add a new machine: no jobs specified") 1149 } 1150 1151 func (s *StateSuite) TestInjectMachine(c *gc.C) { 1152 cons := constraints.MustParse("mem=4G") 1153 arch := "amd64" 1154 mem := uint64(1024) 1155 disk := uint64(1024) 1156 tags := []string{"foo", "bar"} 1157 template := state.MachineTemplate{ 1158 Series: "quantal", 1159 Jobs: []state.MachineJob{state.JobHostUnits, state.JobManageModel}, 1160 Constraints: cons, 1161 InstanceId: "i-mindustrious", 1162 Nonce: agent.BootstrapNonce, 1163 HardwareCharacteristics: instance.HardwareCharacteristics{ 1164 Arch: &arch, 1165 Mem: &mem, 1166 RootDisk: &disk, 1167 Tags: &tags, 1168 }, 1169 } 1170 m, err := s.State.AddOneMachine(template) 1171 c.Assert(err, jc.ErrorIsNil) 1172 c.Assert(m.Jobs(), gc.DeepEquals, template.Jobs) 1173 instanceId, err := m.InstanceId() 1174 c.Assert(err, jc.ErrorIsNil) 1175 c.Assert(instanceId, gc.Equals, template.InstanceId) 1176 mcons, err := m.Constraints() 1177 c.Assert(err, jc.ErrorIsNil) 1178 c.Assert(cons, gc.DeepEquals, mcons) 1179 characteristics, err := m.HardwareCharacteristics() 1180 c.Assert(err, jc.ErrorIsNil) 1181 c.Assert(*characteristics, gc.DeepEquals, template.HardwareCharacteristics) 1182 1183 // Make sure the bootstrap nonce value is set. 1184 c.Assert(m.CheckProvisioned(template.Nonce), jc.IsTrue) 1185 } 1186 1187 func (s *StateSuite) TestAddContainerToInjectedMachine(c *gc.C) { 1188 oneJob := []state.MachineJob{state.JobHostUnits} 1189 template := state.MachineTemplate{ 1190 Series: "quantal", 1191 InstanceId: "i-mindustrious", 1192 Nonce: agent.BootstrapNonce, 1193 Jobs: []state.MachineJob{state.JobHostUnits, state.JobManageModel}, 1194 } 1195 m0, err := s.State.AddOneMachine(template) 1196 c.Assert(err, jc.ErrorIsNil) 1197 1198 // Add first container. 1199 template = state.MachineTemplate{ 1200 Series: "quantal", 1201 Jobs: []state.MachineJob{state.JobHostUnits}, 1202 } 1203 m, err := s.State.AddMachineInsideMachine(template, "0", instance.LXD) 1204 c.Assert(err, jc.ErrorIsNil) 1205 c.Assert(m.Id(), gc.Equals, "0/lxd/0") 1206 c.Assert(m.Series(), gc.Equals, "quantal") 1207 c.Assert(m.ContainerType(), gc.Equals, instance.LXD) 1208 mcons, err := m.Constraints() 1209 c.Assert(err, jc.ErrorIsNil) 1210 c.Assert(&mcons, jc.Satisfies, constraints.IsEmpty) 1211 c.Assert(m.Jobs(), gc.DeepEquals, oneJob) 1212 s.assertMachineContainers(c, m0, []string{"0/lxd/0"}) 1213 1214 // Add second container. 1215 m, err = s.State.AddMachineInsideMachine(template, "0", instance.LXD) 1216 c.Assert(err, jc.ErrorIsNil) 1217 c.Assert(m.Id(), gc.Equals, "0/lxd/1") 1218 c.Assert(m.Series(), gc.Equals, "quantal") 1219 c.Assert(m.ContainerType(), gc.Equals, instance.LXD) 1220 c.Assert(m.Jobs(), gc.DeepEquals, oneJob) 1221 s.assertMachineContainers(c, m0, []string{"0/lxd/0", "0/lxd/1"}) 1222 } 1223 1224 func (s *StateSuite) TestAddMachineCanOnlyAddControllerForMachine0(c *gc.C) { 1225 template := state.MachineTemplate{ 1226 Series: "quantal", 1227 Jobs: []state.MachineJob{state.JobManageModel}, 1228 } 1229 // Check that we can add the bootstrap machine. 1230 m, err := s.State.AddOneMachine(template) 1231 c.Assert(err, jc.ErrorIsNil) 1232 c.Assert(m.Id(), gc.Equals, "0") 1233 c.Assert(m.WantsVote(), jc.IsTrue) 1234 c.Assert(m.Jobs(), gc.DeepEquals, []state.MachineJob{state.JobManageModel}) 1235 1236 // Check that the controller information is correct. 1237 info, err := s.State.ControllerInfo() 1238 c.Assert(err, jc.ErrorIsNil) 1239 c.Assert(info.ModelTag, gc.Equals, s.modelTag) 1240 c.Assert(info.MachineIds, gc.DeepEquals, []string{"0"}) 1241 c.Assert(info.VotingMachineIds, gc.DeepEquals, []string{"0"}) 1242 1243 const errCannotAdd = "cannot add a new machine: controller jobs specified but not allowed" 1244 m, err = s.State.AddOneMachine(template) 1245 c.Assert(err, gc.ErrorMatches, errCannotAdd) 1246 1247 m, err = s.State.AddMachineInsideMachine(template, "0", instance.LXD) 1248 c.Assert(err, gc.ErrorMatches, errCannotAdd) 1249 1250 m, err = s.State.AddMachineInsideNewMachine(template, template, instance.LXD) 1251 c.Assert(err, gc.ErrorMatches, errCannotAdd) 1252 } 1253 1254 func (s *StateSuite) TestReadMachine(c *gc.C) { 1255 machine, err := s.State.AddMachine("quantal", state.JobHostUnits) 1256 c.Assert(err, jc.ErrorIsNil) 1257 expectedId := machine.Id() 1258 machine, err = s.State.Machine(expectedId) 1259 c.Assert(err, jc.ErrorIsNil) 1260 c.Assert(machine.Id(), gc.Equals, expectedId) 1261 } 1262 1263 func (s *StateSuite) TestMachineNotFound(c *gc.C) { 1264 _, err := s.State.Machine("0") 1265 c.Assert(err, gc.ErrorMatches, "machine 0 not found") 1266 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1267 } 1268 1269 func (s *StateSuite) TestMachineIdLessThan(c *gc.C) { 1270 c.Assert(state.MachineIdLessThan("0", "0"), jc.IsFalse) 1271 c.Assert(state.MachineIdLessThan("0", "1"), jc.IsTrue) 1272 c.Assert(state.MachineIdLessThan("1", "0"), jc.IsFalse) 1273 c.Assert(state.MachineIdLessThan("10", "2"), jc.IsFalse) 1274 c.Assert(state.MachineIdLessThan("0", "0/lxd/0"), jc.IsTrue) 1275 c.Assert(state.MachineIdLessThan("0/lxd/0", "0"), jc.IsFalse) 1276 c.Assert(state.MachineIdLessThan("1", "0/lxd/0"), jc.IsFalse) 1277 c.Assert(state.MachineIdLessThan("0/lxd/0", "1"), jc.IsTrue) 1278 c.Assert(state.MachineIdLessThan("0/lxd/0/lxd/1", "0/lxd/0"), jc.IsFalse) 1279 c.Assert(state.MachineIdLessThan("0/kvm/0", "0/lxd/0"), jc.IsTrue) 1280 } 1281 1282 func (s *StateSuite) TestAllMachines(c *gc.C) { 1283 numInserts := 42 1284 for i := 0; i < numInserts; i++ { 1285 m, err := s.State.AddMachine("quantal", state.JobHostUnits) 1286 c.Assert(err, jc.ErrorIsNil) 1287 err = m.SetProvisioned(instance.Id(fmt.Sprintf("foo-%d", i)), "fake_nonce", nil) 1288 c.Assert(err, jc.ErrorIsNil) 1289 err = m.SetAgentVersion(version.MustParseBinary("7.8.9-quantal-amd64")) 1290 c.Assert(err, jc.ErrorIsNil) 1291 err = m.Destroy() 1292 c.Assert(err, jc.ErrorIsNil) 1293 } 1294 s.AssertMachineCount(c, numInserts) 1295 ms, _ := s.State.AllMachines() 1296 for i, m := range ms { 1297 c.Assert(m.Id(), gc.Equals, strconv.Itoa(i)) 1298 instId, err := m.InstanceId() 1299 c.Assert(err, jc.ErrorIsNil) 1300 c.Assert(string(instId), gc.Equals, fmt.Sprintf("foo-%d", i)) 1301 tools, err := m.AgentTools() 1302 c.Check(err, jc.ErrorIsNil) 1303 c.Check(tools.Version, gc.DeepEquals, version.MustParseBinary("7.8.9-quantal-amd64")) 1304 c.Assert(m.Life(), gc.Equals, state.Dying) 1305 } 1306 } 1307 1308 func (s *StateSuite) TestAllRelations(c *gc.C) { 1309 const numRelations = 32 1310 _, err := s.State.AddMachine("quantal", state.JobHostUnits) 1311 c.Assert(err, jc.ErrorIsNil) 1312 mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql")) 1313 _, err = mysql.AddUnit() 1314 c.Assert(err, jc.ErrorIsNil) 1315 wordpressCharm := s.AddTestingCharm(c, "wordpress") 1316 for i := 0; i < numRelations; i++ { 1317 applicationname := fmt.Sprintf("wordpress%d", i) 1318 wordpress := s.AddTestingService(c, applicationname, wordpressCharm) 1319 _, err = wordpress.AddUnit() 1320 c.Assert(err, jc.ErrorIsNil) 1321 eps, err := s.State.InferEndpoints(applicationname, "mysql") 1322 c.Assert(err, jc.ErrorIsNil) 1323 _, err = s.State.AddRelation(eps...) 1324 c.Assert(err, jc.ErrorIsNil) 1325 } 1326 1327 relations, _ := s.State.AllRelations() 1328 1329 c.Assert(len(relations), gc.Equals, numRelations) 1330 for i, relation := range relations { 1331 c.Assert(relation.Id(), gc.Equals, i) 1332 c.Assert(relation, gc.Matches, fmt.Sprintf("wordpress%d:.+ mysql:.+", i)) 1333 } 1334 } 1335 1336 func (s *StateSuite) TestAddApplication(c *gc.C) { 1337 ch := s.AddTestingCharm(c, "dummy") 1338 _, err := s.State.AddApplication(state.AddApplicationArgs{Name: "haha/borken", Charm: ch}) 1339 c.Assert(err, gc.ErrorMatches, `cannot add application "haha/borken": invalid name`) 1340 _, err = s.State.Application("haha/borken") 1341 c.Assert(err, gc.ErrorMatches, `"haha/borken" is not a valid application name`) 1342 1343 // set that a nil charm is handled correctly 1344 _, err = s.State.AddApplication(state.AddApplicationArgs{Name: "umadbro"}) 1345 c.Assert(err, gc.ErrorMatches, `cannot add application "umadbro": charm is nil`) 1346 1347 insettings := charm.Settings{"tuning": "optimized"} 1348 1349 wordpress, err := s.State.AddApplication(state.AddApplicationArgs{Name: "wordpress", Charm: ch, Settings: insettings}) 1350 c.Assert(err, jc.ErrorIsNil) 1351 c.Assert(wordpress.Name(), gc.Equals, "wordpress") 1352 outsettings, err := wordpress.ConfigSettings() 1353 c.Assert(err, jc.ErrorIsNil) 1354 c.Assert(outsettings, gc.DeepEquals, insettings) 1355 1356 mysql, err := s.State.AddApplication(state.AddApplicationArgs{Name: "mysql", Charm: ch}) 1357 c.Assert(err, jc.ErrorIsNil) 1358 c.Assert(mysql.Name(), gc.Equals, "mysql") 1359 sInfo, err := mysql.Status() 1360 c.Assert(sInfo.Status, gc.Equals, status.Waiting) 1361 c.Assert(sInfo.Message, gc.Equals, "waiting for machine") 1362 1363 // Check that retrieving the new created services works correctly. 1364 wordpress, err = s.State.Application("wordpress") 1365 c.Assert(err, jc.ErrorIsNil) 1366 c.Assert(wordpress.Name(), gc.Equals, "wordpress") 1367 ch, _, err = wordpress.Charm() 1368 c.Assert(err, jc.ErrorIsNil) 1369 c.Assert(ch.URL(), gc.DeepEquals, ch.URL()) 1370 mysql, err = s.State.Application("mysql") 1371 c.Assert(err, jc.ErrorIsNil) 1372 c.Assert(mysql.Name(), gc.Equals, "mysql") 1373 ch, _, err = mysql.Charm() 1374 c.Assert(err, jc.ErrorIsNil) 1375 c.Assert(ch.URL(), gc.DeepEquals, ch.URL()) 1376 } 1377 1378 func (s *StateSuite) TestAddServiceEnvironmentDying(c *gc.C) { 1379 charm := s.AddTestingCharm(c, "dummy") 1380 // Check that services cannot be added if the model is initially Dying. 1381 env, err := s.State.Model() 1382 c.Assert(err, jc.ErrorIsNil) 1383 err = env.Destroy() 1384 c.Assert(err, jc.ErrorIsNil) 1385 _, err = s.State.AddApplication(state.AddApplicationArgs{Name: "s1", Charm: charm}) 1386 c.Assert(err, gc.ErrorMatches, `cannot add application "s1": model "testenv" is no longer alive`) 1387 } 1388 1389 func (s *StateSuite) TestAddServiceEnvironmentMigrating(c *gc.C) { 1390 charm := s.AddTestingCharm(c, "dummy") 1391 // Check that services cannot be added if the model is initially Dying. 1392 env, err := s.State.Model() 1393 c.Assert(err, jc.ErrorIsNil) 1394 err = env.SetMigrationMode(state.MigrationModeExporting) 1395 c.Assert(err, jc.ErrorIsNil) 1396 _, err = s.State.AddApplication(state.AddApplicationArgs{Name: "s1", Charm: charm}) 1397 c.Assert(err, gc.ErrorMatches, `cannot add application "s1": model "testenv" is being migrated`) 1398 } 1399 1400 func (s *StateSuite) TestAddServiceEnvironmentDyingAfterInitial(c *gc.C) { 1401 charm := s.AddTestingCharm(c, "dummy") 1402 s.AddTestingService(c, "s0", charm) 1403 env, err := s.State.Model() 1404 c.Assert(err, jc.ErrorIsNil) 1405 // Check that services cannot be added if the model is initially 1406 // Alive but set to Dying immediately before the transaction is run. 1407 defer state.SetBeforeHooks(c, s.State, func() { 1408 c.Assert(env.Life(), gc.Equals, state.Alive) 1409 c.Assert(env.Destroy(), gc.IsNil) 1410 }).Check() 1411 _, err = s.State.AddApplication(state.AddApplicationArgs{Name: "s1", Charm: charm}) 1412 c.Assert(err, gc.ErrorMatches, `cannot add application "s1": model "testenv" is no longer alive`) 1413 } 1414 1415 func (s *StateSuite) TestServiceNotFound(c *gc.C) { 1416 _, err := s.State.Application("bummer") 1417 c.Assert(err, gc.ErrorMatches, `application "bummer" not found`) 1418 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1419 } 1420 1421 func (s *StateSuite) TestAddServiceWithDefaultBindings(c *gc.C) { 1422 ch := s.AddMetaCharm(c, "mysql", metaBase, 42) 1423 svc, err := s.State.AddApplication(state.AddApplicationArgs{ 1424 Name: "yoursql", 1425 Charm: ch, 1426 }) 1427 c.Assert(err, jc.ErrorIsNil) 1428 1429 // Read them back to verify defaults and given bindings got merged as 1430 // expected. 1431 bindings, err := svc.EndpointBindings() 1432 c.Assert(err, jc.ErrorIsNil) 1433 c.Assert(bindings, jc.DeepEquals, map[string]string{ 1434 "server": "", 1435 "client": "", 1436 "cluster": "", 1437 }) 1438 1439 // Removing the service also removes its bindings. 1440 err = svc.Destroy() 1441 c.Assert(err, jc.ErrorIsNil) 1442 err = svc.Refresh() 1443 c.Assert(err, jc.Satisfies, errors.IsNotFound) 1444 state.AssertEndpointBindingsNotFoundForService(c, svc) 1445 } 1446 1447 func (s *StateSuite) TestAddServiceWithSpecifiedBindings(c *gc.C) { 1448 // Add extra spaces to use in bindings. 1449 _, err := s.State.AddSpace("db", "", nil, false) 1450 c.Assert(err, jc.ErrorIsNil) 1451 _, err = s.State.AddSpace("client", "", nil, true) 1452 c.Assert(err, jc.ErrorIsNil) 1453 1454 // Specify some bindings, but not all when adding the service. 1455 ch := s.AddMetaCharm(c, "mysql", metaBase, 43) 1456 svc, err := s.State.AddApplication(state.AddApplicationArgs{ 1457 Name: "yoursql", 1458 Charm: ch, 1459 EndpointBindings: map[string]string{ 1460 "client": "client", 1461 "cluster": "db", 1462 }, 1463 }) 1464 c.Assert(err, jc.ErrorIsNil) 1465 1466 // Read them back to verify defaults and given bindings got merged as 1467 // expected. 1468 bindings, err := svc.EndpointBindings() 1469 c.Assert(err, jc.ErrorIsNil) 1470 c.Assert(bindings, jc.DeepEquals, map[string]string{ 1471 "server": "", // inherited from defaults. 1472 "client": "client", 1473 "cluster": "db", 1474 }) 1475 } 1476 1477 func (s *StateSuite) TestAddServiceWithInvalidBindings(c *gc.C) { 1478 charm := s.AddMetaCharm(c, "mysql", metaBase, 44) 1479 // Add extra spaces to use in bindings. 1480 _, err := s.State.AddSpace("db", "", nil, false) 1481 c.Assert(err, jc.ErrorIsNil) 1482 _, err = s.State.AddSpace("client", "", nil, true) 1483 c.Assert(err, jc.ErrorIsNil) 1484 1485 for i, test := range []struct { 1486 about string 1487 bindings map[string]string 1488 expectedError string 1489 }{{ 1490 about: "extra endpoint bound to unknown space", 1491 bindings: map[string]string{"extra": "missing"}, 1492 expectedError: `unknown endpoint "extra" not valid`, 1493 }, { 1494 about: "extra endpoint not bound to a space", 1495 bindings: map[string]string{"extra": ""}, 1496 expectedError: `unknown endpoint "extra" not valid`, 1497 }, { 1498 about: "two extra endpoints, both bound to known spaces", 1499 bindings: map[string]string{"ex1": "db", "ex2": "client"}, 1500 expectedError: `unknown endpoint "ex(1|2)" not valid`, 1501 }, { 1502 about: "empty endpoint bound to unknown space", 1503 bindings: map[string]string{"": "anything"}, 1504 expectedError: `unknown endpoint "" not valid`, 1505 }, { 1506 about: "empty endpoint not bound to a space", 1507 bindings: map[string]string{"": ""}, 1508 expectedError: `unknown endpoint "" not valid`, 1509 }, { 1510 about: "known endpoint bound to unknown space", 1511 bindings: map[string]string{"server": "invalid"}, 1512 expectedError: `unknown space "invalid" not valid`, 1513 }, { 1514 about: "known endpoint bound correctly and an extra endpoint", 1515 bindings: map[string]string{"server": "db", "foo": "public"}, 1516 expectedError: `unknown endpoint "foo" not valid`, 1517 }} { 1518 c.Logf("test #%d: %s", i, test.about) 1519 1520 _, err := s.State.AddApplication(state.AddApplicationArgs{ 1521 Name: "yoursql", 1522 Charm: charm, 1523 EndpointBindings: test.bindings, 1524 }) 1525 c.Check(err, gc.ErrorMatches, `cannot add application "yoursql": `+test.expectedError) 1526 c.Check(err, jc.Satisfies, errors.IsNotValid) 1527 } 1528 } 1529 1530 func (s *StateSuite) TestAddServiceMachinePlacementInvalidSeries(c *gc.C) { 1531 m, err := s.State.AddMachine("trusty", state.JobHostUnits) 1532 c.Assert(err, jc.ErrorIsNil) 1533 1534 charm := s.AddTestingCharm(c, "dummy") 1535 _, err = s.State.AddApplication(state.AddApplicationArgs{ 1536 Name: "wordpress", Charm: charm, 1537 Placement: []*instance.Placement{ 1538 {instance.MachineScope, m.Id()}, 1539 }, 1540 }) 1541 c.Assert(err, gc.ErrorMatches, "cannot add application \"wordpress\": cannot deploy to machine .*: series does not match") 1542 } 1543 1544 func (s *StateSuite) TestAddServiceIncompatibleOSWithSeriesInURL(c *gc.C) { 1545 charm := s.AddTestingCharm(c, "dummy") 1546 // A charm with a series in its URL is implicitly supported by that 1547 // series only. 1548 _, err := s.State.AddApplication(state.AddApplicationArgs{ 1549 Name: "wordpress", Charm: charm, 1550 Series: "centos7", 1551 }) 1552 c.Assert(err, gc.ErrorMatches, `cannot add application "wordpress": series "centos7" \(OS \"CentOS"\) not supported by charm, supported series are "quantal"`) 1553 } 1554 1555 func (s *StateSuite) TestAddServiceCompatibleOSWithSeriesInURL(c *gc.C) { 1556 charm := s.AddTestingCharm(c, "dummy") 1557 // A charm with a series in its URL is implicitly supported by that 1558 // series only. 1559 _, err := s.State.AddApplication(state.AddApplicationArgs{ 1560 Name: "wordpress", Charm: charm, 1561 Series: charm.URL().Series, 1562 }) 1563 c.Assert(err, jc.ErrorIsNil) 1564 } 1565 1566 func (s *StateSuite) TestAddServiceCompatibleOSWithNoExplicitSupportedSeries(c *gc.C) { 1567 // If a charm doesn't declare any series, we can add it with any series we choose. 1568 charm := s.AddSeriesCharm(c, "dummy", "") 1569 _, err := s.State.AddApplication(state.AddApplicationArgs{ 1570 Name: "wordpress", Charm: charm, 1571 Series: "quantal", 1572 }) 1573 c.Assert(err, jc.ErrorIsNil) 1574 } 1575 1576 func (s *StateSuite) TestAddServiceOSIncompatibleWithSupportedSeries(c *gc.C) { 1577 charm := state.AddTestingCharmMultiSeries(c, s.State, "multi-series") 1578 // A charm with supported series can only be force-deployed to series 1579 // of the same operating systems as the suppoted series. 1580 _, err := s.State.AddApplication(state.AddApplicationArgs{ 1581 Name: "wordpress", Charm: charm, 1582 Series: "centos7", 1583 }) 1584 c.Assert(err, gc.ErrorMatches, `cannot add application "wordpress": series "centos7" \(OS "CentOS"\) not supported by charm, supported series are "precise, trusty"`) 1585 } 1586 1587 func (s *StateSuite) TestAllApplications(c *gc.C) { 1588 charm := s.AddTestingCharm(c, "dummy") 1589 services, err := s.State.AllApplications() 1590 c.Assert(err, jc.ErrorIsNil) 1591 c.Assert(len(services), gc.Equals, 0) 1592 1593 // Check that after adding services the result is ok. 1594 _, err = s.State.AddApplication(state.AddApplicationArgs{Name: "wordpress", Charm: charm}) 1595 c.Assert(err, jc.ErrorIsNil) 1596 services, err = s.State.AllApplications() 1597 c.Assert(err, jc.ErrorIsNil) 1598 c.Assert(len(services), gc.Equals, 1) 1599 1600 _, err = s.State.AddApplication(state.AddApplicationArgs{Name: "mysql", Charm: charm}) 1601 c.Assert(err, jc.ErrorIsNil) 1602 services, err = s.State.AllApplications() 1603 c.Assert(err, jc.ErrorIsNil) 1604 c.Assert(services, gc.HasLen, 2) 1605 1606 // Check the returned service, order is defined by sorted keys. 1607 names := make([]string, len(services)) 1608 for i, svc := range services { 1609 names[i] = svc.Name() 1610 } 1611 sort.Strings(names) 1612 c.Assert(names[0], gc.Equals, "mysql") 1613 c.Assert(names[1], gc.Equals, "wordpress") 1614 } 1615 1616 var inferEndpointsTests = []struct { 1617 summary string 1618 inputs [][]string 1619 eps []state.Endpoint 1620 err string 1621 }{ 1622 { 1623 summary: "insane args", 1624 inputs: [][]string{nil}, 1625 err: `cannot relate 0 endpoints`, 1626 }, { 1627 summary: "insane args", 1628 inputs: [][]string{{"blah", "blur", "bleurgh"}}, 1629 err: `cannot relate 3 endpoints`, 1630 }, { 1631 summary: "invalid args", 1632 inputs: [][]string{ 1633 {"ping:"}, 1634 {":pong"}, 1635 {":"}, 1636 }, 1637 err: `invalid endpoint ".*"`, 1638 }, { 1639 summary: "unknown service", 1640 inputs: [][]string{{"wooble"}}, 1641 err: `application "wooble" not found`, 1642 }, { 1643 summary: "invalid relations", 1644 inputs: [][]string{ 1645 {"ms", "ms"}, 1646 {"wp", "wp"}, 1647 {"rk1", "rk1"}, 1648 {"rk1", "rk2"}, 1649 }, 1650 err: `no relations found`, 1651 }, { 1652 summary: "container scoped relation not possible when there's no subordinate", 1653 inputs: [][]string{ 1654 {"lg-p", "wp"}, 1655 }, 1656 err: `no relations found`, 1657 }, { 1658 summary: "container scoped relations between 2 subordinates is ok", 1659 inputs: [][]string{{"lg:logging-directory", "lg2:logging-client"}}, 1660 eps: []state.Endpoint{{ 1661 ApplicationName: "lg", 1662 Relation: charm.Relation{ 1663 Name: "logging-directory", 1664 Role: "requirer", 1665 Interface: "logging", 1666 Limit: 1, 1667 Scope: charm.ScopeContainer, 1668 }}, { 1669 ApplicationName: "lg2", 1670 Relation: charm.Relation{ 1671 Name: "logging-client", 1672 Role: "provider", 1673 Interface: "logging", 1674 Limit: 0, 1675 Scope: charm.ScopeGlobal, 1676 }}, 1677 }, 1678 }, 1679 { 1680 summary: "valid peer relation", 1681 inputs: [][]string{ 1682 {"rk1"}, 1683 {"rk1:ring"}, 1684 }, 1685 eps: []state.Endpoint{{ 1686 ApplicationName: "rk1", 1687 Relation: charm.Relation{ 1688 Name: "ring", 1689 Interface: "riak", 1690 Limit: 1, 1691 Role: charm.RolePeer, 1692 Scope: charm.ScopeGlobal, 1693 }, 1694 }}, 1695 }, { 1696 summary: "ambiguous provider/requirer relation", 1697 inputs: [][]string{ 1698 {"ms", "wp"}, 1699 {"ms", "wp:db"}, 1700 }, 1701 err: `ambiguous relation: ".*" could refer to "wp:db ms:dev"; "wp:db ms:prod"`, 1702 }, { 1703 summary: "unambiguous provider/requirer relation", 1704 inputs: [][]string{ 1705 {"ms:dev", "wp"}, 1706 {"ms:dev", "wp:db"}, 1707 }, 1708 eps: []state.Endpoint{{ 1709 ApplicationName: "ms", 1710 Relation: charm.Relation{ 1711 Interface: "mysql", 1712 Name: "dev", 1713 Role: charm.RoleProvider, 1714 Scope: charm.ScopeGlobal, 1715 Limit: 2, 1716 }, 1717 }, { 1718 ApplicationName: "wp", 1719 Relation: charm.Relation{ 1720 Interface: "mysql", 1721 Name: "db", 1722 Role: charm.RoleRequirer, 1723 Scope: charm.ScopeGlobal, 1724 Limit: 1, 1725 }, 1726 }}, 1727 }, { 1728 summary: "explicit logging relation is preferred over implicit juju-info", 1729 inputs: [][]string{{"lg", "wp"}}, 1730 eps: []state.Endpoint{{ 1731 ApplicationName: "lg", 1732 Relation: charm.Relation{ 1733 Interface: "logging", 1734 Name: "logging-directory", 1735 Role: charm.RoleRequirer, 1736 Scope: charm.ScopeContainer, 1737 Limit: 1, 1738 }, 1739 }, { 1740 ApplicationName: "wp", 1741 Relation: charm.Relation{ 1742 Interface: "logging", 1743 Name: "logging-dir", 1744 Role: charm.RoleProvider, 1745 Scope: charm.ScopeContainer, 1746 }, 1747 }}, 1748 }, { 1749 summary: "implict relations can be chosen explicitly", 1750 inputs: [][]string{ 1751 {"lg:info", "wp"}, 1752 {"lg", "wp:juju-info"}, 1753 {"lg:info", "wp:juju-info"}, 1754 }, 1755 eps: []state.Endpoint{{ 1756 ApplicationName: "lg", 1757 Relation: charm.Relation{ 1758 Interface: "juju-info", 1759 Name: "info", 1760 Role: charm.RoleRequirer, 1761 Scope: charm.ScopeContainer, 1762 Limit: 1, 1763 }, 1764 }, { 1765 ApplicationName: "wp", 1766 Relation: charm.Relation{ 1767 Interface: "juju-info", 1768 Name: "juju-info", 1769 Role: charm.RoleProvider, 1770 Scope: charm.ScopeGlobal, 1771 }, 1772 }}, 1773 }, { 1774 summary: "implicit relations will be chosen if there are no other options", 1775 inputs: [][]string{{"lg", "ms"}}, 1776 eps: []state.Endpoint{{ 1777 ApplicationName: "lg", 1778 Relation: charm.Relation{ 1779 Interface: "juju-info", 1780 Name: "info", 1781 Role: charm.RoleRequirer, 1782 Scope: charm.ScopeContainer, 1783 Limit: 1, 1784 }, 1785 }, { 1786 ApplicationName: "ms", 1787 Relation: charm.Relation{ 1788 Interface: "juju-info", 1789 Name: "juju-info", 1790 Role: charm.RoleProvider, 1791 Scope: charm.ScopeGlobal, 1792 }, 1793 }}, 1794 }, 1795 } 1796 1797 func (s *StateSuite) TestInferEndpoints(c *gc.C) { 1798 s.AddTestingService(c, "ms", s.AddTestingCharm(c, "mysql-alternative")) 1799 s.AddTestingService(c, "wp", s.AddTestingCharm(c, "wordpress")) 1800 loggingCh := s.AddTestingCharm(c, "logging") 1801 s.AddTestingService(c, "lg", loggingCh) 1802 s.AddTestingService(c, "lg2", loggingCh) 1803 riak := s.AddTestingCharm(c, "riak") 1804 s.AddTestingService(c, "rk1", riak) 1805 s.AddTestingService(c, "rk2", riak) 1806 s.AddTestingService(c, "lg-p", s.AddTestingCharm(c, "logging-principal")) 1807 1808 for i, t := range inferEndpointsTests { 1809 c.Logf("test %d: %s", i, t.summary) 1810 for j, input := range t.inputs { 1811 c.Logf(" input %d: %+v", j, input) 1812 eps, err := s.State.InferEndpoints(input...) 1813 if t.err == "" { 1814 c.Assert(err, jc.ErrorIsNil) 1815 c.Assert(eps, gc.DeepEquals, t.eps) 1816 } else { 1817 c.Assert(err, gc.ErrorMatches, t.err) 1818 } 1819 } 1820 } 1821 } 1822 1823 func (s *StateSuite) TestModelConstraints(c *gc.C) { 1824 // Environ constraints start out empty (for now). 1825 cons, err := s.State.ModelConstraints() 1826 c.Assert(err, jc.ErrorIsNil) 1827 c.Assert(&cons, jc.Satisfies, constraints.IsEmpty) 1828 1829 // Environ constraints can be set. 1830 cons2 := constraints.Value{Mem: uint64p(1024)} 1831 err = s.State.SetModelConstraints(cons2) 1832 c.Assert(err, jc.ErrorIsNil) 1833 cons3, err := s.State.ModelConstraints() 1834 c.Assert(err, jc.ErrorIsNil) 1835 c.Assert(cons3, gc.DeepEquals, cons2) 1836 1837 // Environ constraints are completely overwritten when re-set. 1838 cons4 := constraints.Value{CpuPower: uint64p(250)} 1839 err = s.State.SetModelConstraints(cons4) 1840 c.Assert(err, jc.ErrorIsNil) 1841 cons5, err := s.State.ModelConstraints() 1842 c.Assert(err, jc.ErrorIsNil) 1843 c.Assert(cons5, gc.DeepEquals, cons4) 1844 } 1845 1846 func (s *StateSuite) TestSetInvalidConstraints(c *gc.C) { 1847 cons := constraints.MustParse("mem=4G instance-type=foo") 1848 err := s.State.SetModelConstraints(cons) 1849 c.Assert(err, gc.ErrorMatches, `ambiguous constraints: "instance-type" overlaps with "mem"`) 1850 } 1851 1852 func (s *StateSuite) TestSetUnsupportedConstraintsWarning(c *gc.C) { 1853 defer loggo.ResetWriters() 1854 logger := loggo.GetLogger("test") 1855 logger.SetLogLevel(loggo.DEBUG) 1856 tw := &loggo.TestWriter{} 1857 c.Assert(loggo.RegisterWriter("constraints-tester", tw), gc.IsNil) 1858 1859 cons := constraints.MustParse("mem=4G cpu-power=10") 1860 err := s.State.SetModelConstraints(cons) 1861 c.Assert(err, jc.ErrorIsNil) 1862 c.Assert(tw.Log(), jc.LogMatches, jc.SimpleMessages{{ 1863 loggo.WARNING, 1864 `setting model constraints: unsupported constraints: cpu-power`}, 1865 }) 1866 econs, err := s.State.ModelConstraints() 1867 c.Assert(err, jc.ErrorIsNil) 1868 c.Assert(econs, gc.DeepEquals, cons) 1869 } 1870 1871 func (s *StateSuite) TestWatchModelsBulkEvents(c *gc.C) { 1872 // Alive model... 1873 alive, err := s.State.Model() 1874 c.Assert(err, jc.ErrorIsNil) 1875 1876 // Dying model... 1877 st1 := s.Factory.MakeModel(c, nil) 1878 defer st1.Close() 1879 // Add a service so Destroy doesn't advance to Dead. 1880 svc := factory.NewFactory(st1).MakeApplication(c, nil) 1881 dying, err := st1.Model() 1882 c.Assert(err, jc.ErrorIsNil) 1883 err = dying.Destroy() 1884 c.Assert(err, jc.ErrorIsNil) 1885 1886 // Add an empty model, destroy and remove it; we should 1887 // never see it reported. 1888 st2 := s.Factory.MakeModel(c, nil) 1889 defer st2.Close() 1890 env2, err := st2.Model() 1891 c.Assert(err, jc.ErrorIsNil) 1892 c.Assert(env2.Destroy(), jc.ErrorIsNil) 1893 err = st2.RemoveAllModelDocs() 1894 c.Assert(err, jc.ErrorIsNil) 1895 1896 // All except the removed env are reported in initial event. 1897 w := s.State.WatchModels() 1898 defer statetesting.AssertStop(c, w) 1899 wc := statetesting.NewStringsWatcherC(c, s.State, w) 1900 wc.AssertChangeInSingleEvent(alive.UUID(), dying.UUID()) 1901 1902 // Progress dying to dead, alive to dying; and see changes reported. 1903 err = svc.Destroy() 1904 c.Assert(err, jc.ErrorIsNil) 1905 err = st1.ProcessDyingModel() 1906 c.Assert(err, jc.ErrorIsNil) 1907 err = alive.Destroy() 1908 c.Assert(err, jc.ErrorIsNil) 1909 wc.AssertChangeInSingleEvent(alive.UUID(), dying.UUID()) 1910 } 1911 1912 func (s *StateSuite) TestWatchModelsLifecycle(c *gc.C) { 1913 // Initial event reports the controller model. 1914 w := s.State.WatchModels() 1915 defer statetesting.AssertStop(c, w) 1916 wc := statetesting.NewStringsWatcherC(c, s.State, w) 1917 wc.AssertChange(s.State.ModelUUID()) 1918 wc.AssertNoChange() 1919 1920 // Add a non-empty model: reported. 1921 st1 := s.Factory.MakeModel(c, nil) 1922 defer st1.Close() 1923 svc := factory.NewFactory(st1).MakeApplication(c, nil) 1924 env, err := st1.Model() 1925 c.Assert(err, jc.ErrorIsNil) 1926 wc.AssertChange(env.UUID()) 1927 wc.AssertNoChange() 1928 1929 // Make it Dying: reported. 1930 err = env.Destroy() 1931 c.Assert(err, jc.ErrorIsNil) 1932 wc.AssertChange(env.UUID()) 1933 wc.AssertNoChange() 1934 1935 // Remove the model: reported. 1936 err = svc.Destroy() 1937 c.Assert(err, jc.ErrorIsNil) 1938 err = st1.ProcessDyingModel() 1939 c.Assert(err, jc.ErrorIsNil) 1940 err = st1.RemoveAllModelDocs() 1941 c.Assert(err, jc.ErrorIsNil) 1942 wc.AssertChange(env.UUID()) 1943 wc.AssertNoChange() 1944 } 1945 1946 func (s *StateSuite) TestWatchServicesBulkEvents(c *gc.C) { 1947 // Alive service... 1948 dummyCharm := s.AddTestingCharm(c, "dummy") 1949 alive := s.AddTestingService(c, "service0", dummyCharm) 1950 1951 // Dying service... 1952 dying := s.AddTestingService(c, "service1", dummyCharm) 1953 keepDying, err := dying.AddUnit() 1954 c.Assert(err, jc.ErrorIsNil) 1955 err = dying.Destroy() 1956 c.Assert(err, jc.ErrorIsNil) 1957 1958 // Dead service (actually, gone, Dead == removed in this case). 1959 gone := s.AddTestingService(c, "service2", dummyCharm) 1960 err = gone.Destroy() 1961 c.Assert(err, jc.ErrorIsNil) 1962 1963 // All except gone are reported in initial event. 1964 w := s.State.WatchServices() 1965 defer statetesting.AssertStop(c, w) 1966 wc := statetesting.NewStringsWatcherC(c, s.State, w) 1967 wc.AssertChange(alive.Name(), dying.Name()) 1968 wc.AssertNoChange() 1969 1970 // Remove them all; alive/dying changes reported. 1971 err = alive.Destroy() 1972 c.Assert(err, jc.ErrorIsNil) 1973 err = keepDying.Destroy() 1974 c.Assert(err, jc.ErrorIsNil) 1975 wc.AssertChange(alive.Name(), dying.Name()) 1976 wc.AssertNoChange() 1977 } 1978 1979 func (s *StateSuite) TestWatchServicesLifecycle(c *gc.C) { 1980 // Initial event is empty when no services. 1981 w := s.State.WatchServices() 1982 defer statetesting.AssertStop(c, w) 1983 wc := statetesting.NewStringsWatcherC(c, s.State, w) 1984 wc.AssertChange() 1985 wc.AssertNoChange() 1986 1987 // Add a service: reported. 1988 service := s.AddTestingService(c, "application", s.AddTestingCharm(c, "dummy")) 1989 wc.AssertChange("application") 1990 wc.AssertNoChange() 1991 1992 // Change the service: not reported. 1993 keepDying, err := service.AddUnit() 1994 c.Assert(err, jc.ErrorIsNil) 1995 wc.AssertNoChange() 1996 1997 // Make it Dying: reported. 1998 err = service.Destroy() 1999 c.Assert(err, jc.ErrorIsNil) 2000 wc.AssertChange("application") 2001 wc.AssertNoChange() 2002 2003 // Make it Dead(/removed): reported. 2004 err = keepDying.Destroy() 2005 c.Assert(err, jc.ErrorIsNil) 2006 wc.AssertChange("application") 2007 wc.AssertNoChange() 2008 } 2009 2010 func (s *StateSuite) TestWatchServicesDiesOnStateClose(c *gc.C) { 2011 // This test is testing logic in watcher.lifecycleWatcher, 2012 // which is also used by: 2013 // State.WatchModels 2014 // Service.WatchUnits 2015 // Service.WatchRelations 2016 // State.WatchEnviron 2017 // Machine.WatchContainers 2018 testWatcherDiesWhenStateCloses(c, s.modelTag, s.State.ControllerTag(), func(c *gc.C, st *state.State) waiter { 2019 w := st.WatchServices() 2020 <-w.Changes() 2021 return w 2022 }) 2023 } 2024 2025 func (s *StateSuite) TestWatchMachinesBulkEvents(c *gc.C) { 2026 // Alive machine... 2027 alive, err := s.State.AddMachine("quantal", state.JobHostUnits) 2028 c.Assert(err, jc.ErrorIsNil) 2029 2030 // Dying machine... 2031 dying, err := s.State.AddMachine("quantal", state.JobHostUnits) 2032 c.Assert(err, jc.ErrorIsNil) 2033 err = dying.SetProvisioned(instance.Id("i-blah"), "fake-nonce", nil) 2034 c.Assert(err, jc.ErrorIsNil) 2035 err = dying.Destroy() 2036 c.Assert(err, jc.ErrorIsNil) 2037 2038 // Dead machine... 2039 dead, err := s.State.AddMachine("quantal", state.JobHostUnits) 2040 c.Assert(err, jc.ErrorIsNil) 2041 err = dead.EnsureDead() 2042 c.Assert(err, jc.ErrorIsNil) 2043 2044 // Gone machine. 2045 gone, err := s.State.AddMachine("quantal", state.JobHostUnits) 2046 c.Assert(err, jc.ErrorIsNil) 2047 err = gone.EnsureDead() 2048 c.Assert(err, jc.ErrorIsNil) 2049 err = gone.Remove() 2050 c.Assert(err, jc.ErrorIsNil) 2051 2052 // All except gone machine are reported in initial event. 2053 w := s.State.WatchModelMachines() 2054 defer statetesting.AssertStop(c, w) 2055 wc := statetesting.NewStringsWatcherC(c, s.State, w) 2056 wc.AssertChange(alive.Id(), dying.Id(), dead.Id()) 2057 wc.AssertNoChange() 2058 2059 // Remove them all; alive/dying changes reported; dead never mentioned again. 2060 err = alive.Destroy() 2061 c.Assert(err, jc.ErrorIsNil) 2062 err = dying.EnsureDead() 2063 c.Assert(err, jc.ErrorIsNil) 2064 err = dying.Remove() 2065 c.Assert(err, jc.ErrorIsNil) 2066 err = dead.Remove() 2067 c.Assert(err, jc.ErrorIsNil) 2068 wc.AssertChange(alive.Id(), dying.Id()) 2069 wc.AssertNoChange() 2070 } 2071 2072 func (s *StateSuite) TestWatchMachinesLifecycle(c *gc.C) { 2073 // Initial event is empty when no machines. 2074 w := s.State.WatchModelMachines() 2075 defer statetesting.AssertStop(c, w) 2076 wc := statetesting.NewStringsWatcherC(c, s.State, w) 2077 wc.AssertChange() 2078 wc.AssertNoChange() 2079 2080 // Add a machine: reported. 2081 machine, err := s.State.AddMachine("quantal", state.JobHostUnits) 2082 c.Assert(err, jc.ErrorIsNil) 2083 wc.AssertChange("0") 2084 wc.AssertNoChange() 2085 2086 // Change the machine: not reported. 2087 err = machine.SetProvisioned(instance.Id("i-blah"), "fake-nonce", nil) 2088 c.Assert(err, jc.ErrorIsNil) 2089 wc.AssertNoChange() 2090 2091 // Make it Dying: reported. 2092 err = machine.Destroy() 2093 c.Assert(err, jc.ErrorIsNil) 2094 wc.AssertChange("0") 2095 wc.AssertNoChange() 2096 2097 // Make it Dead: reported. 2098 err = machine.EnsureDead() 2099 c.Assert(err, jc.ErrorIsNil) 2100 wc.AssertChange("0") 2101 wc.AssertNoChange() 2102 2103 // Remove it: not reported. 2104 err = machine.Remove() 2105 c.Assert(err, jc.ErrorIsNil) 2106 wc.AssertNoChange() 2107 } 2108 2109 func (s *StateSuite) TestWatchMachinesIncludesOldMachines(c *gc.C) { 2110 // Older versions of juju do not write the "containertype" field. 2111 // This has caused machines to not be detected in the initial event. 2112 machine, err := s.State.AddMachine("quantal", state.JobHostUnits) 2113 c.Assert(err, jc.ErrorIsNil) 2114 err = s.machines.Update( 2115 bson.D{{"_id", state.DocID(s.State, machine.Id())}}, 2116 bson.D{{"$unset", bson.D{{"containertype", 1}}}}, 2117 ) 2118 c.Assert(err, jc.ErrorIsNil) 2119 2120 w := s.State.WatchModelMachines() 2121 defer statetesting.AssertStop(c, w) 2122 wc := statetesting.NewStringsWatcherC(c, s.State, w) 2123 wc.AssertChange(machine.Id()) 2124 wc.AssertNoChange() 2125 } 2126 2127 func (s *StateSuite) TestWatchMachinesIgnoresContainers(c *gc.C) { 2128 // Initial event is empty when no machines. 2129 w := s.State.WatchModelMachines() 2130 defer statetesting.AssertStop(c, w) 2131 wc := statetesting.NewStringsWatcherC(c, s.State, w) 2132 wc.AssertChange() 2133 wc.AssertNoChange() 2134 2135 // Add a machine: reported. 2136 template := state.MachineTemplate{ 2137 Series: "quantal", 2138 Jobs: []state.MachineJob{state.JobHostUnits}, 2139 } 2140 machines, err := s.State.AddMachines(template) 2141 c.Assert(err, jc.ErrorIsNil) 2142 c.Assert(machines, gc.HasLen, 1) 2143 machine := machines[0] 2144 wc.AssertChange("0") 2145 wc.AssertNoChange() 2146 2147 // Add a container: not reported. 2148 m, err := s.State.AddMachineInsideMachine(template, machine.Id(), instance.LXD) 2149 c.Assert(err, jc.ErrorIsNil) 2150 wc.AssertNoChange() 2151 2152 // Make the container Dying: not reported. 2153 err = m.Destroy() 2154 c.Assert(err, jc.ErrorIsNil) 2155 wc.AssertNoChange() 2156 2157 // Make the container Dead: not reported. 2158 err = m.EnsureDead() 2159 c.Assert(err, jc.ErrorIsNil) 2160 wc.AssertNoChange() 2161 2162 // Remove the container: not reported. 2163 err = m.Remove() 2164 c.Assert(err, jc.ErrorIsNil) 2165 wc.AssertNoChange() 2166 } 2167 2168 func (s *StateSuite) TestWatchContainerLifecycle(c *gc.C) { 2169 // Add a host machine. 2170 template := state.MachineTemplate{ 2171 Series: "quantal", 2172 Jobs: []state.MachineJob{state.JobHostUnits}, 2173 } 2174 machine, err := s.State.AddOneMachine(template) 2175 c.Assert(err, jc.ErrorIsNil) 2176 2177 otherMachine, err := s.State.AddOneMachine(template) 2178 c.Assert(err, jc.ErrorIsNil) 2179 2180 // Initial event is empty when no containers. 2181 w := machine.WatchContainers(instance.LXD) 2182 defer statetesting.AssertStop(c, w) 2183 wAll := machine.WatchAllContainers() 2184 defer statetesting.AssertStop(c, wAll) 2185 2186 wc := statetesting.NewStringsWatcherC(c, s.State, w) 2187 wc.AssertChange() 2188 wc.AssertNoChange() 2189 2190 wcAll := statetesting.NewStringsWatcherC(c, s.State, wAll) 2191 wcAll.AssertChange() 2192 wcAll.AssertNoChange() 2193 2194 // Add a container of the required type: reported. 2195 m, err := s.State.AddMachineInsideMachine(template, machine.Id(), instance.LXD) 2196 c.Assert(err, jc.ErrorIsNil) 2197 wc.AssertChange("0/lxd/0") 2198 wc.AssertNoChange() 2199 wcAll.AssertChange("0/lxd/0") 2200 wcAll.AssertNoChange() 2201 2202 // Add a container of a different type: not reported. 2203 m1, err := s.State.AddMachineInsideMachine(template, machine.Id(), instance.KVM) 2204 c.Assert(err, jc.ErrorIsNil) 2205 wc.AssertNoChange() 2206 // But reported by the all watcher. 2207 wcAll.AssertChange("0/kvm/0") 2208 wcAll.AssertNoChange() 2209 2210 // Add a nested container of the right type: not reported. 2211 mchild, err := s.State.AddMachineInsideMachine(template, m.Id(), instance.LXD) 2212 c.Assert(err, jc.ErrorIsNil) 2213 wc.AssertNoChange() 2214 wcAll.AssertNoChange() 2215 2216 // Add a container of a different machine: not reported. 2217 m2, err := s.State.AddMachineInsideMachine(template, otherMachine.Id(), instance.LXD) 2218 c.Assert(err, jc.ErrorIsNil) 2219 wc.AssertNoChange() 2220 statetesting.AssertStop(c, w) 2221 wcAll.AssertNoChange() 2222 statetesting.AssertStop(c, wAll) 2223 2224 w = machine.WatchContainers(instance.LXD) 2225 defer statetesting.AssertStop(c, w) 2226 wc = statetesting.NewStringsWatcherC(c, s.State, w) 2227 wAll = machine.WatchAllContainers() 2228 defer statetesting.AssertStop(c, wAll) 2229 wcAll = statetesting.NewStringsWatcherC(c, s.State, wAll) 2230 wc.AssertChange("0/lxd/0") 2231 wc.AssertNoChange() 2232 wcAll.AssertChange("0/kvm/0", "0/lxd/0") 2233 wcAll.AssertNoChange() 2234 2235 // Make the container Dying: cannot because of nested container. 2236 err = m.Destroy() 2237 c.Assert(err, gc.ErrorMatches, `machine .* is hosting containers ".*"`) 2238 2239 err = mchild.EnsureDead() 2240 c.Assert(err, jc.ErrorIsNil) 2241 err = mchild.Remove() 2242 c.Assert(err, jc.ErrorIsNil) 2243 2244 // Make the container Dying: reported. 2245 err = m.Destroy() 2246 c.Assert(err, jc.ErrorIsNil) 2247 wc.AssertChange("0/lxd/0") 2248 wc.AssertNoChange() 2249 wcAll.AssertChange("0/lxd/0") 2250 wcAll.AssertNoChange() 2251 2252 // Make the other containers Dying: not reported. 2253 err = m1.Destroy() 2254 c.Assert(err, jc.ErrorIsNil) 2255 err = m2.Destroy() 2256 c.Assert(err, jc.ErrorIsNil) 2257 wc.AssertNoChange() 2258 // But reported by the all watcher. 2259 wcAll.AssertChange("0/kvm/0") 2260 wcAll.AssertNoChange() 2261 2262 // Make the container Dead: reported. 2263 err = m.EnsureDead() 2264 c.Assert(err, jc.ErrorIsNil) 2265 wc.AssertChange("0/lxd/0") 2266 wc.AssertNoChange() 2267 wcAll.AssertChange("0/lxd/0") 2268 wcAll.AssertNoChange() 2269 2270 // Make the other containers Dead: not reported. 2271 err = m1.EnsureDead() 2272 c.Assert(err, jc.ErrorIsNil) 2273 err = m2.EnsureDead() 2274 c.Assert(err, jc.ErrorIsNil) 2275 wc.AssertNoChange() 2276 // But reported by the all watcher. 2277 wcAll.AssertChange("0/kvm/0") 2278 wcAll.AssertNoChange() 2279 2280 // Remove the container: not reported. 2281 err = m.Remove() 2282 c.Assert(err, jc.ErrorIsNil) 2283 wc.AssertNoChange() 2284 wcAll.AssertNoChange() 2285 } 2286 2287 func (s *StateSuite) TestWatchMachineHardwareCharacteristics(c *gc.C) { 2288 // Add a machine: reported. 2289 machine, err := s.State.AddMachine("quantal", state.JobHostUnits) 2290 c.Assert(err, jc.ErrorIsNil) 2291 w := machine.WatchHardwareCharacteristics() 2292 defer statetesting.AssertStop(c, w) 2293 2294 // Initial event. 2295 wc := statetesting.NewNotifyWatcherC(c, s.State, w) 2296 wc.AssertOneChange() 2297 2298 // Provision a machine: reported. 2299 err = machine.SetProvisioned(instance.Id("i-blah"), "fake-nonce", nil) 2300 c.Assert(err, jc.ErrorIsNil) 2301 wc.AssertOneChange() 2302 2303 // Alter the machine: not reported. 2304 vers := version.MustParseBinary("1.2.3-quantal-ppc") 2305 err = machine.SetAgentVersion(vers) 2306 c.Assert(err, jc.ErrorIsNil) 2307 wc.AssertNoChange() 2308 } 2309 2310 func (s *StateSuite) TestWatchControllerInfo(c *gc.C) { 2311 _, err := s.State.AddMachine("quantal", state.JobManageModel) 2312 c.Assert(err, jc.ErrorIsNil) 2313 2314 w := s.State.WatchControllerInfo() 2315 defer statetesting.AssertStop(c, w) 2316 2317 // Initial event. 2318 wc := statetesting.NewNotifyWatcherC(c, s.State, w) 2319 wc.AssertOneChange() 2320 2321 info, err := s.State.ControllerInfo() 2322 c.Assert(err, jc.ErrorIsNil) 2323 c.Assert(info, jc.DeepEquals, &state.ControllerInfo{ 2324 CloudName: "dummy", 2325 ModelTag: s.modelTag, 2326 MachineIds: []string{"0"}, 2327 VotingMachineIds: []string{"0"}, 2328 }) 2329 2330 s.PatchValue(state.ControllerAvailable, func(m *state.Machine) (bool, error) { 2331 return true, nil 2332 }) 2333 2334 changes, err := s.State.EnableHA(3, constraints.Value{}, "quantal", nil) 2335 c.Assert(err, jc.ErrorIsNil) 2336 c.Assert(changes.Added, gc.HasLen, 2) 2337 2338 wc.AssertOneChange() 2339 2340 info, err = s.State.ControllerInfo() 2341 c.Assert(err, jc.ErrorIsNil) 2342 c.Assert(info, jc.DeepEquals, &state.ControllerInfo{ 2343 CloudName: "dummy", 2344 ModelTag: s.modelTag, 2345 MachineIds: []string{"0", "1", "2"}, 2346 VotingMachineIds: []string{"0", "1", "2"}, 2347 }) 2348 } 2349 2350 func (s *StateSuite) insertFakeModelDocs(c *gc.C, st *state.State) string { 2351 // insert one doc for each multiEnvCollection 2352 var ops []mgotxn.Op 2353 modelUUID := st.ModelUUID() 2354 for _, collName := range state.MultiEnvCollections() { 2355 // skip adding constraints, modelUser and settings as they were added when the 2356 // model was created 2357 if collName == "constraints" || collName == "modelusers" || collName == "settings" { 2358 continue 2359 } 2360 if state.HasRawAccess(collName) { 2361 coll, closer := state.GetRawCollection(st, collName) 2362 defer closer() 2363 2364 err := coll.Insert(bson.M{ 2365 "_id": state.DocID(st, "arbitraryid"), 2366 "model-uuid": modelUUID, 2367 }) 2368 c.Assert(err, jc.ErrorIsNil) 2369 } else { 2370 ops = append(ops, mgotxn.Op{ 2371 C: collName, 2372 Id: state.DocID(st, "arbitraryid"), 2373 Insert: bson.M{"model-uuid": modelUUID}, 2374 }) 2375 } 2376 } 2377 2378 err := state.RunTransaction(st, ops) 2379 c.Assert(err, jc.ErrorIsNil) 2380 2381 // test that we can find each doc in state 2382 for _, collName := range state.MultiEnvCollections() { 2383 coll, closer := state.GetRawCollection(st, collName) 2384 defer closer() 2385 n, err := coll.Find(bson.D{{"model-uuid", st.ModelUUID()}}).Count() 2386 c.Assert(err, jc.ErrorIsNil) 2387 c.Assert(n, gc.Not(gc.Equals), 0) 2388 } 2389 2390 model, err := st.Model() 2391 c.Assert(err, jc.ErrorIsNil) 2392 2393 // Add a model user whose permissions should get removed 2394 // when the model is. 2395 _, err = s.State.AddModelUser( 2396 s.State.ModelUUID(), 2397 state.UserAccessSpec{ 2398 User: names.NewUserTag("amelia@external"), 2399 CreatedBy: s.Owner, 2400 Access: permission.ReadAccess, 2401 }) 2402 c.Assert(err, jc.ErrorIsNil) 2403 2404 return state.UserModelNameIndex(model.Owner().Canonical(), model.Name()) 2405 } 2406 2407 type checkUserModelNameArgs struct { 2408 st *state.State 2409 id string 2410 exists bool 2411 } 2412 2413 func (s *StateSuite) checkUserModelNameExists(c *gc.C, args checkUserModelNameArgs) { 2414 indexColl, closer := state.GetCollection(args.st, "usermodelname") 2415 defer closer() 2416 n, err := indexColl.FindId(args.id).Count() 2417 c.Assert(err, jc.ErrorIsNil) 2418 if args.exists { 2419 c.Assert(n, gc.Equals, 1) 2420 } else { 2421 c.Assert(n, gc.Equals, 0) 2422 } 2423 } 2424 2425 func (s *StateSuite) AssertModelDeleted(c *gc.C, st *state.State) { 2426 // check to see if the model itself is gone 2427 _, err := st.Model() 2428 c.Assert(err, gc.ErrorMatches, `model not found`) 2429 2430 // ensure all docs for all multiEnvCollections are removed 2431 for _, collName := range state.MultiEnvCollections() { 2432 coll, closer := state.GetRawCollection(st, collName) 2433 defer closer() 2434 n, err := coll.Find(bson.D{{"model-uuid", st.ModelUUID()}}).Count() 2435 c.Assert(err, jc.ErrorIsNil) 2436 c.Assert(n, gc.Equals, 0) 2437 } 2438 2439 // ensure user permissions for the model are removed 2440 permPattern := fmt.Sprintf("^%s#%s#", state.ModelGlobalKey, st.ModelUUID()) 2441 permissions, closer := state.GetCollection(st, "permissions") 2442 defer closer() 2443 permCount, err := permissions.Find(bson.M{"_id": bson.M{"$regex": permPattern}}).Count() 2444 c.Assert(err, jc.ErrorIsNil) 2445 c.Check(permCount, gc.Equals, 0) 2446 } 2447 2448 func (s *StateSuite) TestRemoveAllModelDocs(c *gc.C) { 2449 st := s.Factory.MakeModel(c, nil) 2450 defer st.Close() 2451 2452 userModelKey := s.insertFakeModelDocs(c, st) 2453 s.checkUserModelNameExists(c, checkUserModelNameArgs{st: st, id: userModelKey, exists: true}) 2454 2455 err := state.SetModelLifeDead(st, st.ModelUUID()) 2456 c.Assert(err, jc.ErrorIsNil) 2457 2458 err = st.RemoveAllModelDocs() 2459 c.Assert(err, jc.ErrorIsNil) 2460 2461 // test that we can not find the user:envName unique index 2462 s.checkUserModelNameExists(c, checkUserModelNameArgs{st: st, id: userModelKey, exists: false}) 2463 s.AssertModelDeleted(c, st) 2464 } 2465 2466 func (s *StateSuite) TestRemoveAllModelDocsAliveEnvFails(c *gc.C) { 2467 st := s.Factory.MakeModel(c, nil) 2468 defer st.Close() 2469 2470 err := st.RemoveAllModelDocs() 2471 c.Assert(err, gc.ErrorMatches, "can't remove model: model not dead") 2472 } 2473 2474 func (s *StateSuite) TestRemoveImportingModelDocsFailsActive(c *gc.C) { 2475 st := s.Factory.MakeModel(c, nil) 2476 defer st.Close() 2477 2478 err := st.RemoveImportingModelDocs() 2479 c.Assert(err, gc.ErrorMatches, "can't remove model: model not being imported for migration") 2480 } 2481 2482 func (s *StateSuite) TestRemoveImportingModelDocsFailsExporting(c *gc.C) { 2483 st := s.Factory.MakeModel(c, nil) 2484 defer st.Close() 2485 model, err := st.Model() 2486 c.Assert(err, jc.ErrorIsNil) 2487 err = model.SetMigrationMode(state.MigrationModeExporting) 2488 c.Assert(err, jc.ErrorIsNil) 2489 2490 err = st.RemoveImportingModelDocs() 2491 c.Assert(err, gc.ErrorMatches, "can't remove model: model not being imported for migration") 2492 } 2493 2494 func (s *StateSuite) TestRemoveImportingModelDocsImporting(c *gc.C) { 2495 st := s.Factory.MakeModel(c, nil) 2496 defer st.Close() 2497 userModelKey := s.insertFakeModelDocs(c, st) 2498 c.Assert(state.HostedModelCount(c, s.State), gc.Equals, 1) 2499 2500 model, err := st.Model() 2501 c.Assert(err, jc.ErrorIsNil) 2502 err = model.SetMigrationMode(state.MigrationModeImporting) 2503 c.Assert(err, jc.ErrorIsNil) 2504 2505 err = st.RemoveImportingModelDocs() 2506 c.Assert(err, jc.ErrorIsNil) 2507 2508 // test that we can not find the user:envName unique index 2509 s.checkUserModelNameExists(c, checkUserModelNameArgs{st: st, id: userModelKey, exists: false}) 2510 s.AssertModelDeleted(c, st) 2511 c.Assert(state.HostedModelCount(c, s.State), gc.Equals, 0) 2512 } 2513 2514 func (s *StateSuite) TestRemoveExportingModelDocsFailsActive(c *gc.C) { 2515 st := s.Factory.MakeModel(c, nil) 2516 defer st.Close() 2517 2518 err := st.RemoveExportingModelDocs() 2519 c.Assert(err, gc.ErrorMatches, "can't remove model: model not being exported for migration") 2520 } 2521 2522 func (s *StateSuite) TestRemoveExportingModelDocsFailsImporting(c *gc.C) { 2523 st := s.Factory.MakeModel(c, nil) 2524 defer st.Close() 2525 model, err := st.Model() 2526 c.Assert(err, jc.ErrorIsNil) 2527 err = model.SetMigrationMode(state.MigrationModeImporting) 2528 c.Assert(err, jc.ErrorIsNil) 2529 2530 err = st.RemoveExportingModelDocs() 2531 c.Assert(err, gc.ErrorMatches, "can't remove model: model not being exported for migration") 2532 } 2533 2534 func (s *StateSuite) TestRemoveExportingModelDocsExporting(c *gc.C) { 2535 st := s.Factory.MakeModel(c, nil) 2536 defer st.Close() 2537 userModelKey := s.insertFakeModelDocs(c, st) 2538 c.Assert(state.HostedModelCount(c, s.State), gc.Equals, 1) 2539 2540 model, err := st.Model() 2541 c.Assert(err, jc.ErrorIsNil) 2542 err = model.SetMigrationMode(state.MigrationModeExporting) 2543 c.Assert(err, jc.ErrorIsNil) 2544 2545 err = st.RemoveExportingModelDocs() 2546 c.Assert(err, jc.ErrorIsNil) 2547 2548 // test that we can not find the user:envName unique index 2549 s.checkUserModelNameExists(c, checkUserModelNameArgs{st: st, id: userModelKey, exists: false}) 2550 s.AssertModelDeleted(c, st) 2551 c.Assert(state.HostedModelCount(c, s.State), gc.Equals, 0) 2552 } 2553 2554 type attrs map[string]interface{} 2555 2556 func (s *StateSuite) TestWatchForModelConfigChanges(c *gc.C) { 2557 cur := jujuversion.Current 2558 err := statetesting.SetAgentVersion(s.State, cur) 2559 c.Assert(err, jc.ErrorIsNil) 2560 w := s.State.WatchForModelConfigChanges() 2561 defer statetesting.AssertStop(c, w) 2562 2563 wc := statetesting.NewNotifyWatcherC(c, s.State, w) 2564 // Initially we get one change notification 2565 wc.AssertOneChange() 2566 2567 // Multiple changes will only result in a single change notification 2568 newVersion := cur 2569 newVersion.Minor++ 2570 err = statetesting.SetAgentVersion(s.State, newVersion) 2571 c.Assert(err, jc.ErrorIsNil) 2572 2573 newerVersion := newVersion 2574 newerVersion.Minor++ 2575 err = statetesting.SetAgentVersion(s.State, newerVersion) 2576 c.Assert(err, jc.ErrorIsNil) 2577 wc.AssertOneChange() 2578 2579 // Setting it to the same value does not trigger a change notification 2580 err = statetesting.SetAgentVersion(s.State, newerVersion) 2581 c.Assert(err, jc.ErrorIsNil) 2582 wc.AssertNoChange() 2583 } 2584 2585 func (s *StateSuite) TestWatchForModelConfigControllerChanges(c *gc.C) { 2586 w := s.State.WatchForModelConfigChanges() 2587 defer statetesting.AssertStop(c, w) 2588 2589 wc := statetesting.NewNotifyWatcherC(c, s.State, w) 2590 wc.AssertOneChange() 2591 } 2592 2593 func (s *StateSuite) TestAddAndGetEquivalence(c *gc.C) { 2594 // The equivalence tested here isn't necessarily correct, and 2595 // comparing private details is discouraged in the project. 2596 // The implementation might choose to cache information, or 2597 // to have different logic when adding or removing, and the 2598 // comparison might fail despite it being correct. 2599 // That said, we've had bugs with txn-revno being incorrect 2600 // before, so this testing at least ensures we're conscious 2601 // about such changes. 2602 2603 m1, err := s.State.AddMachine("quantal", state.JobHostUnits) 2604 c.Assert(err, jc.ErrorIsNil) 2605 m2, err := s.State.Machine(m1.Id()) 2606 c.Assert(m1, jc.DeepEquals, m2) 2607 2608 charm1 := s.AddTestingCharm(c, "wordpress") 2609 charm2, err := s.State.Charm(charm1.URL()) 2610 c.Assert(err, jc.ErrorIsNil) 2611 c.Assert(charm1, jc.DeepEquals, charm2) 2612 2613 wordpress1 := s.AddTestingService(c, "wordpress", charm1) 2614 wordpress2, err := s.State.Application("wordpress") 2615 c.Assert(err, jc.ErrorIsNil) 2616 c.Assert(wordpress1, jc.DeepEquals, wordpress2) 2617 2618 unit1, err := wordpress1.AddUnit() 2619 c.Assert(err, jc.ErrorIsNil) 2620 unit2, err := s.State.Unit("wordpress/0") 2621 c.Assert(err, jc.ErrorIsNil) 2622 c.Assert(unit1, jc.DeepEquals, unit2) 2623 2624 s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql")) 2625 c.Assert(err, jc.ErrorIsNil) 2626 eps, err := s.State.InferEndpoints("wordpress", "mysql") 2627 c.Assert(err, jc.ErrorIsNil) 2628 relation1, err := s.State.AddRelation(eps...) 2629 c.Assert(err, jc.ErrorIsNil) 2630 relation2, err := s.State.EndpointsRelation(eps...) 2631 c.Assert(relation1, jc.DeepEquals, relation2) 2632 relation3, err := s.State.Relation(relation1.Id()) 2633 c.Assert(relation1, jc.DeepEquals, relation3) 2634 } 2635 2636 func tryOpenState(modelTag names.ModelTag, controllerTag names.ControllerTag, info *mongo.MongoInfo) error { 2637 st, err := state.Open(modelTag, controllerTag, info, mongotest.DialOpts(), nil) 2638 if err == nil { 2639 err = st.Close() 2640 } 2641 return err 2642 } 2643 2644 func (s *StateSuite) TestOpenWithoutSetMongoPassword(c *gc.C) { 2645 info := statetesting.NewMongoInfo() 2646 info.Tag, info.Password = names.NewUserTag("arble"), "bar" 2647 err := tryOpenState(s.modelTag, s.State.ControllerTag(), info) 2648 c.Check(errors.Cause(err), jc.Satisfies, errors.IsUnauthorized) 2649 c.Check(err, gc.ErrorMatches, `cannot log in to admin database as "user-arble": unauthorized mongo access: .*`) 2650 2651 info.Tag, info.Password = names.NewUserTag("arble"), "" 2652 err = tryOpenState(s.modelTag, s.State.ControllerTag(), info) 2653 c.Check(errors.Cause(err), jc.Satisfies, errors.IsUnauthorized) 2654 c.Check(err, gc.ErrorMatches, `cannot log in to admin database as "user-arble": unauthorized mongo access: .*`) 2655 2656 info.Tag, info.Password = nil, "" 2657 err = tryOpenState(s.modelTag, s.State.ControllerTag(), info) 2658 c.Check(err, jc.ErrorIsNil) 2659 } 2660 2661 func (s *StateSuite) TestOpenBadAddress(c *gc.C) { 2662 info := statetesting.NewMongoInfo() 2663 info.Addrs = []string{"0.1.2.3:1234"} 2664 st, err := state.Open(testing.ModelTag, testing.ControllerTag, info, mongo.DialOpts{ 2665 Timeout: 1 * time.Millisecond, 2666 }, nil) 2667 if err == nil { 2668 st.Close() 2669 } 2670 c.Assert(err, gc.ErrorMatches, "cannot connect to mongodb: no reachable servers") 2671 } 2672 2673 func (s *StateSuite) TestOpenDelaysRetryBadAddress(c *gc.C) { 2674 // Default mgo retry delay 2675 retryDelay := 500 * time.Millisecond 2676 info := statetesting.NewMongoInfo() 2677 info.Addrs = []string{"0.1.2.3:1234"} 2678 2679 t0 := time.Now() 2680 st, err := state.Open(testing.ModelTag, testing.ControllerTag, info, mongo.DialOpts{ 2681 Timeout: 1 * time.Millisecond, 2682 }, nil) 2683 if err == nil { 2684 st.Close() 2685 } 2686 c.Assert(err, gc.ErrorMatches, "cannot connect to mongodb: no reachable servers") 2687 // tryOpenState should have delayed for at least retryDelay 2688 if t1 := time.Since(t0); t1 < retryDelay { 2689 c.Errorf("mgo.Dial only paused for %v, expected at least %v", t1, retryDelay) 2690 } 2691 } 2692 2693 func testSetPassword(c *gc.C, getEntity func() (state.Authenticator, error)) { 2694 e, err := getEntity() 2695 c.Assert(err, jc.ErrorIsNil) 2696 2697 c.Assert(e.PasswordValid(goodPassword), jc.IsFalse) 2698 err = e.SetPassword(goodPassword) 2699 c.Assert(err, jc.ErrorIsNil) 2700 c.Assert(e.PasswordValid(goodPassword), jc.IsTrue) 2701 2702 // Check a newly-fetched entity has the same password. 2703 e2, err := getEntity() 2704 c.Assert(err, jc.ErrorIsNil) 2705 c.Assert(e2.PasswordValid(goodPassword), jc.IsTrue) 2706 2707 err = e.SetPassword(alternatePassword) 2708 c.Assert(err, jc.ErrorIsNil) 2709 c.Assert(e.PasswordValid(goodPassword), jc.IsFalse) 2710 c.Assert(e.PasswordValid(alternatePassword), jc.IsTrue) 2711 2712 // Check that refreshing fetches the new password 2713 err = e2.Refresh() 2714 c.Assert(err, jc.ErrorIsNil) 2715 c.Assert(e2.PasswordValid(alternatePassword), jc.IsTrue) 2716 2717 if le, ok := e.(lifer); ok { 2718 testWhenDying(c, le, noErr, deadErr, func() error { 2719 return e.SetPassword("arble-farble-dying-yarble") 2720 }) 2721 } 2722 } 2723 2724 type entity interface { 2725 state.Entity 2726 state.Lifer 2727 state.Authenticator 2728 } 2729 2730 type findEntityTest struct { 2731 tag names.Tag 2732 err string 2733 } 2734 2735 var findEntityTests = []findEntityTest{{ 2736 tag: names.NewRelationTag("svc1:rel1 svc2:rel2"), 2737 err: `relation "svc1:rel1 svc2:rel2" not found`, 2738 }, { 2739 tag: names.NewModelTag("9f484882-2f18-4fd2-967d-db9663db7bea"), 2740 err: `model "9f484882-2f18-4fd2-967d-db9663db7bea" not found`, 2741 }, { 2742 tag: names.NewMachineTag("0"), 2743 }, { 2744 tag: names.NewApplicationTag("ser-vice2"), 2745 }, { 2746 tag: names.NewRelationTag("wordpress:db ser-vice2:server"), 2747 }, { 2748 tag: names.NewUnitTag("ser-vice2/0"), 2749 }, { 2750 tag: names.NewUserTag("arble"), 2751 }, { 2752 tag: names.NewActionTag("fedcba98-7654-4321-ba98-76543210beef"), 2753 err: `action "fedcba98-7654-4321-ba98-76543210beef" not found`, 2754 }, { 2755 tag: names.NewUserTag("eric"), 2756 }, { 2757 tag: names.NewUserTag("eric@local"), 2758 }, { 2759 tag: names.NewUserTag("eric@remote"), 2760 err: `user "eric@remote" not found`, 2761 }} 2762 2763 var entityTypes = map[string]interface{}{ 2764 names.UserTagKind: (*state.User)(nil), 2765 names.ModelTagKind: (*state.Model)(nil), 2766 names.ApplicationTagKind: (*state.Application)(nil), 2767 names.UnitTagKind: (*state.Unit)(nil), 2768 names.MachineTagKind: (*state.Machine)(nil), 2769 names.RelationTagKind: (*state.Relation)(nil), 2770 names.ActionTagKind: (state.Action)(nil), 2771 } 2772 2773 func (s *StateSuite) TestFindEntity(c *gc.C) { 2774 s.Factory.MakeUser(c, &factory.UserParams{Name: "eric"}) 2775 _, err := s.State.AddMachine("quantal", state.JobHostUnits) 2776 c.Assert(err, jc.ErrorIsNil) 2777 svc := s.AddTestingService(c, "ser-vice2", s.AddTestingCharm(c, "mysql")) 2778 unit, err := svc.AddUnit() 2779 c.Assert(err, jc.ErrorIsNil) 2780 _, err = unit.AddAction("fakeaction", nil) 2781 c.Assert(err, jc.ErrorIsNil) 2782 s.Factory.MakeUser(c, &factory.UserParams{Name: "arble"}) 2783 c.Assert(err, jc.ErrorIsNil) 2784 s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress")) 2785 eps, err := s.State.InferEndpoints("wordpress", "ser-vice2") 2786 c.Assert(err, jc.ErrorIsNil) 2787 rel, err := s.State.AddRelation(eps...) 2788 c.Assert(err, jc.ErrorIsNil) 2789 c.Assert(rel.String(), gc.Equals, "wordpress:db ser-vice2:server") 2790 2791 // model tag is dynamically generated 2792 env, err := s.State.Model() 2793 c.Assert(err, jc.ErrorIsNil) 2794 findEntityTests = append([]findEntityTest{}, findEntityTests...) 2795 findEntityTests = append(findEntityTests, findEntityTest{ 2796 tag: names.NewModelTag(env.UUID()), 2797 }) 2798 2799 for i, test := range findEntityTests { 2800 c.Logf("test %d: %q", i, test.tag) 2801 e, err := s.State.FindEntity(test.tag) 2802 if test.err != "" { 2803 c.Assert(err, gc.ErrorMatches, test.err) 2804 } else { 2805 c.Assert(err, jc.ErrorIsNil) 2806 kind := test.tag.Kind() 2807 c.Assert(e, gc.FitsTypeOf, entityTypes[kind]) 2808 if kind == names.ModelTagKind { 2809 // TODO(axw) 2013-12-04 #1257587 2810 // We *should* only be able to get the entity with its tag, but 2811 // for backwards-compatibility we accept any non-UUID tag. 2812 c.Assert(e.Tag(), gc.Equals, env.Tag()) 2813 } else if kind == names.UserTagKind { 2814 // Test the fully qualified username rather than the tag structure itself. 2815 expected := test.tag.(names.UserTag).Canonical() 2816 c.Assert(e.Tag().(names.UserTag).Canonical(), gc.Equals, expected) 2817 } else { 2818 c.Assert(e.Tag(), gc.Equals, test.tag) 2819 } 2820 } 2821 } 2822 } 2823 2824 func (s *StateSuite) TestParseNilTagReturnsAnError(c *gc.C) { 2825 coll, id, err := state.ConvertTagToCollectionNameAndId(s.State, nil) 2826 c.Assert(err, gc.ErrorMatches, "tag is nil") 2827 c.Assert(coll, gc.Equals, "") 2828 c.Assert(id, gc.IsNil) 2829 } 2830 2831 func (s *StateSuite) TestParseMachineTag(c *gc.C) { 2832 m, err := s.State.AddMachine("quantal", state.JobHostUnits) 2833 c.Assert(err, jc.ErrorIsNil) 2834 coll, id, err := state.ConvertTagToCollectionNameAndId(s.State, m.Tag()) 2835 c.Assert(err, jc.ErrorIsNil) 2836 c.Assert(coll, gc.Equals, "machines") 2837 c.Assert(id, gc.Equals, state.DocID(s.State, m.Id())) 2838 } 2839 2840 func (s *StateSuite) TestParseApplicationTag(c *gc.C) { 2841 svc := s.AddTestingService(c, "ser-vice2", s.AddTestingCharm(c, "dummy")) 2842 coll, id, err := state.ConvertTagToCollectionNameAndId(s.State, svc.Tag()) 2843 c.Assert(err, jc.ErrorIsNil) 2844 c.Assert(coll, gc.Equals, "applications") 2845 c.Assert(id, gc.Equals, state.DocID(s.State, svc.Name())) 2846 } 2847 2848 func (s *StateSuite) TestParseUnitTag(c *gc.C) { 2849 svc := s.AddTestingService(c, "service2", s.AddTestingCharm(c, "dummy")) 2850 u, err := svc.AddUnit() 2851 c.Assert(err, jc.ErrorIsNil) 2852 coll, id, err := state.ConvertTagToCollectionNameAndId(s.State, u.Tag()) 2853 c.Assert(err, jc.ErrorIsNil) 2854 c.Assert(coll, gc.Equals, "units") 2855 c.Assert(id, gc.Equals, state.DocID(s.State, u.Name())) 2856 } 2857 2858 func (s *StateSuite) TestParseActionTag(c *gc.C) { 2859 svc := s.AddTestingService(c, "service2", s.AddTestingCharm(c, "dummy")) 2860 u, err := svc.AddUnit() 2861 c.Assert(err, jc.ErrorIsNil) 2862 f, err := u.AddAction("snapshot", nil) 2863 c.Assert(err, jc.ErrorIsNil) 2864 action, err := s.State.Action(f.Id()) 2865 c.Assert(action.Tag(), gc.Equals, names.NewActionTag(action.Id())) 2866 coll, id, err := state.ConvertTagToCollectionNameAndId(s.State, action.Tag()) 2867 c.Assert(err, jc.ErrorIsNil) 2868 c.Assert(coll, gc.Equals, "actions") 2869 c.Assert(id, gc.Equals, action.Id()) 2870 } 2871 2872 func (s *StateSuite) TestParseUserTag(c *gc.C) { 2873 user := s.Factory.MakeUser(c, nil) 2874 coll, id, err := state.ConvertTagToCollectionNameAndId(s.State, user.Tag()) 2875 c.Assert(err, jc.ErrorIsNil) 2876 c.Assert(coll, gc.Equals, "users") 2877 c.Assert(id, gc.Equals, user.Name()) 2878 } 2879 2880 func (s *StateSuite) TestParseModelTag(c *gc.C) { 2881 env, err := s.State.Model() 2882 c.Assert(err, jc.ErrorIsNil) 2883 coll, id, err := state.ConvertTagToCollectionNameAndId(s.State, env.Tag()) 2884 c.Assert(err, jc.ErrorIsNil) 2885 c.Assert(coll, gc.Equals, "models") 2886 c.Assert(id, gc.Equals, env.UUID()) 2887 } 2888 2889 func (s *StateSuite) TestWatchCleanups(c *gc.C) { 2890 // Check initial event. 2891 w := s.State.WatchCleanups() 2892 defer statetesting.AssertStop(c, w) 2893 wc := statetesting.NewNotifyWatcherC(c, s.State, w) 2894 wc.AssertOneChange() 2895 2896 // Set up two relations for later use, check no events. 2897 s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress")) 2898 s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql")) 2899 eps, err := s.State.InferEndpoints("wordpress", "mysql") 2900 c.Assert(err, jc.ErrorIsNil) 2901 relM, err := s.State.AddRelation(eps...) 2902 c.Assert(err, jc.ErrorIsNil) 2903 s.AddTestingService(c, "varnish", s.AddTestingCharm(c, "varnish")) 2904 c.Assert(err, jc.ErrorIsNil) 2905 eps, err = s.State.InferEndpoints("wordpress", "varnish") 2906 c.Assert(err, jc.ErrorIsNil) 2907 relV, err := s.State.AddRelation(eps...) 2908 c.Assert(err, jc.ErrorIsNil) 2909 wc.AssertNoChange() 2910 2911 // Destroy one relation, check one change. 2912 err = relM.Destroy() 2913 c.Assert(err, jc.ErrorIsNil) 2914 wc.AssertOneChange() 2915 2916 // Handle that cleanup doc and create another, check one change. 2917 err = s.State.Cleanup() 2918 c.Assert(err, jc.ErrorIsNil) 2919 err = relV.Destroy() 2920 c.Assert(err, jc.ErrorIsNil) 2921 wc.AssertOneChange() 2922 2923 // Clean up final doc, check change. 2924 err = s.State.Cleanup() 2925 c.Assert(err, jc.ErrorIsNil) 2926 wc.AssertOneChange() 2927 2928 // Stop watcher, check closed. 2929 statetesting.AssertStop(c, w) 2930 wc.AssertClosed() 2931 } 2932 2933 func (s *StateSuite) TestWatchCleanupsDiesOnStateClose(c *gc.C) { 2934 testWatcherDiesWhenStateCloses(c, s.modelTag, s.State.ControllerTag(), func(c *gc.C, st *state.State) waiter { 2935 w := st.WatchCleanups() 2936 <-w.Changes() 2937 return w 2938 }) 2939 } 2940 2941 func (s *StateSuite) TestWatchCleanupsBulk(c *gc.C) { 2942 // Check initial event. 2943 w := s.State.WatchCleanups() 2944 defer statetesting.AssertStop(c, w) 2945 wc := statetesting.NewNotifyWatcherC(c, s.State, w) 2946 wc.AssertOneChange() 2947 2948 // Create two peer relations by creating their services. 2949 riak := s.AddTestingService(c, "riak", s.AddTestingCharm(c, "riak")) 2950 _, err := riak.Endpoint("ring") 2951 c.Assert(err, jc.ErrorIsNil) 2952 allHooks := s.AddTestingService(c, "all-hooks", s.AddTestingCharm(c, "all-hooks")) 2953 _, err = allHooks.Endpoint("self") 2954 c.Assert(err, jc.ErrorIsNil) 2955 wc.AssertNoChange() 2956 2957 // Destroy them both, check one change. 2958 err = riak.Destroy() 2959 c.Assert(err, jc.ErrorIsNil) 2960 err = allHooks.Destroy() 2961 c.Assert(err, jc.ErrorIsNil) 2962 wc.AssertOneChange() 2963 2964 // Clean them both up, check one change. 2965 err = s.State.Cleanup() 2966 c.Assert(err, jc.ErrorIsNil) 2967 wc.AssertOneChange() 2968 } 2969 2970 func (s *StateSuite) TestWatchMinUnits(c *gc.C) { 2971 // Check initial event. 2972 w := s.State.WatchMinUnits() 2973 defer statetesting.AssertStop(c, w) 2974 wc := statetesting.NewStringsWatcherC(c, s.State, w) 2975 wc.AssertChange() 2976 wc.AssertNoChange() 2977 2978 // Set up services for later use. 2979 wordpress := s.AddTestingService(c, 2980 "wordpress", s.AddTestingCharm(c, "wordpress")) 2981 mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql")) 2982 wordpressName := wordpress.Name() 2983 2984 // Add service units for later use. 2985 wordpress0, err := wordpress.AddUnit() 2986 c.Assert(err, jc.ErrorIsNil) 2987 wordpress1, err := wordpress.AddUnit() 2988 c.Assert(err, jc.ErrorIsNil) 2989 mysql0, err := mysql.AddUnit() 2990 c.Assert(err, jc.ErrorIsNil) 2991 // No events should occur. 2992 wc.AssertNoChange() 2993 2994 // Add minimum units to a service; a single change should occur. 2995 err = wordpress.SetMinUnits(2) 2996 c.Assert(err, jc.ErrorIsNil) 2997 wc.AssertChange(wordpressName) 2998 wc.AssertNoChange() 2999 3000 // Decrease minimum units for a service; expect no changes. 3001 err = wordpress.SetMinUnits(1) 3002 c.Assert(err, jc.ErrorIsNil) 3003 wc.AssertNoChange() 3004 3005 // Increase minimum units for two services; a single change should occur. 3006 err = mysql.SetMinUnits(1) 3007 c.Assert(err, jc.ErrorIsNil) 3008 err = wordpress.SetMinUnits(3) 3009 c.Assert(err, jc.ErrorIsNil) 3010 wc.AssertChange(mysql.Name(), wordpressName) 3011 wc.AssertNoChange() 3012 3013 // Remove minimum units for a service; expect no changes. 3014 err = mysql.SetMinUnits(0) 3015 c.Assert(err, jc.ErrorIsNil) 3016 wc.AssertNoChange() 3017 3018 // Destroy a unit of a service with required minimum units. 3019 // Also avoid the unit removal. A single change should occur. 3020 preventUnitDestroyRemove(c, wordpress0) 3021 err = wordpress0.Destroy() 3022 c.Assert(err, jc.ErrorIsNil) 3023 wc.AssertChange(wordpressName) 3024 wc.AssertNoChange() 3025 3026 // Two actions: destroy a unit and increase minimum units for a service. 3027 // A single change should occur, and the application name should appear only 3028 // one time in the change. 3029 err = wordpress.SetMinUnits(5) 3030 c.Assert(err, jc.ErrorIsNil) 3031 err = wordpress1.Destroy() 3032 c.Assert(err, jc.ErrorIsNil) 3033 wc.AssertChange(wordpressName) 3034 wc.AssertNoChange() 3035 3036 // Destroy a unit of a service not requiring minimum units; expect no changes. 3037 err = mysql0.Destroy() 3038 c.Assert(err, jc.ErrorIsNil) 3039 wc.AssertNoChange() 3040 3041 // Destroy a service with required minimum units; expect no changes. 3042 err = wordpress.Destroy() 3043 c.Assert(err, jc.ErrorIsNil) 3044 wc.AssertNoChange() 3045 3046 // Destroy a service not requiring minimum units; expect no changes. 3047 err = mysql.Destroy() 3048 c.Assert(err, jc.ErrorIsNil) 3049 wc.AssertNoChange() 3050 3051 // Stop watcher, check closed. 3052 statetesting.AssertStop(c, w) 3053 wc.AssertClosed() 3054 } 3055 3056 func (s *StateSuite) TestWatchMinUnitsDiesOnStateClose(c *gc.C) { 3057 testWatcherDiesWhenStateCloses(c, s.modelTag, s.State.ControllerTag(), func(c *gc.C, st *state.State) waiter { 3058 w := st.WatchMinUnits() 3059 <-w.Changes() 3060 return w 3061 }) 3062 } 3063 3064 func (s *StateSuite) TestNestingLevel(c *gc.C) { 3065 c.Assert(state.NestingLevel("0"), gc.Equals, 0) 3066 c.Assert(state.NestingLevel("0/lxd/1"), gc.Equals, 1) 3067 c.Assert(state.NestingLevel("0/lxd/1/kvm/0"), gc.Equals, 2) 3068 } 3069 3070 func (s *StateSuite) TestTopParentId(c *gc.C) { 3071 c.Assert(state.TopParentId("0"), gc.Equals, "0") 3072 c.Assert(state.TopParentId("0/lxd/1"), gc.Equals, "0") 3073 c.Assert(state.TopParentId("0/lxd/1/kvm/2"), gc.Equals, "0") 3074 } 3075 3076 func (s *StateSuite) TestParentId(c *gc.C) { 3077 c.Assert(state.ParentId("0"), gc.Equals, "") 3078 c.Assert(state.ParentId("0/lxd/1"), gc.Equals, "0") 3079 c.Assert(state.ParentId("0/lxd/1/kvm/0"), gc.Equals, "0/lxd/1") 3080 } 3081 3082 func (s *StateSuite) TestContainerTypeFromId(c *gc.C) { 3083 c.Assert(state.ContainerTypeFromId("0"), gc.Equals, instance.ContainerType("")) 3084 c.Assert(state.ContainerTypeFromId("0/lxd/1"), gc.Equals, instance.LXD) 3085 c.Assert(state.ContainerTypeFromId("0/lxd/1/kvm/0"), gc.Equals, instance.KVM) 3086 } 3087 3088 func (s *StateSuite) TestIsUpgradeInProgressError(c *gc.C) { 3089 c.Assert(state.IsUpgradeInProgressError(errors.New("foo")), jc.IsFalse) 3090 c.Assert(state.IsUpgradeInProgressError(state.UpgradeInProgressError), jc.IsTrue) 3091 c.Assert(state.IsUpgradeInProgressError(errors.Trace(state.UpgradeInProgressError)), jc.IsTrue) 3092 } 3093 3094 func (s *StateSuite) TestSetEnvironAgentVersionErrors(c *gc.C) { 3095 // Get the agent-version set in the model. 3096 envConfig, err := s.State.ModelConfig() 3097 c.Assert(err, jc.ErrorIsNil) 3098 agentVersion, ok := envConfig.AgentVersion() 3099 c.Assert(ok, jc.IsTrue) 3100 stringVersion := agentVersion.String() 3101 3102 // Add 4 machines: one with a different version, one with an 3103 // empty version, one with the current version, and one with 3104 // the new version. 3105 machine0, err := s.State.AddMachine("series", state.JobHostUnits) 3106 c.Assert(err, jc.ErrorIsNil) 3107 err = machine0.SetAgentVersion(version.MustParseBinary("9.9.9-quantal-amd64")) 3108 c.Assert(err, jc.ErrorIsNil) 3109 machine1, err := s.State.AddMachine("series", state.JobHostUnits) 3110 c.Assert(err, jc.ErrorIsNil) 3111 machine2, err := s.State.AddMachine("series", state.JobHostUnits) 3112 c.Assert(err, jc.ErrorIsNil) 3113 err = machine2.SetAgentVersion(version.MustParseBinary(stringVersion + "-quantal-amd64")) 3114 c.Assert(err, jc.ErrorIsNil) 3115 machine3, err := s.State.AddMachine("series", state.JobHostUnits) 3116 c.Assert(err, jc.ErrorIsNil) 3117 err = machine3.SetAgentVersion(version.MustParseBinary("4.5.6-quantal-amd64")) 3118 c.Assert(err, jc.ErrorIsNil) 3119 3120 // Verify machine0 and machine1 are reported as error. 3121 err = s.State.SetModelAgentVersion(version.MustParse("4.5.6")) 3122 expectErr := fmt.Sprintf("some agents have not upgraded to the current model version %s: machine-0, machine-1", stringVersion) 3123 c.Assert(err, gc.ErrorMatches, expectErr) 3124 c.Assert(err, jc.Satisfies, state.IsVersionInconsistentError) 3125 3126 // Add a service and 4 units: one with a different version, one 3127 // with an empty version, one with the current version, and one 3128 // with the new version. 3129 service, err := s.State.AddApplication(state.AddApplicationArgs{Name: "wordpress", Charm: s.AddTestingCharm(c, "wordpress")}) 3130 c.Assert(err, jc.ErrorIsNil) 3131 unit0, err := service.AddUnit() 3132 c.Assert(err, jc.ErrorIsNil) 3133 err = unit0.SetAgentVersion(version.MustParseBinary("6.6.6-quantal-amd64")) 3134 c.Assert(err, jc.ErrorIsNil) 3135 _, err = service.AddUnit() 3136 c.Assert(err, jc.ErrorIsNil) 3137 unit2, err := service.AddUnit() 3138 c.Assert(err, jc.ErrorIsNil) 3139 err = unit2.SetAgentVersion(version.MustParseBinary(stringVersion + "-quantal-amd64")) 3140 c.Assert(err, jc.ErrorIsNil) 3141 unit3, err := service.AddUnit() 3142 c.Assert(err, jc.ErrorIsNil) 3143 err = unit3.SetAgentVersion(version.MustParseBinary("4.5.6-quantal-amd64")) 3144 c.Assert(err, jc.ErrorIsNil) 3145 3146 // Verify unit0 and unit1 are reported as error, along with the 3147 // machines from before. 3148 err = s.State.SetModelAgentVersion(version.MustParse("4.5.6")) 3149 expectErr = fmt.Sprintf("some agents have not upgraded to the current model version %s: machine-0, machine-1, unit-wordpress-0, unit-wordpress-1", stringVersion) 3150 c.Assert(err, gc.ErrorMatches, expectErr) 3151 c.Assert(err, jc.Satisfies, state.IsVersionInconsistentError) 3152 3153 // Now remove the machines. 3154 for _, machine := range []*state.Machine{machine0, machine1, machine2} { 3155 err = machine.EnsureDead() 3156 c.Assert(err, jc.ErrorIsNil) 3157 err = machine.Remove() 3158 c.Assert(err, jc.ErrorIsNil) 3159 } 3160 3161 // Verify only the units are reported as error. 3162 err = s.State.SetModelAgentVersion(version.MustParse("4.5.6")) 3163 expectErr = fmt.Sprintf("some agents have not upgraded to the current model version %s: unit-wordpress-0, unit-wordpress-1", stringVersion) 3164 c.Assert(err, gc.ErrorMatches, expectErr) 3165 c.Assert(err, jc.Satisfies, state.IsVersionInconsistentError) 3166 } 3167 3168 func (s *StateSuite) prepareAgentVersionTests(c *gc.C, st *state.State) (*config.Config, string) { 3169 // Get the agent-version set in the model. 3170 envConfig, err := st.ModelConfig() 3171 c.Assert(err, jc.ErrorIsNil) 3172 agentVersion, ok := envConfig.AgentVersion() 3173 c.Assert(ok, jc.IsTrue) 3174 currentVersion := agentVersion.String() 3175 3176 // Add a machine and a unit with the current version. 3177 machine, err := st.AddMachine("series", state.JobHostUnits) 3178 c.Assert(err, jc.ErrorIsNil) 3179 service, err := st.AddApplication(state.AddApplicationArgs{Name: "wordpress", Charm: s.AddTestingCharm(c, "wordpress")}) 3180 c.Assert(err, jc.ErrorIsNil) 3181 unit, err := service.AddUnit() 3182 c.Assert(err, jc.ErrorIsNil) 3183 3184 err = machine.SetAgentVersion(version.MustParseBinary(currentVersion + "-quantal-amd64")) 3185 c.Assert(err, jc.ErrorIsNil) 3186 err = unit.SetAgentVersion(version.MustParseBinary(currentVersion + "-quantal-amd64")) 3187 c.Assert(err, jc.ErrorIsNil) 3188 3189 return envConfig, currentVersion 3190 } 3191 3192 func (s *StateSuite) changeEnviron(c *gc.C, envConfig *config.Config, name string, value interface{}) { 3193 attrs := envConfig.AllAttrs() 3194 attrs[name] = value 3195 c.Assert(s.State.UpdateModelConfig(attrs, nil, nil), gc.IsNil) 3196 } 3197 3198 func assertAgentVersion(c *gc.C, st *state.State, vers string) { 3199 envConfig, err := st.ModelConfig() 3200 c.Assert(err, jc.ErrorIsNil) 3201 agentVersion, ok := envConfig.AgentVersion() 3202 c.Assert(ok, jc.IsTrue) 3203 c.Assert(agentVersion.String(), gc.Equals, vers) 3204 } 3205 3206 func (s *StateSuite) TestSetEnvironAgentVersionRetriesOnConfigChange(c *gc.C) { 3207 envConfig, _ := s.prepareAgentVersionTests(c, s.State) 3208 3209 // Set up a transaction hook to change something 3210 // other than the version, and make sure it retries 3211 // and passes. 3212 defer state.SetBeforeHooks(c, s.State, func() { 3213 s.changeEnviron(c, envConfig, "default-series", "foo") 3214 }).Check() 3215 3216 // Change the agent-version and ensure it has changed. 3217 err := s.State.SetModelAgentVersion(version.MustParse("4.5.6")) 3218 c.Assert(err, jc.ErrorIsNil) 3219 assertAgentVersion(c, s.State, "4.5.6") 3220 } 3221 3222 func (s *StateSuite) TestSetEnvironAgentVersionSucceedsWithSameVersion(c *gc.C) { 3223 envConfig, _ := s.prepareAgentVersionTests(c, s.State) 3224 3225 // Set up a transaction hook to change the version 3226 // to the new one, and make sure it retries 3227 // and passes. 3228 defer state.SetBeforeHooks(c, s.State, func() { 3229 s.changeEnviron(c, envConfig, "agent-version", "4.5.6") 3230 }).Check() 3231 3232 // Change the agent-version and verify. 3233 err := s.State.SetModelAgentVersion(version.MustParse("4.5.6")) 3234 c.Assert(err, jc.ErrorIsNil) 3235 assertAgentVersion(c, s.State, "4.5.6") 3236 } 3237 3238 func (s *StateSuite) TestSetEnvironAgentVersionOnOtherEnviron(c *gc.C) { 3239 current := version.MustParseBinary("1.24.7-trusty-amd64") 3240 s.PatchValue(&jujuversion.Current, current.Number) 3241 s.PatchValue(&arch.HostArch, func() string { return current.Arch }) 3242 s.PatchValue(&series.HostSeries, func() string { return current.Series }) 3243 3244 otherSt := s.Factory.MakeModel(c, nil) 3245 defer otherSt.Close() 3246 3247 higher := version.MustParseBinary("1.25.0-trusty-amd64") 3248 lower := version.MustParseBinary("1.24.6-trusty-amd64") 3249 3250 // Set other environ version to < server environ version 3251 err := otherSt.SetModelAgentVersion(lower.Number) 3252 c.Assert(err, jc.ErrorIsNil) 3253 assertAgentVersion(c, otherSt, lower.Number.String()) 3254 3255 // Set other environ version == server environ version 3256 err = otherSt.SetModelAgentVersion(jujuversion.Current) 3257 c.Assert(err, jc.ErrorIsNil) 3258 assertAgentVersion(c, otherSt, jujuversion.Current.String()) 3259 3260 // Set other environ version to > server environ version 3261 err = otherSt.SetModelAgentVersion(higher.Number) 3262 expected := fmt.Sprintf("a hosted model cannot have a higher version than the server model: %s > %s", 3263 higher.Number, 3264 jujuversion.Current, 3265 ) 3266 c.Assert(err, gc.ErrorMatches, expected) 3267 } 3268 3269 func (s *StateSuite) TestSetEnvironAgentVersionExcessiveContention(c *gc.C) { 3270 envConfig, currentVersion := s.prepareAgentVersionTests(c, s.State) 3271 3272 // Set a hook to change the config 3 times 3273 // to test we return ErrExcessiveContention. 3274 changeFuncs := []func(){ 3275 func() { s.changeEnviron(c, envConfig, "default-series", "1") }, 3276 func() { s.changeEnviron(c, envConfig, "default-series", "2") }, 3277 func() { s.changeEnviron(c, envConfig, "default-series", "3") }, 3278 } 3279 defer state.SetBeforeHooks(c, s.State, changeFuncs...).Check() 3280 err := s.State.SetModelAgentVersion(version.MustParse("4.5.6")) 3281 c.Assert(errors.Cause(err), gc.Equals, txn.ErrExcessiveContention) 3282 // Make sure the version remained the same. 3283 assertAgentVersion(c, s.State, currentVersion) 3284 } 3285 3286 func (s *StateSuite) TestSetModelAgentFailsIfUpgrading(c *gc.C) { 3287 // Get the agent-version set in the model. 3288 modelConfig, err := s.State.ModelConfig() 3289 c.Assert(err, jc.ErrorIsNil) 3290 agentVersion, ok := modelConfig.AgentVersion() 3291 c.Assert(ok, jc.IsTrue) 3292 3293 machine, err := s.State.AddMachine("series", state.JobManageModel) 3294 c.Assert(err, jc.ErrorIsNil) 3295 err = machine.SetAgentVersion(version.MustParseBinary(agentVersion.String() + "-quantal-amd64")) 3296 c.Assert(err, jc.ErrorIsNil) 3297 err = machine.SetProvisioned(instance.Id("i-blah"), "fake-nonce", nil) 3298 c.Assert(err, jc.ErrorIsNil) 3299 3300 nextVersion := agentVersion 3301 nextVersion.Minor++ 3302 3303 // Create an unfinished UpgradeInfo instance. 3304 _, err = s.State.EnsureUpgradeInfo(machine.Tag().Id(), agentVersion, nextVersion) 3305 c.Assert(err, jc.ErrorIsNil) 3306 3307 err = s.State.SetModelAgentVersion(nextVersion) 3308 c.Assert(err, jc.Satisfies, state.IsUpgradeInProgressError) 3309 } 3310 3311 func (s *StateSuite) TestSetEnvironAgentFailsReportsCorrectError(c *gc.C) { 3312 // Ensure that the correct error is reported if an upgrade is 3313 // progress but that isn't the reason for the 3314 // SetModelAgentVersion call failing. 3315 3316 // Get the agent-version set in the model. 3317 envConfig, err := s.State.ModelConfig() 3318 c.Assert(err, jc.ErrorIsNil) 3319 agentVersion, ok := envConfig.AgentVersion() 3320 c.Assert(ok, jc.IsTrue) 3321 3322 machine, err := s.State.AddMachine("series", state.JobManageModel) 3323 c.Assert(err, jc.ErrorIsNil) 3324 err = machine.SetAgentVersion(version.MustParseBinary("9.9.9-quantal-amd64")) 3325 c.Assert(err, jc.ErrorIsNil) 3326 err = machine.SetProvisioned(instance.Id("i-blah"), "fake-nonce", nil) 3327 c.Assert(err, jc.ErrorIsNil) 3328 3329 nextVersion := agentVersion 3330 nextVersion.Minor++ 3331 3332 // Create an unfinished UpgradeInfo instance. 3333 _, err = s.State.EnsureUpgradeInfo(machine.Tag().Id(), agentVersion, nextVersion) 3334 c.Assert(err, jc.ErrorIsNil) 3335 3336 err = s.State.SetModelAgentVersion(nextVersion) 3337 c.Assert(err, gc.ErrorMatches, "some agents have not upgraded to the current model version.+") 3338 } 3339 3340 type waiter interface { 3341 Wait() error 3342 } 3343 3344 // testWatcherDiesWhenStateCloses calls the given function to start a watcher, 3345 // closes the state and checks that the watcher dies with the expected error. 3346 // The watcher should already have consumed the first 3347 // event, otherwise the watcher's initialisation logic may 3348 // interact with the closed state, causing it to return an 3349 // unexpected error (often "Closed explictly"). 3350 func testWatcherDiesWhenStateCloses(c *gc.C, modelTag names.ModelTag, controllerTag names.ControllerTag, startWatcher func(c *gc.C, st *state.State) waiter) { 3351 st, err := state.Open(modelTag, controllerTag, statetesting.NewMongoInfo(), mongotest.DialOpts(), nil) 3352 c.Assert(err, jc.ErrorIsNil) 3353 watcher := startWatcher(c, st) 3354 err = st.Close() 3355 c.Assert(err, jc.ErrorIsNil) 3356 done := make(chan error) 3357 go func() { 3358 done <- watcher.Wait() 3359 }() 3360 select { 3361 case err := <-done: 3362 c.Assert(err, gc.ErrorMatches, state.ErrStateClosed.Error()) 3363 case <-time.After(testing.LongWait): 3364 c.Fatalf("watcher %T did not exit when state closed", watcher) 3365 } 3366 } 3367 3368 func (s *StateSuite) TestControllerInfo(c *gc.C) { 3369 ids, err := s.State.ControllerInfo() 3370 c.Assert(err, jc.ErrorIsNil) 3371 c.Assert(ids.CloudName, gc.Equals, "dummy") 3372 c.Assert(ids.ModelTag, gc.Equals, s.modelTag) 3373 c.Assert(ids.MachineIds, gc.HasLen, 0) 3374 c.Assert(ids.VotingMachineIds, gc.HasLen, 0) 3375 3376 // TODO(rog) more testing here when we can actually add 3377 // controllers. 3378 } 3379 3380 func (s *StateSuite) TestReopenWithNoMachines(c *gc.C) { 3381 expected := &state.ControllerInfo{ 3382 CloudName: "dummy", 3383 ModelTag: s.modelTag, 3384 } 3385 info, err := s.State.ControllerInfo() 3386 c.Assert(err, jc.ErrorIsNil) 3387 c.Assert(info, jc.DeepEquals, expected) 3388 3389 st, err := state.Open(s.modelTag, s.State.ControllerTag(), statetesting.NewMongoInfo(), mongotest.DialOpts(), nil) 3390 c.Assert(err, jc.ErrorIsNil) 3391 defer st.Close() 3392 3393 info, err = s.State.ControllerInfo() 3394 c.Assert(err, jc.ErrorIsNil) 3395 c.Assert(info, jc.DeepEquals, expected) 3396 } 3397 3398 func (s *StateSuite) TestEnableHAFailsWithBadCount(c *gc.C) { 3399 for _, n := range []int{-1, 2, 6} { 3400 changes, err := s.State.EnableHA(n, constraints.Value{}, "", nil) 3401 c.Assert(err, gc.ErrorMatches, "number of controllers must be odd and non-negative") 3402 c.Assert(changes.Added, gc.HasLen, 0) 3403 } 3404 _, err := s.State.EnableHA(replicaset.MaxPeers+2, constraints.Value{}, "", nil) 3405 c.Assert(err, gc.ErrorMatches, `controller count is too large \(allowed \d+\)`) 3406 } 3407 3408 func (s *StateSuite) TestEnableHAAddsNewMachines(c *gc.C) { 3409 // Don't use agent presence to decide on machine availability. 3410 s.PatchValue(state.ControllerAvailable, func(m *state.Machine) (bool, error) { 3411 return true, nil 3412 }) 3413 3414 ids := make([]string, 3) 3415 m0, err := s.State.AddMachine("quantal", state.JobHostUnits, state.JobManageModel) 3416 c.Assert(err, jc.ErrorIsNil) 3417 ids[0] = m0.Id() 3418 3419 // Add a non-controller machine just to make sure. 3420 _, err = s.State.AddMachine("quantal", state.JobHostUnits) 3421 c.Assert(err, jc.ErrorIsNil) 3422 3423 s.assertControllerInfo(c, []string{"0"}, []string{"0"}, nil) 3424 3425 cons := constraints.Value{ 3426 Mem: newUint64(100), 3427 } 3428 changes, err := s.State.EnableHA(3, cons, "quantal", nil) 3429 c.Assert(err, jc.ErrorIsNil) 3430 c.Assert(changes.Added, gc.HasLen, 2) 3431 3432 for i := 1; i < 3; i++ { 3433 m, err := s.State.Machine(fmt.Sprint(i + 1)) 3434 c.Assert(err, jc.ErrorIsNil) 3435 c.Assert(m.Jobs(), gc.DeepEquals, []state.MachineJob{ 3436 state.JobHostUnits, 3437 state.JobManageModel, 3438 }) 3439 gotCons, err := m.Constraints() 3440 c.Assert(err, jc.ErrorIsNil) 3441 c.Assert(gotCons, gc.DeepEquals, cons) 3442 c.Assert(m.WantsVote(), jc.IsTrue) 3443 ids[i] = m.Id() 3444 } 3445 s.assertControllerInfo(c, ids, ids, nil) 3446 } 3447 3448 func (s *StateSuite) TestEnableHATo(c *gc.C) { 3449 // Don't use agent presence to decide on machine availability. 3450 s.PatchValue(state.ControllerAvailable, func(m *state.Machine) (bool, error) { 3451 return true, nil 3452 }) 3453 3454 ids := make([]string, 3) 3455 m0, err := s.State.AddMachine("quantal", state.JobHostUnits, state.JobManageModel) 3456 c.Assert(err, jc.ErrorIsNil) 3457 ids[0] = m0.Id() 3458 3459 // Add two non-controller machines. 3460 _, err = s.State.AddMachine("quantal", state.JobHostUnits) 3461 c.Assert(err, jc.ErrorIsNil) 3462 3463 _, err = s.State.AddMachine("quantal", state.JobHostUnits) 3464 c.Assert(err, jc.ErrorIsNil) 3465 3466 s.assertControllerInfo(c, []string{"0"}, []string{"0"}, nil) 3467 3468 changes, err := s.State.EnableHA(3, constraints.Value{}, "quantal", []string{"1", "2"}) 3469 c.Assert(err, jc.ErrorIsNil) 3470 c.Assert(changes.Added, gc.HasLen, 0) 3471 c.Assert(changes.Converted, gc.HasLen, 2) 3472 3473 for i := 1; i < 3; i++ { 3474 m, err := s.State.Machine(fmt.Sprint(i)) 3475 c.Assert(err, jc.ErrorIsNil) 3476 c.Assert(m.Jobs(), gc.DeepEquals, []state.MachineJob{ 3477 state.JobHostUnits, 3478 state.JobManageModel, 3479 }) 3480 gotCons, err := m.Constraints() 3481 c.Assert(err, jc.ErrorIsNil) 3482 c.Assert(gotCons, gc.DeepEquals, constraints.Value{}) 3483 c.Assert(m.WantsVote(), jc.IsTrue) 3484 ids[i] = m.Id() 3485 } 3486 s.assertControllerInfo(c, ids, ids, nil) 3487 } 3488 3489 func newUint64(i uint64) *uint64 { 3490 return &i 3491 } 3492 3493 func (s *StateSuite) assertControllerInfo(c *gc.C, machineIds []string, votingMachineIds []string, placement []string) { 3494 info, err := s.State.ControllerInfo() 3495 c.Assert(err, jc.ErrorIsNil) 3496 c.Assert(info.ModelTag, gc.Equals, s.modelTag) 3497 c.Assert(info.MachineIds, jc.SameContents, machineIds) 3498 c.Assert(info.VotingMachineIds, jc.SameContents, votingMachineIds) 3499 for i, id := range machineIds { 3500 m, err := s.State.Machine(id) 3501 c.Assert(err, jc.ErrorIsNil) 3502 if len(placement) == 0 || i >= len(placement) { 3503 c.Check(m.Placement(), gc.Equals, "") 3504 } else { 3505 c.Check(m.Placement(), gc.Equals, placement[i]) 3506 } 3507 } 3508 } 3509 3510 func (s *StateSuite) TestEnableHASamePlacementAsNewCount(c *gc.C) { 3511 placement := []string{"p1", "p2", "p3"} 3512 changes, err := s.State.EnableHA(3, constraints.Value{}, "quantal", placement) 3513 c.Assert(err, jc.ErrorIsNil) 3514 c.Assert(changes.Added, gc.HasLen, 3) 3515 s.assertControllerInfo(c, []string{"0", "1", "2"}, []string{"0", "1", "2"}, []string{"p1", "p2", "p3"}) 3516 } 3517 3518 func (s *StateSuite) TestEnableHAMorePlacementThanNewCount(c *gc.C) { 3519 placement := []string{"p1", "p2", "p3", "p4"} 3520 changes, err := s.State.EnableHA(3, constraints.Value{}, "quantal", placement) 3521 c.Assert(err, jc.ErrorIsNil) 3522 c.Assert(changes.Added, gc.HasLen, 3) 3523 s.assertControllerInfo(c, []string{"0", "1", "2"}, []string{"0", "1", "2"}, []string{"p1", "p2", "p3"}) 3524 } 3525 3526 func (s *StateSuite) TestEnableHALessPlacementThanNewCount(c *gc.C) { 3527 placement := []string{"p1", "p2"} 3528 changes, err := s.State.EnableHA(3, constraints.Value{}, "quantal", placement) 3529 c.Assert(err, jc.ErrorIsNil) 3530 c.Assert(changes.Added, gc.HasLen, 3) 3531 s.assertControllerInfo(c, []string{"0", "1", "2"}, []string{"0", "1", "2"}, []string{"p1", "p2"}) 3532 } 3533 3534 func (s *StateSuite) TestEnableHADemotesUnavailableMachines(c *gc.C) { 3535 changes, err := s.State.EnableHA(3, constraints.Value{}, "quantal", nil) 3536 c.Assert(err, jc.ErrorIsNil) 3537 c.Assert(changes.Added, gc.HasLen, 3) 3538 s.assertControllerInfo(c, []string{"0", "1", "2"}, []string{"0", "1", "2"}, nil) 3539 s.PatchValue(state.ControllerAvailable, func(m *state.Machine) (bool, error) { 3540 return m.Id() != "0", nil 3541 }) 3542 changes, err = s.State.EnableHA(3, constraints.Value{}, "quantal", nil) 3543 c.Assert(err, jc.ErrorIsNil) 3544 c.Assert(changes.Added, gc.HasLen, 1) 3545 c.Assert(changes.Maintained, gc.HasLen, 2) 3546 3547 // New controller machine "3" is created; "0" still exists in MachineIds, 3548 // but no longer in VotingMachineIds. 3549 s.assertControllerInfo(c, []string{"0", "1", "2", "3"}, []string{"1", "2", "3"}, nil) 3550 m0, err := s.State.Machine("0") 3551 c.Assert(err, jc.ErrorIsNil) 3552 c.Assert(m0.WantsVote(), jc.IsFalse) 3553 c.Assert(m0.IsManager(), jc.IsTrue) // job still intact for now 3554 m3, err := s.State.Machine("3") 3555 c.Assert(err, jc.ErrorIsNil) 3556 c.Assert(m3.WantsVote(), jc.IsTrue) 3557 c.Assert(m3.IsManager(), jc.IsTrue) 3558 } 3559 3560 func (s *StateSuite) TestEnableHAPromotesAvailableMachines(c *gc.C) { 3561 changes, err := s.State.EnableHA(3, constraints.Value{}, "quantal", nil) 3562 c.Assert(err, jc.ErrorIsNil) 3563 c.Assert(changes.Added, gc.HasLen, 3) 3564 s.assertControllerInfo(c, []string{"0", "1", "2"}, []string{"0", "1", "2"}, nil) 3565 s.PatchValue(state.ControllerAvailable, func(m *state.Machine) (bool, error) { 3566 return m.Id() != "0", nil 3567 }) 3568 changes, err = s.State.EnableHA(3, constraints.Value{}, "quantal", nil) 3569 c.Assert(err, jc.ErrorIsNil) 3570 c.Assert(changes.Added, gc.HasLen, 1) 3571 c.Assert(changes.Demoted, gc.DeepEquals, []string{"0"}) 3572 c.Assert(changes.Maintained, gc.HasLen, 2) 3573 3574 // New controller machine "3" is created; "0" still exists in MachineIds, 3575 // but no longer in VotingMachineIds. 3576 s.assertControllerInfo(c, []string{"0", "1", "2", "3"}, []string{"1", "2", "3"}, nil) 3577 m0, err := s.State.Machine("0") 3578 c.Assert(err, jc.ErrorIsNil) 3579 c.Assert(m0.WantsVote(), jc.IsFalse) 3580 3581 // Mark machine 0 as having a vote, so it doesn't get removed, and make it 3582 // available once more. 3583 err = m0.SetHasVote(true) 3584 c.Assert(err, jc.ErrorIsNil) 3585 s.PatchValue(state.ControllerAvailable, func(m *state.Machine) (bool, error) { 3586 return true, nil 3587 }) 3588 changes, err = s.State.EnableHA(3, constraints.Value{}, "quantal", nil) 3589 c.Assert(err, jc.ErrorIsNil) 3590 c.Assert(changes.Added, gc.HasLen, 0) 3591 3592 // No change; we've got as many voting machines as we need. 3593 s.assertControllerInfo(c, []string{"0", "1", "2", "3"}, []string{"1", "2", "3"}, nil) 3594 3595 // Make machine 3 unavailable; machine 0 should be promoted, and two new 3596 // machines created. 3597 s.PatchValue(state.ControllerAvailable, func(m *state.Machine) (bool, error) { 3598 return m.Id() != "3", nil 3599 }) 3600 changes, err = s.State.EnableHA(5, constraints.Value{}, "quantal", nil) 3601 c.Assert(err, jc.ErrorIsNil) 3602 c.Assert(changes.Added, gc.HasLen, 2) 3603 c.Assert(changes.Demoted, gc.DeepEquals, []string{"3"}) 3604 s.assertControllerInfo(c, []string{"0", "1", "2", "3", "4", "5"}, []string{"0", "1", "2", "4", "5"}, nil) 3605 err = m0.Refresh() 3606 c.Assert(err, jc.ErrorIsNil) 3607 c.Assert(m0.WantsVote(), jc.IsTrue) 3608 } 3609 3610 func (s *StateSuite) TestEnableHARemovesUnavailableMachines(c *gc.C) { 3611 changes, err := s.State.EnableHA(3, constraints.Value{}, "quantal", nil) 3612 c.Assert(err, jc.ErrorIsNil) 3613 c.Assert(changes.Added, gc.HasLen, 3) 3614 3615 s.assertControllerInfo(c, []string{"0", "1", "2"}, []string{"0", "1", "2"}, nil) 3616 s.PatchValue(state.ControllerAvailable, func(m *state.Machine) (bool, error) { 3617 return m.Id() != "0", nil 3618 }) 3619 changes, err = s.State.EnableHA(3, constraints.Value{}, "quantal", nil) 3620 c.Assert(err, jc.ErrorIsNil) 3621 c.Assert(changes.Added, gc.HasLen, 1) 3622 s.assertControllerInfo(c, []string{"0", "1", "2", "3"}, []string{"1", "2", "3"}, nil) 3623 // machine 0 does not have a vote, so another call to EnableHA 3624 // will remove machine 0's JobEnvironManager job. 3625 changes, err = s.State.EnableHA(3, constraints.Value{}, "quantal", nil) 3626 c.Assert(changes.Removed, gc.HasLen, 1) 3627 c.Assert(changes.Maintained, gc.HasLen, 3) 3628 c.Assert(err, jc.ErrorIsNil) 3629 s.assertControllerInfo(c, []string{"1", "2", "3"}, []string{"1", "2", "3"}, nil) 3630 m0, err := s.State.Machine("0") 3631 c.Assert(err, jc.ErrorIsNil) 3632 c.Assert(m0.IsManager(), jc.IsFalse) 3633 } 3634 3635 func (s *StateSuite) TestEnableHAMaintainsVoteList(c *gc.C) { 3636 changes, err := s.State.EnableHA(5, constraints.Value{}, "quantal", nil) 3637 c.Assert(err, jc.ErrorIsNil) 3638 c.Assert(changes.Added, gc.HasLen, 5) 3639 3640 s.assertControllerInfo(c, 3641 []string{"0", "1", "2", "3", "4"}, 3642 []string{"0", "1", "2", "3", "4"}, nil) 3643 // Mark machine-0 as dead, so we'll want to create another one again 3644 s.PatchValue(state.ControllerAvailable, func(m *state.Machine) (bool, error) { 3645 return m.Id() != "0", nil 3646 }) 3647 changes, err = s.State.EnableHA(0, constraints.Value{}, "quantal", nil) 3648 c.Assert(err, jc.ErrorIsNil) 3649 c.Assert(changes.Added, gc.HasLen, 1) 3650 3651 // New controller machine "5" is created; "0" still exists in MachineIds, 3652 // but no longer in VotingMachineIds. 3653 s.assertControllerInfo(c, 3654 []string{"0", "1", "2", "3", "4", "5"}, 3655 []string{"1", "2", "3", "4", "5"}, nil) 3656 m0, err := s.State.Machine("0") 3657 c.Assert(err, jc.ErrorIsNil) 3658 c.Assert(m0.WantsVote(), jc.IsFalse) 3659 c.Assert(m0.IsManager(), jc.IsTrue) // job still intact for now 3660 m3, err := s.State.Machine("5") 3661 c.Assert(err, jc.ErrorIsNil) 3662 c.Assert(m3.WantsVote(), jc.IsTrue) 3663 c.Assert(m3.IsManager(), jc.IsTrue) 3664 } 3665 3666 func (s *StateSuite) TestEnableHADefaultsTo3(c *gc.C) { 3667 changes, err := s.State.EnableHA(0, constraints.Value{}, "quantal", nil) 3668 c.Assert(err, jc.ErrorIsNil) 3669 c.Assert(changes.Added, gc.HasLen, 3) 3670 s.assertControllerInfo(c, []string{"0", "1", "2"}, []string{"0", "1", "2"}, nil) 3671 // Mark machine-0 as dead, so we'll want to create it again 3672 s.PatchValue(state.ControllerAvailable, func(m *state.Machine) (bool, error) { 3673 return m.Id() != "0", nil 3674 }) 3675 changes, err = s.State.EnableHA(0, constraints.Value{}, "quantal", nil) 3676 c.Assert(err, jc.ErrorIsNil) 3677 c.Assert(changes.Added, gc.HasLen, 1) 3678 3679 // New controller machine "3" is created; "0" still exists in MachineIds, 3680 // but no longer in VotingMachineIds. 3681 s.assertControllerInfo(c, 3682 []string{"0", "1", "2", "3"}, 3683 []string{"1", "2", "3"}, nil) 3684 m0, err := s.State.Machine("0") 3685 c.Assert(err, jc.ErrorIsNil) 3686 c.Assert(m0.WantsVote(), jc.IsFalse) 3687 c.Assert(m0.IsManager(), jc.IsTrue) // job still intact for now 3688 m3, err := s.State.Machine("3") 3689 c.Assert(err, jc.ErrorIsNil) 3690 c.Assert(m3.WantsVote(), jc.IsTrue) 3691 c.Assert(m3.IsManager(), jc.IsTrue) 3692 } 3693 3694 func (s *StateSuite) TestEnableHAConcurrentSame(c *gc.C) { 3695 s.PatchValue(state.ControllerAvailable, func(m *state.Machine) (bool, error) { 3696 return true, nil 3697 }) 3698 3699 defer state.SetBeforeHooks(c, s.State, func() { 3700 changes, err := s.State.EnableHA(3, constraints.Value{}, "quantal", nil) 3701 c.Assert(err, jc.ErrorIsNil) 3702 // The outer EnableHA call will allocate IDs 0..2, 3703 // and the inner one 3..5. 3704 c.Assert(changes.Added, gc.HasLen, 3) 3705 expected := []string{"3", "4", "5"} 3706 s.assertControllerInfo(c, expected, expected, nil) 3707 }).Check() 3708 3709 changes, err := s.State.EnableHA(3, constraints.Value{}, "quantal", nil) 3710 c.Assert(err, jc.ErrorIsNil) 3711 c.Assert(changes.Added, gc.DeepEquals, []string{"0", "1", "2"}) 3712 s.assertControllerInfo(c, []string{"3", "4", "5"}, []string{"3", "4", "5"}, nil) 3713 3714 // Machine 0 should never have been created. 3715 _, err = s.State.Machine("0") 3716 c.Assert(err, jc.Satisfies, errors.IsNotFound) 3717 } 3718 3719 func (s *StateSuite) TestEnableHAConcurrentLess(c *gc.C) { 3720 s.PatchValue(state.ControllerAvailable, func(m *state.Machine) (bool, error) { 3721 return true, nil 3722 }) 3723 3724 defer state.SetBeforeHooks(c, s.State, func() { 3725 changes, err := s.State.EnableHA(3, constraints.Value{}, "quantal", nil) 3726 c.Assert(err, jc.ErrorIsNil) 3727 c.Assert(changes.Added, gc.HasLen, 3) 3728 // The outer EnableHA call will initially allocate IDs 0..4, 3729 // and the inner one 5..7. 3730 expected := []string{"5", "6", "7"} 3731 s.assertControllerInfo(c, expected, expected, nil) 3732 }).Check() 3733 3734 // This call to EnableHA will initially attempt to allocate 3735 // machines 0..4, and fail due to the concurrent change. It will then 3736 // allocate machines 8..9 to make up the difference from the concurrent 3737 // EnableHA call. 3738 changes, err := s.State.EnableHA(5, constraints.Value{}, "quantal", nil) 3739 c.Assert(err, jc.ErrorIsNil) 3740 c.Assert(changes.Added, gc.HasLen, 2) 3741 expected := []string{"5", "6", "7", "8", "9"} 3742 s.assertControllerInfo(c, expected, expected, nil) 3743 3744 // Machine 0 should never have been created. 3745 _, err = s.State.Machine("0") 3746 c.Assert(err, jc.Satisfies, errors.IsNotFound) 3747 } 3748 3749 func (s *StateSuite) TestEnableHAConcurrentMore(c *gc.C) { 3750 s.PatchValue(state.ControllerAvailable, func(m *state.Machine) (bool, error) { 3751 return true, nil 3752 }) 3753 3754 defer state.SetBeforeHooks(c, s.State, func() { 3755 changes, err := s.State.EnableHA(5, constraints.Value{}, "quantal", nil) 3756 c.Assert(err, jc.ErrorIsNil) 3757 c.Assert(changes.Added, gc.HasLen, 5) 3758 // The outer EnableHA call will allocate IDs 0..2, 3759 // and the inner one 3..7. 3760 expected := []string{"3", "4", "5", "6", "7"} 3761 s.assertControllerInfo(c, expected, expected, nil) 3762 }).Check() 3763 3764 // This call to EnableHA will initially attempt to allocate 3765 // machines 0..2, and fail due to the concurrent change. It will then 3766 // find that the number of voting machines in state is greater than 3767 // what we're attempting to ensure, and fail. 3768 changes, err := s.State.EnableHA(3, constraints.Value{}, "quantal", nil) 3769 c.Assert(err, gc.ErrorMatches, "failed to create new controller machines: cannot reduce controller count") 3770 c.Assert(changes.Added, gc.HasLen, 0) 3771 3772 // Machine 0 should never have been created. 3773 _, err = s.State.Machine("0") 3774 c.Assert(err, jc.Satisfies, errors.IsNotFound) 3775 } 3776 3777 func (s *StateSuite) TestStateServingInfo(c *gc.C) { 3778 info, err := s.State.StateServingInfo() 3779 c.Assert(err, gc.ErrorMatches, "state serving info not found") 3780 c.Assert(err, jc.Satisfies, errors.IsNotFound) 3781 3782 data := state.StateServingInfo{ 3783 APIPort: 69, 3784 StatePort: 80, 3785 Cert: "Some cert", 3786 PrivateKey: "Some key", 3787 SharedSecret: "Some Keyfile", 3788 } 3789 err = s.State.SetStateServingInfo(data) 3790 c.Assert(err, jc.ErrorIsNil) 3791 3792 info, err = s.State.StateServingInfo() 3793 c.Assert(err, jc.ErrorIsNil) 3794 c.Assert(info, jc.DeepEquals, data) 3795 } 3796 3797 var setStateServingInfoWithInvalidInfoTests = []func(info *state.StateServingInfo){ 3798 func(info *state.StateServingInfo) { info.APIPort = 0 }, 3799 func(info *state.StateServingInfo) { info.StatePort = 0 }, 3800 func(info *state.StateServingInfo) { info.Cert = "" }, 3801 func(info *state.StateServingInfo) { info.PrivateKey = "" }, 3802 } 3803 3804 func (s *StateSuite) TestSetStateServingInfoWithInvalidInfo(c *gc.C) { 3805 origData := state.StateServingInfo{ 3806 APIPort: 69, 3807 StatePort: 80, 3808 Cert: "Some cert", 3809 PrivateKey: "Some key", 3810 SharedSecret: "Some Keyfile", 3811 } 3812 for i, test := range setStateServingInfoWithInvalidInfoTests { 3813 c.Logf("test %d", i) 3814 data := origData 3815 test(&data) 3816 err := s.State.SetStateServingInfo(data) 3817 c.Assert(err, gc.ErrorMatches, "incomplete state serving info set in state") 3818 } 3819 } 3820 3821 func (s *StateSuite) TestSetAPIHostPorts(c *gc.C) { 3822 addrs, err := s.State.APIHostPorts() 3823 c.Assert(err, jc.ErrorIsNil) 3824 c.Assert(addrs, gc.HasLen, 0) 3825 3826 newHostPorts := [][]network.HostPort{{{ 3827 Address: network.Address{ 3828 Value: "0.2.4.6", 3829 Type: network.IPv4Address, 3830 Scope: network.ScopeCloudLocal, 3831 }, 3832 Port: 1, 3833 }, { 3834 Address: network.Address{ 3835 Value: "0.4.8.16", 3836 Type: network.IPv4Address, 3837 Scope: network.ScopePublic, 3838 }, 3839 Port: 2, 3840 }}, {{ 3841 Address: network.Address{ 3842 Value: "0.6.1.2", 3843 Type: network.IPv4Address, 3844 Scope: network.ScopeCloudLocal, 3845 }, 3846 Port: 5, 3847 }}} 3848 err = s.State.SetAPIHostPorts(newHostPorts) 3849 c.Assert(err, jc.ErrorIsNil) 3850 3851 gotHostPorts, err := s.State.APIHostPorts() 3852 c.Assert(err, jc.ErrorIsNil) 3853 c.Assert(gotHostPorts, jc.DeepEquals, newHostPorts) 3854 3855 newHostPorts = [][]network.HostPort{{{ 3856 Address: network.Address{ 3857 Value: "0.2.4.6", 3858 Type: network.IPv6Address, 3859 Scope: network.ScopeCloudLocal, 3860 }, 3861 Port: 13, 3862 }}} 3863 err = s.State.SetAPIHostPorts(newHostPorts) 3864 c.Assert(err, jc.ErrorIsNil) 3865 3866 gotHostPorts, err = s.State.APIHostPorts() 3867 c.Assert(err, jc.ErrorIsNil) 3868 c.Assert(gotHostPorts, jc.DeepEquals, newHostPorts) 3869 } 3870 3871 func (s *StateSuite) TestSetAPIHostPortsConcurrentSame(c *gc.C) { 3872 hostPorts := [][]network.HostPort{{{ 3873 Address: network.Address{ 3874 Value: "0.4.8.16", 3875 Type: network.IPv4Address, 3876 Scope: network.ScopePublic, 3877 }, 3878 Port: 2, 3879 }}, {{ 3880 Address: network.Address{ 3881 Value: "0.2.4.6", 3882 Type: network.IPv4Address, 3883 Scope: network.ScopeCloudLocal, 3884 }, 3885 Port: 1, 3886 }}} 3887 3888 // API host ports are concurrently changed to the same 3889 // desired value; second arrival will fail its assertion, 3890 // refresh finding nothing to do, and then issue a 3891 // read-only assertion that suceeds. 3892 3893 var prevRevno int64 3894 defer state.SetBeforeHooks(c, s.State, func() { 3895 err := s.State.SetAPIHostPorts(hostPorts) 3896 c.Assert(err, jc.ErrorIsNil) 3897 revno, err := state.TxnRevno(s.State, "controllers", "apiHostPorts") 3898 c.Assert(err, jc.ErrorIsNil) 3899 prevRevno = revno 3900 }).Check() 3901 3902 err := s.State.SetAPIHostPorts(hostPorts) 3903 c.Assert(err, jc.ErrorIsNil) 3904 c.Assert(prevRevno, gc.Not(gc.Equals), 0) 3905 revno, err := state.TxnRevno(s.State, "controllers", "apiHostPorts") 3906 c.Assert(err, jc.ErrorIsNil) 3907 c.Assert(revno, gc.Equals, prevRevno) 3908 } 3909 3910 func (s *StateSuite) TestSetAPIHostPortsConcurrentDifferent(c *gc.C) { 3911 hostPorts0 := []network.HostPort{{ 3912 Address: network.Address{ 3913 Value: "0.4.8.16", 3914 Type: network.IPv4Address, 3915 Scope: network.ScopePublic, 3916 }, 3917 Port: 2, 3918 }} 3919 hostPorts1 := []network.HostPort{{ 3920 Address: network.Address{ 3921 Value: "0.2.4.6", 3922 Type: network.IPv4Address, 3923 Scope: network.ScopeCloudLocal, 3924 }, 3925 Port: 1, 3926 }} 3927 3928 // API host ports are concurrently changed to different 3929 // values; second arrival will fail its assertion, refresh 3930 // finding and reattempt. 3931 3932 var prevRevno int64 3933 defer state.SetBeforeHooks(c, s.State, func() { 3934 err := s.State.SetAPIHostPorts([][]network.HostPort{hostPorts0}) 3935 c.Assert(err, jc.ErrorIsNil) 3936 revno, err := state.TxnRevno(s.State, "controllers", "apiHostPorts") 3937 c.Assert(err, jc.ErrorIsNil) 3938 prevRevno = revno 3939 }).Check() 3940 3941 err := s.State.SetAPIHostPorts([][]network.HostPort{hostPorts1}) 3942 c.Assert(err, jc.ErrorIsNil) 3943 c.Assert(prevRevno, gc.Not(gc.Equals), 0) 3944 revno, err := state.TxnRevno(s.State, "controllers", "apiHostPorts") 3945 c.Assert(err, jc.ErrorIsNil) 3946 c.Assert(revno, gc.Not(gc.Equals), prevRevno) 3947 3948 hostPorts, err := s.State.APIHostPorts() 3949 c.Assert(err, jc.ErrorIsNil) 3950 c.Assert(hostPorts, gc.DeepEquals, [][]network.HostPort{hostPorts1}) 3951 } 3952 3953 func (s *StateSuite) TestWatchAPIHostPorts(c *gc.C) { 3954 w := s.State.WatchAPIHostPorts() 3955 defer statetesting.AssertStop(c, w) 3956 3957 // Initial event. 3958 wc := statetesting.NewNotifyWatcherC(c, s.State, w) 3959 wc.AssertOneChange() 3960 3961 err := s.State.SetAPIHostPorts([][]network.HostPort{ 3962 network.NewHostPorts(99, "0.1.2.3"), 3963 }) 3964 c.Assert(err, jc.ErrorIsNil) 3965 3966 wc.AssertOneChange() 3967 3968 // Stop, check closed. 3969 statetesting.AssertStop(c, w) 3970 wc.AssertClosed() 3971 } 3972 3973 func (s *StateSuite) TestWatchMachineAddresses(c *gc.C) { 3974 // Add a machine: reported. 3975 machine, err := s.State.AddMachine("quantal", state.JobHostUnits) 3976 c.Assert(err, jc.ErrorIsNil) 3977 3978 w := machine.WatchAddresses() 3979 defer w.Stop() 3980 wc := statetesting.NewNotifyWatcherC(c, s.State, w) 3981 wc.AssertOneChange() 3982 3983 // Change the machine: not reported. 3984 err = machine.SetProvisioned(instance.Id("i-blah"), "fake-nonce", nil) 3985 c.Assert(err, jc.ErrorIsNil) 3986 wc.AssertNoChange() 3987 3988 // Set machine addresses: reported. 3989 err = machine.SetMachineAddresses(network.NewAddress("abc")) 3990 c.Assert(err, jc.ErrorIsNil) 3991 wc.AssertOneChange() 3992 3993 // Set provider addresses eclipsing machine addresses: reported. 3994 err = machine.SetProviderAddresses(network.NewScopedAddress("abc", network.ScopePublic)) 3995 c.Assert(err, jc.ErrorIsNil) 3996 wc.AssertOneChange() 3997 3998 // Set same machine eclipsed by provider addresses: not reported. 3999 err = machine.SetMachineAddresses(network.NewScopedAddress("abc", network.ScopeCloudLocal)) 4000 c.Assert(err, jc.ErrorIsNil) 4001 wc.AssertNoChange() 4002 4003 // Set different machine addresses: reported. 4004 err = machine.SetMachineAddresses(network.NewAddress("def")) 4005 c.Assert(err, jc.ErrorIsNil) 4006 wc.AssertOneChange() 4007 4008 // Set different provider addresses: reported. 4009 err = machine.SetMachineAddresses(network.NewScopedAddress("def", network.ScopePublic)) 4010 c.Assert(err, jc.ErrorIsNil) 4011 wc.AssertOneChange() 4012 4013 // Make it Dying: not reported. 4014 err = machine.Destroy() 4015 c.Assert(err, jc.ErrorIsNil) 4016 wc.AssertNoChange() 4017 4018 // Make it Dead: not reported. 4019 err = machine.EnsureDead() 4020 c.Assert(err, jc.ErrorIsNil) 4021 wc.AssertNoChange() 4022 4023 // Remove it: watcher eventually closed and Err 4024 // returns an IsNotFound error. 4025 err = machine.Remove() 4026 c.Assert(err, jc.ErrorIsNil) 4027 s.State.StartSync() 4028 select { 4029 case _, ok := <-w.Changes(): 4030 c.Assert(ok, jc.IsFalse) 4031 case <-time.After(testing.LongWait): 4032 c.Fatalf("watcher not closed") 4033 } 4034 c.Assert(w.Err(), jc.Satisfies, errors.IsNotFound) 4035 } 4036 4037 func (s *StateSuite) TestNowToTheSecond(c *gc.C) { 4038 t := s.State.NowToTheSecond() 4039 rounded := t.Round(time.Second) 4040 c.Assert(t, gc.DeepEquals, rounded) 4041 } 4042 4043 func (s *StateSuite) TestUnitsForInvalidId(c *gc.C) { 4044 // Check that an error is returned if an invalid machine id is provided. 4045 // Success cases are tested as part of TestMachinePrincipalUnits in the 4046 // MachineSuite. 4047 units, err := s.State.UnitsFor("invalid-id") 4048 c.Assert(units, gc.IsNil) 4049 c.Assert(err, gc.ErrorMatches, `"invalid-id" is not a valid machine id`) 4050 } 4051 4052 func (s *StateSuite) TestSetOrGetMongoSpaceNameSets(c *gc.C) { 4053 info, err := s.State.ControllerInfo() 4054 c.Assert(err, jc.ErrorIsNil) 4055 c.Assert(info.MongoSpaceName, gc.Equals, "") 4056 c.Assert(info.MongoSpaceState, gc.Equals, state.MongoSpaceUnknown) 4057 4058 spaceName := network.SpaceName("foo") 4059 4060 name, err := s.State.SetOrGetMongoSpaceName(spaceName) 4061 c.Assert(err, jc.ErrorIsNil) 4062 c.Assert(name, gc.Equals, spaceName) 4063 4064 info, err = s.State.ControllerInfo() 4065 c.Assert(err, jc.ErrorIsNil) 4066 c.Assert(info.MongoSpaceName, gc.Equals, string(spaceName)) 4067 c.Assert(info.MongoSpaceState, gc.Equals, state.MongoSpaceValid) 4068 } 4069 4070 func (s *StateSuite) TestSetOrGetMongoSpaceNameDoesNotReplaceValidSpace(c *gc.C) { 4071 spaceName := network.SpaceName("foo") 4072 name, err := s.State.SetOrGetMongoSpaceName(spaceName) 4073 c.Assert(err, jc.ErrorIsNil) 4074 c.Assert(name, gc.Equals, spaceName) 4075 4076 name, err = s.State.SetOrGetMongoSpaceName(network.SpaceName("bar")) 4077 c.Assert(err, jc.ErrorIsNil) 4078 c.Assert(name, gc.Equals, spaceName) 4079 4080 info, err := s.State.ControllerInfo() 4081 c.Assert(err, jc.ErrorIsNil) 4082 c.Assert(info.MongoSpaceName, gc.Equals, string(spaceName)) 4083 c.Assert(info.MongoSpaceState, gc.Equals, state.MongoSpaceValid) 4084 } 4085 4086 func (s *StateSuite) TestSetMongoSpaceStateSetsValidStates(c *gc.C) { 4087 mongoStates := []state.MongoSpaceStates{ 4088 state.MongoSpaceUnknown, 4089 state.MongoSpaceValid, 4090 state.MongoSpaceInvalid, 4091 state.MongoSpaceUnsupported, 4092 } 4093 for _, st := range mongoStates { 4094 err := s.State.SetMongoSpaceState(st) 4095 c.Assert(err, jc.ErrorIsNil) 4096 info, err := s.State.ControllerInfo() 4097 c.Assert(err, jc.ErrorIsNil) 4098 c.Assert(info.MongoSpaceState, gc.Equals, st) 4099 } 4100 } 4101 4102 func (s *StateSuite) TestSetMongoSpaceStateErrorOnInvalidStates(c *gc.C) { 4103 err := s.State.SetMongoSpaceState(state.MongoSpaceStates("bad")) 4104 c.Assert(err, gc.ErrorMatches, "mongoSpaceState: bad not valid") 4105 info, err := s.State.ControllerInfo() 4106 c.Assert(err, jc.ErrorIsNil) 4107 c.Assert(info.MongoSpaceState, gc.Equals, state.MongoSpaceUnknown) 4108 } 4109 4110 type SetAdminMongoPasswordSuite struct { 4111 testing.BaseSuite 4112 } 4113 4114 var _ = gc.Suite(&SetAdminMongoPasswordSuite{}) 4115 4116 func setAdminPassword(c *gc.C, inst *gitjujutesting.MgoInstance, owner names.UserTag, password string) { 4117 session, err := inst.Dial() 4118 c.Assert(err, jc.ErrorIsNil) 4119 defer session.Close() 4120 err = mongo.SetAdminMongoPassword(session, owner.String(), password) 4121 c.Assert(err, jc.ErrorIsNil) 4122 } 4123 4124 func (s *SetAdminMongoPasswordSuite) TestSetAdminMongoPassword(c *gc.C) { 4125 inst := &gitjujutesting.MgoInstance{EnableAuth: true} 4126 err := inst.Start(testing.Certs) 4127 c.Assert(err, jc.ErrorIsNil) 4128 defer inst.DestroyWithLog() 4129 4130 // We need to make an admin user before we initialize the state 4131 // because in Mongo3.2 the localhost exception no longer has 4132 // permission to create indexes. 4133 // https://docs.mongodb.com/manual/core/security-users/#localhost-exception 4134 owner := names.NewLocalUserTag("initialize-admin") 4135 password := "huggies" 4136 setAdminPassword(c, inst, owner, password) 4137 4138 noAuthInfo := &mongo.MongoInfo{ 4139 Info: mongo.Info{ 4140 Addrs: []string{inst.Addr()}, 4141 CACert: testing.CACert, 4142 }, 4143 } 4144 authInfo := &mongo.MongoInfo{ 4145 Info: noAuthInfo.Info, 4146 Tag: owner, 4147 Password: password, 4148 } 4149 cfg := testing.ModelConfig(c) 4150 controllerCfg := testing.FakeControllerConfig() 4151 st, err := state.Initialize(state.InitializeParams{ 4152 Clock: clock.WallClock, 4153 ControllerConfig: controllerCfg, 4154 ControllerModelArgs: state.ModelArgs{ 4155 CloudName: "dummy", 4156 Owner: owner, 4157 Config: cfg, 4158 StorageProviderRegistry: storage.StaticProviderRegistry{}, 4159 }, 4160 CloudName: "dummy", 4161 Cloud: cloud.Cloud{ 4162 Type: "dummy", 4163 AuthTypes: []cloud.AuthType{cloud.EmptyAuthType}, 4164 }, 4165 MongoInfo: authInfo, 4166 MongoDialOpts: mongotest.DialOpts(), 4167 }) 4168 c.Assert(err, jc.ErrorIsNil) 4169 defer st.Close() 4170 4171 // Check that we can SetAdminMongoPassword to nothing when there's 4172 // no password currently set. 4173 err = st.SetAdminMongoPassword("") 4174 c.Assert(err, jc.ErrorIsNil) 4175 4176 err = st.SetAdminMongoPassword("foo") 4177 c.Assert(err, jc.ErrorIsNil) 4178 err = st.MongoSession().DB("admin").Login("admin", "foo") 4179 c.Assert(err, jc.ErrorIsNil) 4180 4181 err = tryOpenState(st.ModelTag(), st.ControllerTag(), noAuthInfo) 4182 c.Check(errors.Cause(err), jc.Satisfies, errors.IsUnauthorized) 4183 // note: collections are set up in arbitrary order, proximate cause of 4184 // failure may differ. 4185 c.Check(err, gc.ErrorMatches, `[^:]+: unauthorized mongo access: .*`) 4186 4187 passwordOnlyInfo := *noAuthInfo 4188 passwordOnlyInfo.Password = "foo" 4189 4190 // Under mongo 3.2 it's not possible to create collections and 4191 // indexes with no user - the localhost exception only permits 4192 // creating users. There were some checks for unsetting the 4193 // password and then creating the state in an older version of 4194 // this test, but they couldn't be made to work with 3.2. 4195 err = tryOpenState(st.ModelTag(), st.ControllerTag(), &passwordOnlyInfo) 4196 c.Assert(err, jc.ErrorIsNil) 4197 }