github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/state_test.go (about)

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