62
63
func (s *StateSuite) TestAddresses(c *gc.C) {
64
machines := make([]*state.Machine, 3)
65
machines[0], err = s.State.AddMachine("quantal", state.JobHostUnits)
66
c.Assert(err, gc.IsNil)
67
machines[1], err = s.State.AddMachine("quantal", state.JobManageState, state.JobHostUnits)
68
c.Assert(err, gc.IsNil)
69
machines[2], err = s.State.AddMachine("quantal", state.JobManageState)
65
machines := make([]*state.Machine, 4)
66
machines[0], err = s.State.AddMachine("quantal", state.JobManageEnviron, state.JobHostUnits)
67
c.Assert(err, gc.IsNil)
68
machines[1], err = s.State.AddMachine("quantal", state.JobHostUnits)
69
c.Assert(err, gc.IsNil)
70
err = s.State.EnsureAvailability(3, constraints.Value{}, "quantal")
71
c.Assert(err, gc.IsNil)
72
machines[2], err = s.State.Machine("2")
73
c.Assert(err, gc.IsNil)
74
machines[3], err = s.State.Machine("3")
70
75
c.Assert(err, gc.IsNil)
72
77
for i, m := range machines {
95
100
addrs, err := s.State.Addresses()
96
101
c.Assert(err, gc.IsNil)
97
c.Assert(addrs, gc.HasLen, 2)
102
c.Assert(addrs, gc.HasLen, 3)
98
103
c.Assert(addrs, jc.SameContents, []string{
99
fmt.Sprintf("10.0.0.1:%d", envConfig.StatePort()),
104
fmt.Sprintf("10.0.0.0:%d", envConfig.StatePort()),
100
105
fmt.Sprintf("10.0.0.2:%d", envConfig.StatePort()),
106
fmt.Sprintf("10.0.0.3:%d", envConfig.StatePort()),
103
109
addrs, err = s.State.APIAddresses()
104
110
c.Assert(err, gc.IsNil)
105
c.Assert(addrs, gc.HasLen, 2)
111
c.Assert(addrs, gc.HasLen, 3)
106
112
c.Assert(addrs, jc.SameContents, []string{
107
fmt.Sprintf("10.0.0.1:%d", envConfig.APIPort()),
113
fmt.Sprintf("10.0.0.0:%d", envConfig.APIPort()),
108
114
fmt.Sprintf("10.0.0.2:%d", envConfig.APIPort()),
115
fmt.Sprintf("10.0.0.3:%d", envConfig.APIPort()),
122
129
c.Assert(err2, jc.Satisfies, errors.IsNotFoundError)
132
func (s *StateSuite) dummyCharm(c *gc.C, curlOverride string) (ch charm.Charm, curl *charm.URL, bundleURL *url.URL, bundleSHA256 string) {
134
ch = testing.Charms.Dir("dummy")
135
if curlOverride != "" {
136
curl = charm.MustParseURL(curlOverride)
138
curl = charm.MustParseURL(
139
fmt.Sprintf("local:quantal/%s-%d", ch.Meta().Name, ch.Revision()),
142
bundleURL, err = url.Parse("http://bundles.testing.invalid/dummy-1")
143
c.Assert(err, gc.IsNil)
144
bundleSHA256 = "dummy-1-sha256"
145
return ch, curl, bundleURL, bundleSHA256
125
148
func (s *StateSuite) TestAddCharm(c *gc.C) {
126
149
// Check that adding charms from scratch works correctly.
127
ch := testing.Charms.Dir("dummy")
128
curl := charm.MustParseURL(
129
fmt.Sprintf("local:quantal/%s-%d", ch.Meta().Name, ch.Revision()),
131
bundleURL, err := url.Parse("http://bundles.testing.invalid/dummy-1")
132
c.Assert(err, gc.IsNil)
133
dummy, err := s.State.AddCharm(ch, curl, bundleURL, "dummy-1-sha256")
150
ch, curl, bundleURL, bundleSHA256 := s.dummyCharm(c, "")
151
dummy, err := s.State.AddCharm(ch, curl, bundleURL, bundleSHA256)
134
152
c.Assert(err, gc.IsNil)
135
153
c.Assert(dummy.URL().String(), gc.Equals, curl.String())
224
243
c.Assert(curl.Revision, gc.Equals, 1234)
246
func (s *StateSuite) TestPrepareStoreCharmUpload(c *gc.C) {
247
// First test the sanity checks.
248
sch, err := s.State.PrepareStoreCharmUpload(charm.MustParseURL("cs:quantal/dummy"))
249
c.Assert(err, gc.ErrorMatches, "expected charm URL with revision, got .*")
250
c.Assert(sch, gc.IsNil)
251
sch, err = s.State.PrepareStoreCharmUpload(charm.MustParseURL("local:quantal/dummy"))
252
c.Assert(err, gc.ErrorMatches, "expected charm URL with cs schema, got .*")
253
c.Assert(sch, gc.IsNil)
255
// No charm in state, so the call should respect given revision.
256
testCurl := charm.MustParseURL("cs:quantal/missing-123")
257
sch, err = s.State.PrepareStoreCharmUpload(testCurl)
258
c.Assert(err, gc.IsNil)
259
c.Assert(sch.URL(), gc.DeepEquals, testCurl)
260
c.Assert(sch.IsUploaded(), jc.IsFalse)
262
s.assertPendingCharmExists(c, sch.URL())
264
// Try adding it again with the same revision and ensure we get the same document.
265
schCopy, err := s.State.PrepareStoreCharmUpload(testCurl)
266
c.Assert(err, gc.IsNil)
267
c.Assert(sch, jc.DeepEquals, schCopy)
269
// Now add a charm and try again - we should get the same result
271
ch, curl, bundleURL, bundleSHA256 := s.dummyCharm(c, "cs:precise/dummy-2")
272
sch, err = s.State.AddCharm(ch, curl, bundleURL, bundleSHA256)
273
c.Assert(err, gc.IsNil)
274
schCopy, err = s.State.PrepareStoreCharmUpload(curl)
275
c.Assert(err, gc.IsNil)
276
c.Assert(sch, jc.DeepEquals, schCopy)
278
// Finally, try poking around the state with a placeholder and
279
// bundlesha256 to make sure we do the right thing.
280
curl = curl.WithRevision(999)
281
first := state.TransactionHook{
283
err := s.State.AddStoreCharmPlaceholder(curl)
284
c.Assert(err, gc.IsNil)
287
err := s.charms.RemoveId(curl)
288
c.Assert(err, gc.IsNil)
291
second := state.TransactionHook{
293
err := s.State.AddStoreCharmPlaceholder(curl)
294
c.Assert(err, gc.IsNil)
297
err := s.charms.UpdateId(curl, D{{"$set", D{
298
{"bundlesha256", "fake"}},
300
c.Assert(err, gc.IsNil)
303
defer state.SetTransactionHooks(
304
c, s.State, first, second, first,
307
_, err = s.State.PrepareStoreCharmUpload(curl)
308
c.Assert(err, gc.Equals, state.ErrExcessiveContention)
227
311
func (s *StateSuite) TestUpdateUploadedCharm(c *gc.C) {
228
ch := testing.Charms.Dir("dummy")
229
curl := charm.MustParseURL(
230
fmt.Sprintf("local:quantal/%s-%d", ch.Meta().Name, ch.Revision()),
232
bundleURL, err := url.Parse("http://bundles.testing.invalid/dummy-1")
233
c.Assert(err, gc.IsNil)
234
_, err = s.State.AddCharm(ch, curl, bundleURL, "dummy-1-sha256")
312
ch, curl, bundleURL, bundleSHA256 := s.dummyCharm(c, "")
313
_, err := s.State.AddCharm(ch, curl, bundleURL, bundleSHA256)
235
314
c.Assert(err, gc.IsNil)
237
// First test with already uploaded and a missing charms.
238
sch, err := s.State.UpdateUploadedCharm(ch, curl, bundleURL, "dummy-1-sha256")
316
// Test with already uploaded and a missing charms.
317
sch, err := s.State.UpdateUploadedCharm(ch, curl, bundleURL, bundleSHA256)
239
318
c.Assert(err, gc.ErrorMatches, fmt.Sprintf("charm %q already uploaded", curl))
240
319
c.Assert(sch, gc.IsNil)
241
320
missingCurl := charm.MustParseURL("local:quantal/missing-1")
421
498
c.Assert(m.Jobs(), gc.DeepEquals, jobs)
422
499
s.assertMachineContainers(c, m, nil)
424
check(m0, "0", "quantal", oneJob)
501
check(m0, "0", "quantal", allJobs)
425
502
m0, err = s.State.Machine("0")
426
503
c.Assert(err, gc.IsNil)
427
check(m0, "0", "quantal", oneJob)
504
check(m0, "0", "quantal", allJobs)
429
allJobs := []state.MachineJob{
431
state.JobManageEnviron,
432
state.JobManageState,
434
m1, err := s.State.AddMachine("blahblah", allJobs...)
506
oneJob := []state.MachineJob{state.JobHostUnits}
507
m1, err := s.State.AddMachine("blahblah", oneJob...)
435
508
c.Assert(err, gc.IsNil)
436
check(m1, "1", "blahblah", allJobs)
509
check(m1, "1", "blahblah", oneJob)
438
511
m1, err = s.State.Machine("1")
439
512
c.Assert(err, gc.IsNil)
440
check(m1, "1", "blahblah", allJobs)
513
check(m1, "1", "blahblah", oneJob)
442
515
m, err := s.State.AllMachines()
443
516
c.Assert(err, gc.IsNil)
444
517
c.Assert(m, gc.HasLen, 2)
445
check(m[0], "0", "quantal", oneJob)
446
check(m[1], "1", "blahblah", allJobs)
518
check(m[0], "0", "quantal", allJobs)
519
check(m[1], "1", "blahblah", oneJob)
522
func (s *StateSuite) TestAddMachines(c *gc.C) {
523
oneJob := []state.MachineJob{state.JobHostUnits}
524
cons := constraints.MustParse("mem=4G")
525
hc := instance.MustParseHardware("mem=2G")
526
machineTemplate := state.MachineTemplate{
529
HardwareCharacteristics: hc,
530
InstanceId: "inst-id",
534
machines, err := s.State.AddMachines(machineTemplate)
535
c.Assert(err, gc.IsNil)
536
c.Assert(machines, gc.HasLen, 1)
537
m, err := s.State.Machine(machines[0].Id())
538
c.Assert(err, gc.IsNil)
539
instId, err := m.InstanceId()
540
c.Assert(err, gc.IsNil)
541
c.Assert(string(instId), gc.Equals, "inst-id")
542
c.Assert(m.CheckProvisioned("nonce"), jc.IsTrue)
543
c.Assert(m.Series(), gc.Equals, "precise")
544
mcons, err := m.Constraints()
545
c.Assert(err, gc.IsNil)
546
c.Assert(mcons, gc.DeepEquals, cons)
547
mhc, err := m.HardwareCharacteristics()
548
c.Assert(err, gc.IsNil)
549
c.Assert(*mhc, gc.DeepEquals, hc)
550
// Clear the deprecated machineDoc InstanceId attribute and do it again.
551
// still works as expected with the new data model.
552
state.SetMachineInstanceId(m, "")
553
instId, err = m.InstanceId()
554
c.Assert(err, gc.IsNil)
555
c.Assert(string(instId), gc.Equals, "inst-id")
449
558
func (s *StateSuite) TestAddMachinesEnvironmentDying(c *gc.C) {
767
876
s.assertMachineContainers(c, m0, []string{"0/lxc/0", "0/lxc/1"})
879
func (s *StateSuite) TestAddMachineCanOnlyAddStateServerForMachine0(c *gc.C) {
880
template := state.MachineTemplate{
882
Jobs: []state.MachineJob{state.JobManageEnviron},
884
// Check that we can add the bootstrap machine.
885
m, err := s.State.AddOneMachine(template)
886
c.Assert(err, gc.IsNil)
887
c.Assert(m.Id(), gc.Equals, "0")
888
c.Assert(m.WantsVote(), jc.IsTrue)
889
c.Assert(m.Jobs(), gc.DeepEquals, []state.MachineJob{state.JobManageEnviron})
891
// Check that the state server information is correct.
892
info, err := s.State.StateServerInfo()
893
c.Assert(err, gc.IsNil)
894
c.Assert(info.MachineIds, gc.DeepEquals, []string{"0"})
895
c.Assert(info.VotingMachineIds, gc.DeepEquals, []string{"0"})
897
const errCannotAdd = "cannot add a new machine: state server jobs specified without calling EnsureAvailability"
898
m, err = s.State.AddOneMachine(template)
899
c.Assert(err, gc.ErrorMatches, errCannotAdd)
901
m, err = s.State.AddMachineInsideMachine(template, "0", instance.LXC)
902
c.Assert(err, gc.ErrorMatches, errCannotAdd)
904
m, err = s.State.AddMachineInsideNewMachine(template, template, instance.LXC)
905
c.Assert(err, gc.ErrorMatches, errCannotAdd)
770
908
func (s *StateSuite) TestReadMachine(c *gc.C) {
771
909
machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
772
910
c.Assert(err, gc.IsNil)
2480
func (s *StateSuite) TestStateServerMachineIds(c *gc.C) {
2481
ids, err := state.StateServerMachineIds(s.State)
2618
func (s *StateSuite) TestStateServerInfo(c *gc.C) {
2619
ids, err := s.State.StateServerInfo()
2482
2620
c.Assert(err, gc.IsNil)
2483
c.Assert(ids, gc.HasLen, 0)
2621
c.Assert(ids.MachineIds, gc.HasLen, 0)
2622
c.Assert(ids.VotingMachineIds, gc.HasLen, 0)
2485
2624
// TODO(rog) more testing here when we can actually add
2486
2625
// state servers.
2489
2628
func (s *StateSuite) TestOpenCreatesStateServersDoc(c *gc.C) {
2490
_, err := s.State.AddMachine("quantal", state.JobHostUnits)
2491
c.Assert(err, gc.IsNil)
2492
m1, err := s.State.AddMachine("quantal", state.JobHostUnits, state.JobManageState)
2493
c.Assert(err, gc.IsNil)
2494
m2, err := s.State.AddMachine("quantal", state.JobManageEnviron, state.JobManageState)
2629
m0, err := s.State.AddMachine("quantal", state.JobHostUnits, state.JobManageEnviron)
2495
2630
c.Assert(err, gc.IsNil)
2497
2632
// Delete the stateServers collection to pretend this
2501
2636
c.Assert(err, gc.IsNil)
2503
2638
// Sanity check that we have in fact deleted the right info.
2504
ids, err := state.StateServerMachineIds(s.State)
2639
info, err := s.State.StateServerInfo()
2505
2640
c.Assert(err, gc.NotNil)
2506
c.Assert(ids, gc.HasLen, 0)
2508
st, err := state.Open(state.TestingStateInfo(), state.TestingDialOpts())
2509
c.Assert(err, gc.IsNil)
2512
expectIds := []string{m1.Id(), m2.Id()}
2513
sort.Strings(expectIds)
2514
ids, err = state.StateServerMachineIds(st)
2515
c.Assert(err, gc.IsNil)
2641
c.Assert(info, gc.IsNil)
2643
st, err := state.Open(state.TestingStateInfo(), state.TestingDialOpts())
2644
c.Assert(err, gc.IsNil)
2647
expectIds := []string{m0.Id()}
2648
expectStateServerInfo := &state.StateServerInfo{
2649
MachineIds: expectIds,
2650
VotingMachineIds: expectIds,
2652
info, err = st.StateServerInfo()
2653
c.Assert(err, gc.IsNil)
2654
c.Assert(info, gc.DeepEquals, expectStateServerInfo)
2657
func (s *StateSuite) TestReopenWithNoMachines(c *gc.C) {
2658
info, err := s.State.StateServerInfo()
2659
c.Assert(err, gc.IsNil)
2660
c.Assert(info, jc.DeepEquals, &state.StateServerInfo{})
2662
st, err := state.Open(state.TestingStateInfo(), state.TestingDialOpts())
2663
c.Assert(err, gc.IsNil)
2666
info, err = s.State.StateServerInfo()
2667
c.Assert(err, gc.IsNil)
2668
c.Assert(info, jc.DeepEquals, &state.StateServerInfo{})
2671
func (s *StateSuite) TestOpenReplacesOldStateServersDoc(c *gc.C) {
2672
m0, err := s.State.AddMachine("quantal", state.JobHostUnits, state.JobManageEnviron)
2673
c.Assert(err, gc.IsNil)
2675
// Clear the voting machine ids from the stateServers collection
2676
// to pretend this is a semi-old environment that had
2677
// created the collection but not the voting ids.
2678
_, err = s.stateServers.UpdateAll(nil, bson.D{{
2681
{"votingmachineids", nil},
2682
{"machineids", nil},
2685
c.Assert(err, gc.IsNil)
2687
// Sanity check that they have actually been removed.
2688
info, err := s.State.StateServerInfo()
2689
c.Assert(err, gc.IsNil)
2690
c.Assert(info.MachineIds, gc.HasLen, 0)
2691
c.Assert(info.VotingMachineIds, gc.HasLen, 0)
2693
st, err := state.Open(state.TestingStateInfo(), state.TestingDialOpts())
2694
c.Assert(err, gc.IsNil)
2697
info, err = s.State.StateServerInfo()
2698
c.Assert(err, gc.IsNil)
2699
expectIds := []string{m0.Id()}
2700
c.Assert(info, gc.DeepEquals, &state.StateServerInfo{
2701
MachineIds: expectIds,
2702
VotingMachineIds: expectIds,
2706
func (s *StateSuite) TestEnsureAvailabilityFailsWithBadCount(c *gc.C) {
2707
for _, n := range []int{-1, 0, 2, 6} {
2708
err := s.State.EnsureAvailability(n, constraints.Value{}, "")
2709
c.Assert(err, gc.ErrorMatches, "number of state servers must be odd and greater than zero")
2711
err := s.State.EnsureAvailability(replicaset.MaxPeers+2, constraints.Value{}, "")
2712
c.Assert(err, gc.ErrorMatches, `state server count is too large \(allowed \d+\)`)
2715
func (s *StateSuite) TestEnsureAvailabilityAddsNewMachines(c *gc.C) {
2716
ids := make([]string, 3)
2717
m0, err := s.State.AddMachine("quantal", state.JobHostUnits, state.JobManageEnviron)
2718
c.Assert(err, gc.IsNil)
2721
// Add a non-state-server machine just to make sure.
2722
_, err = s.State.AddMachine("quantal", state.JobHostUnits)
2723
c.Assert(err, gc.IsNil)
2725
info, err := s.State.StateServerInfo()
2726
c.Assert(err, gc.IsNil)
2727
c.Assert(info, gc.DeepEquals, &state.StateServerInfo{
2728
MachineIds: []string{m0.Id()},
2729
VotingMachineIds: []string{m0.Id()},
2732
cons := constraints.Value{
2733
Mem: newUint64(100),
2735
err = s.State.EnsureAvailability(3, cons, "quantal")
2736
c.Assert(err, gc.IsNil)
2738
for i := 1; i < 3; i++ {
2739
m, err := s.State.Machine(fmt.Sprint(i + 1))
2740
c.Assert(err, gc.IsNil)
2741
c.Assert(m.Jobs(), gc.DeepEquals, []state.MachineJob{
2743
state.JobManageEnviron,
2745
gotCons, err := m.Constraints()
2746
c.Assert(err, gc.IsNil)
2747
c.Assert(gotCons, gc.DeepEquals, cons)
2748
c.Assert(m.WantsVote(), jc.IsTrue)
2516
2751
sort.Strings(ids)
2517
c.Assert(ids, gc.DeepEquals, expectIds)
2519
// Check that it works with the original connection too.
2520
ids, err = state.StateServerMachineIds(s.State)
2753
info, err = s.State.StateServerInfo()
2521
2754
c.Assert(err, gc.IsNil)
2522
c.Assert(ids, gc.DeepEquals, expectIds)
2755
sort.Strings(info.MachineIds)
2756
sort.Strings(info.VotingMachineIds)
2757
c.Assert(info, gc.DeepEquals, &state.StateServerInfo{
2759
VotingMachineIds: ids,
2763
func newUint64(i uint64) *uint64 {