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