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

     1  // Copyright 2012-2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // Package state enables reading, observing, and changing
     5  // the state stored in MongoDB of a whole model
     6  // managed by juju.
     7  package state
     8  
     9  import (
    10  	"fmt"
    11  	"regexp"
    12  	"sort"
    13  	"strconv"
    14  	"strings"
    15  	"sync"
    16  	"time"
    17  
    18  	"github.com/juju/errors"
    19  	"github.com/juju/loggo"
    20  	jujutxn "github.com/juju/txn"
    21  	"github.com/juju/utils"
    22  	"github.com/juju/utils/clock"
    23  	"github.com/juju/utils/os"
    24  	"github.com/juju/utils/series"
    25  	"github.com/juju/utils/set"
    26  	"github.com/juju/version"
    27  	"gopkg.in/juju/charm.v6-unstable"
    28  	csparams "gopkg.in/juju/charmrepo.v2-unstable/csclient/params"
    29  	"gopkg.in/juju/names.v2"
    30  	"gopkg.in/mgo.v2"
    31  	"gopkg.in/mgo.v2/bson"
    32  	"gopkg.in/mgo.v2/txn"
    33  
    34  	"github.com/juju/juju/apiserver/params"
    35  	"github.com/juju/juju/audit"
    36  	"github.com/juju/juju/constraints"
    37  	"github.com/juju/juju/core/lease"
    38  	"github.com/juju/juju/instance"
    39  	"github.com/juju/juju/mongo"
    40  	"github.com/juju/juju/network"
    41  	"github.com/juju/juju/permission"
    42  	"github.com/juju/juju/state/cloudimagemetadata"
    43  	stateaudit "github.com/juju/juju/state/internal/audit"
    44  	statelease "github.com/juju/juju/state/lease"
    45  	"github.com/juju/juju/state/workers"
    46  	"github.com/juju/juju/status"
    47  	jujuversion "github.com/juju/juju/version"
    48  )
    49  
    50  var logger = loggo.GetLogger("juju.state")
    51  
    52  const (
    53  	// jujuDB is the name of the main juju database.
    54  	jujuDB = "juju"
    55  
    56  	// presenceDB is the name of the database used to hold presence pinger data.
    57  	presenceDB = "presence"
    58  	presenceC  = "presence"
    59  
    60  	// blobstoreDB is the name of the blobstore GridFS database.
    61  	blobstoreDB = "blobstore"
    62  
    63  	// applicationLeadershipNamespace is the name of the lease.Client namespace
    64  	// used by the leadership manager.
    65  	applicationLeadershipNamespace = "application-leadership"
    66  
    67  	// singularControllerNamespace is the name of the lease.Client namespace
    68  	// used by the singular manager
    69  	singularControllerNamespace = "singular-controller"
    70  )
    71  
    72  type providerIdDoc struct {
    73  	ID string `bson:"_id"` // format: "<model-uuid>:<global-key>:<provider-id>"
    74  }
    75  
    76  // State represents the state of an model
    77  // managed by juju.
    78  type State struct {
    79  	clock              clock.Clock
    80  	modelTag           names.ModelTag
    81  	controllerModelTag names.ModelTag
    82  	controllerTag      names.ControllerTag
    83  	mongoInfo          *mongo.MongoInfo
    84  	session            *mgo.Session
    85  	database           Database
    86  	policy             Policy
    87  	newPolicy          NewPolicyFunc
    88  
    89  	// cloudName is the name of the cloud on which the model
    90  	// represented by this state runs.
    91  	cloudName string
    92  
    93  	// leaseClientId is used by the lease infrastructure to
    94  	// differentiate between machines whose clocks may be
    95  	// relatively-skewed.
    96  	leaseClientId string
    97  
    98  	// workers is responsible for keeping the various sub-workers
    99  	// available by starting new ones as they fail. It doesn't do
   100  	// that yet, but having a type that collects them together is the
   101  	// first step.
   102  	//
   103  	// note that the allManager stuff below probably ought to be
   104  	// folded in as well, but that feels like its own task.
   105  	workers workers.Workers
   106  
   107  	// mu guards allManager, allModelManager & allModelWatcherBacking
   108  	mu                     sync.Mutex
   109  	allManager             *storeManager
   110  	allModelManager        *storeManager
   111  	allModelWatcherBacking Backing
   112  
   113  	// TODO(anastasiamac 2015-07-16) As state gets broken up, remove this.
   114  	CloudImageMetadataStorage cloudimagemetadata.Storage
   115  }
   116  
   117  // StateServingInfo holds information needed by a controller.
   118  // This type is a copy of the type of the same name from the api/params package.
   119  // It is replicated here to avoid the state pacakge depending on api/params.
   120  //
   121  // NOTE(fwereade): the api/params type exists *purely* for representing
   122  // this data over the wire, and has a legitimate reason to exist. This
   123  // type does not: it's non-implementation-specific and shoudl be defined
   124  // under core/ somewhere, so it can be used both here and in the agent
   125  // without dragging unnecessary/irrelevant packages into scope.
   126  type StateServingInfo struct {
   127  	APIPort      int
   128  	StatePort    int
   129  	Cert         string
   130  	PrivateKey   string
   131  	CAPrivateKey string
   132  	// this will be passed as the KeyFile argument to MongoDB
   133  	SharedSecret   string
   134  	SystemIdentity string
   135  }
   136  
   137  // IsController returns true if this state instance has the bootstrap
   138  // model UUID.
   139  func (st *State) IsController() bool {
   140  	return st.modelTag == st.controllerModelTag
   141  }
   142  
   143  // ControllerUUID returns the UUID for the controller
   144  // of this state instance.
   145  func (st *State) ControllerUUID() string {
   146  	return st.controllerTag.Id()
   147  }
   148  func (st *State) ControllerTag() names.ControllerTag {
   149  	return st.controllerTag
   150  }
   151  
   152  func ControllerAccess(st *State, tag names.Tag) (permission.UserAccess, error) {
   153  	return st.UserAccess(tag.(names.UserTag), st.controllerTag)
   154  }
   155  
   156  // RemoveAllModelDocs removes all documents from multi-model
   157  // collections. The model should be put into a dying state before call
   158  // this method. Otherwise, there is a race condition in which collections
   159  // could be added to during or after the running of this method.
   160  func (st *State) RemoveAllModelDocs() error {
   161  	err := st.removeAllModelDocs(bson.D{{"life", Dead}})
   162  	if errors.Cause(err) == txn.ErrAborted {
   163  		return errors.New("can't remove model: model not dead")
   164  	}
   165  	return errors.Trace(err)
   166  }
   167  
   168  // RemoveImportingModelDocs removes all documents from multi-model collections
   169  // for the current model. This method asserts that the model's migration mode
   170  // is "importing".
   171  func (st *State) RemoveImportingModelDocs() error {
   172  	err := st.removeAllModelDocs(bson.D{{"migration-mode", MigrationModeImporting}})
   173  	if errors.Cause(err) == txn.ErrAborted {
   174  		return errors.New("can't remove model: model not being imported for migration")
   175  	}
   176  	return errors.Trace(err)
   177  }
   178  
   179  // RemoveExportingModelDocs removes all documents from multi-model collections
   180  // for the current model. This method asserts that the model's migration mode
   181  // is "exporting".
   182  func (st *State) RemoveExportingModelDocs() error {
   183  	err := st.removeAllModelDocs(bson.D{{"migration-mode", MigrationModeExporting}})
   184  	if errors.Cause(err) == txn.ErrAborted {
   185  		return errors.New("can't remove model: model not being exported for migration")
   186  	}
   187  	return errors.Trace(err)
   188  }
   189  
   190  func (st *State) removeAllModelDocs(modelAssertion bson.D) error {
   191  	modelUUID := st.ModelUUID()
   192  
   193  	// Remove each collection in its own transaction.
   194  	for name, info := range st.database.Schema() {
   195  		if info.global || info.rawAccess {
   196  			continue
   197  		}
   198  
   199  		ops, err := st.removeAllInCollectionOps(name)
   200  		if err != nil {
   201  			return errors.Trace(err)
   202  		}
   203  		// Make sure we gate everything on the model assertion.
   204  		ops = append([]txn.Op{{
   205  			C:      modelsC,
   206  			Id:     modelUUID,
   207  			Assert: modelAssertion,
   208  		}}, ops...)
   209  		err = st.runTransaction(ops)
   210  		if err != nil {
   211  			return errors.Trace(err)
   212  		}
   213  	}
   214  
   215  	// Remove from the raw (non-transactional) collections.
   216  	for name, info := range st.database.Schema() {
   217  		if !info.global && info.rawAccess {
   218  			if err := st.removeAllInCollectionRaw(name); err != nil {
   219  				return errors.Trace(err)
   220  			}
   221  		}
   222  	}
   223  
   224  	// Remove all user permissions for the model.
   225  	permPattern := bson.M{
   226  		"_id": bson.M{"$regex": "^" + permissionID(modelKey(modelUUID), "")},
   227  	}
   228  	ops, err := st.removeInCollectionOps(permissionsC, permPattern)
   229  	if err != nil {
   230  		return errors.Trace(err)
   231  	}
   232  	err = st.runTransaction(ops)
   233  	if err != nil {
   234  		return errors.Trace(err)
   235  	}
   236  
   237  	// Now remove remove the model.
   238  	env, err := st.Model()
   239  	if err != nil {
   240  		return errors.Trace(err)
   241  	}
   242  	id := userModelNameIndex(env.Owner().Canonical(), env.Name())
   243  	ops = []txn.Op{{
   244  		// Cleanup the owner:envName unique key.
   245  		C:      usermodelnameC,
   246  		Id:     id,
   247  		Remove: true,
   248  	}, {
   249  		C:      modelEntityRefsC,
   250  		Id:     modelUUID,
   251  		Remove: true,
   252  	}, {
   253  		C:      modelsC,
   254  		Id:     modelUUID,
   255  		Assert: modelAssertion,
   256  		Remove: true,
   257  	}}
   258  	if !st.IsController() {
   259  		ops = append(ops, decHostedModelCountOp())
   260  	}
   261  	return st.runTransaction(ops)
   262  }
   263  
   264  // removeAllInCollectionRaw removes all the documents from the given
   265  // named collection.
   266  func (st *State) removeAllInCollectionRaw(name string) error {
   267  	coll, closer := st.getCollection(name)
   268  	defer closer()
   269  	_, err := coll.Writeable().RemoveAll(nil)
   270  	return errors.Trace(err)
   271  }
   272  
   273  // removeAllInCollectionOps appends to ops operations to
   274  // remove all the documents in the given named collection.
   275  func (st *State) removeAllInCollectionOps(name string) ([]txn.Op, error) {
   276  	return st.removeInCollectionOps(name, nil)
   277  }
   278  
   279  // removeInCollectionOps generates operations to remove all documents
   280  // from the named collection matching a specific selector.
   281  func (st *State) removeInCollectionOps(name string, sel interface{}) ([]txn.Op, error) {
   282  	coll, closer := st.getCollection(name)
   283  	defer closer()
   284  
   285  	var ids []bson.M
   286  	err := coll.Find(sel).Select(bson.D{{"_id", 1}}).All(&ids)
   287  	if err != nil {
   288  		return nil, errors.Trace(err)
   289  	}
   290  	var ops []txn.Op
   291  	for _, id := range ids {
   292  		ops = append(ops, txn.Op{
   293  			C:      name,
   294  			Id:     id["_id"],
   295  			Remove: true,
   296  		})
   297  	}
   298  	return ops, nil
   299  }
   300  
   301  // ForModel returns a connection to mongo for the specified model. The
   302  // connection uses the same credentials and policy as the existing connection.
   303  func (st *State) ForModel(modelTag names.ModelTag) (*State, error) {
   304  	session := st.session.Copy()
   305  	newSt, err := newState(
   306  		modelTag, st.controllerModelTag, session, st.mongoInfo, st.newPolicy, st.clock,
   307  	)
   308  	if err != nil {
   309  		return nil, errors.Trace(err)
   310  	}
   311  	if err := newSt.start(st.controllerTag); err != nil {
   312  		return nil, errors.Trace(err)
   313  	}
   314  	return newSt, nil
   315  }
   316  
   317  // start makes a *State functional post-creation, by:
   318  //   * setting controllerTag, cloudName and leaseClientId
   319  //   * starting lease managers and watcher backends
   320  //   * creating cloud metadata storage
   321  //
   322  // start will close the *State if it fails.
   323  func (st *State) start(controllerTag names.ControllerTag) (err error) {
   324  	defer func() {
   325  		if err == nil {
   326  			return
   327  		}
   328  		if err2 := st.Close(); err2 != nil {
   329  			logger.Errorf("closing State for %s: %v", st.modelTag, err2)
   330  		}
   331  	}()
   332  
   333  	st.controllerTag = controllerTag
   334  
   335  	if identity := st.mongoInfo.Tag; identity != nil {
   336  		// TODO(fwereade): it feels a bit wrong to take this from MongoInfo -- I
   337  		// think it's just coincidental that the mongodb user happens to map to
   338  		// the machine that's executing the code -- but there doesn't seem to be
   339  		// an accessible alternative.
   340  		st.leaseClientId = identity.String()
   341  	} else {
   342  		// If we're running state anonymously, we can still use the lease
   343  		// manager; but we need to make sure we use a unique client ID, and
   344  		// will thus not be very performant.
   345  		logger.Infof("running state anonymously; using unique client id")
   346  		uuid, err := utils.NewUUID()
   347  		if err != nil {
   348  			return errors.Trace(err)
   349  		}
   350  		st.leaseClientId = fmt.Sprintf("anon-%s", uuid.String())
   351  	}
   352  	// now we've set up leaseClientId, we can use workersFactory
   353  
   354  	logger.Infof("starting standard state workers")
   355  	factory := workersFactory{
   356  		st:    st,
   357  		clock: st.clock,
   358  	}
   359  	workers, err := workers.NewRestartWorkers(workers.RestartConfig{
   360  		Factory: factory,
   361  		Logger:  loggo.GetLogger(logger.Name() + ".workers"),
   362  		Clock:   st.clock,
   363  		Delay:   time.Second,
   364  	})
   365  	if err != nil {
   366  		return errors.Annotatef(err, "cannot create standard state workers")
   367  	}
   368  	st.workers = workers
   369  
   370  	logger.Infof("creating cloud image metadata storage")
   371  	st.CloudImageMetadataStorage = cloudimagemetadata.NewStorage(
   372  		cloudimagemetadataC,
   373  		&environMongo{st},
   374  	)
   375  
   376  	logger.Infof("started state for %s successfully", st.modelTag)
   377  	return nil
   378  }
   379  
   380  // ApplicationLeaders returns a map of the application name to the
   381  // unit name that is the current leader.
   382  func (st *State) ApplicationLeaders() (map[string]string, error) {
   383  	client, err := st.getLeadershipLeaseClient()
   384  	if err != nil {
   385  		return nil, errors.Trace(err)
   386  	}
   387  	leases := client.Leases()
   388  	result := make(map[string]string, len(leases))
   389  	for key, value := range leases {
   390  		result[key] = value.Holder
   391  	}
   392  	return result, nil
   393  }
   394  
   395  func (st *State) getLeadershipLeaseClient() (lease.Client, error) {
   396  	client, err := statelease.NewClient(statelease.ClientConfig{
   397  		Id:         st.leaseClientId,
   398  		Namespace:  applicationLeadershipNamespace,
   399  		Collection: leasesC,
   400  		Mongo:      &environMongo{st},
   401  		Clock:      st.clock,
   402  	})
   403  	if err != nil {
   404  		return nil, errors.Annotatef(err, "cannot create leadership lease client")
   405  	}
   406  	return client, nil
   407  }
   408  
   409  func (st *State) getSingularLeaseClient() (lease.Client, error) {
   410  	client, err := statelease.NewClient(statelease.ClientConfig{
   411  		Id:         st.leaseClientId,
   412  		Namespace:  singularControllerNamespace,
   413  		Collection: leasesC,
   414  		Mongo:      &environMongo{st},
   415  		Clock:      st.clock,
   416  	})
   417  	if err != nil {
   418  		return nil, errors.Annotatef(err, "cannot create singular lease client")
   419  	}
   420  	return client, nil
   421  }
   422  
   423  // ModelTag() returns the model tag for the model controlled by
   424  // this state instance.
   425  func (st *State) ModelTag() names.ModelTag {
   426  	return st.modelTag
   427  }
   428  
   429  // ModelUUID returns the model UUID for the model
   430  // controlled by this state instance.
   431  func (st *State) ModelUUID() string {
   432  	return st.modelTag.Id()
   433  }
   434  
   435  // userModelNameIndex returns a string to be used as a usermodelnameC unique index.
   436  func userModelNameIndex(username, envName string) string {
   437  	return strings.ToLower(username) + ":" + envName
   438  }
   439  
   440  // EnsureModelRemoved returns an error if any multi-model
   441  // documents for this model are found. It is intended only to be used in
   442  // tests and exported so it can be used in the tests of other packages.
   443  func (st *State) EnsureModelRemoved() error {
   444  	found := map[string]int{}
   445  	var foundOrdered []string
   446  	for name, info := range st.database.Schema() {
   447  		if info.global {
   448  			continue
   449  		}
   450  		coll, closer := st.getCollection(name)
   451  		defer closer()
   452  		n, err := coll.Find(nil).Count()
   453  		if err != nil {
   454  			return errors.Trace(err)
   455  		}
   456  		if n != 0 {
   457  			found[name] = n
   458  			foundOrdered = append(foundOrdered, name)
   459  		}
   460  	}
   461  
   462  	if len(found) != 0 {
   463  		errMessage := fmt.Sprintf("found documents for model with uuid %s:", st.ModelUUID())
   464  		sort.Strings(foundOrdered)
   465  		for _, name := range foundOrdered {
   466  			number := found[name]
   467  			errMessage += fmt.Sprintf(" %d %s doc,", number, name)
   468  		}
   469  		// Remove trailing comma.
   470  		errMessage = errMessage[:len(errMessage)-1]
   471  		return errors.New(errMessage)
   472  	}
   473  	return nil
   474  }
   475  
   476  // getPresenceCollection returns the raw mongodb presence collection,
   477  // which is needed to interact with the state/presence package.
   478  func (st *State) getPresenceCollection() *mgo.Collection {
   479  	return st.session.DB(presenceDB).C(presenceC)
   480  }
   481  
   482  // getTxnLogCollection returns the raw mongodb txns collection, which is
   483  // needed to interact with the state/watcher package.
   484  func (st *State) getTxnLogCollection() *mgo.Collection {
   485  	return st.session.DB(jujuDB).C(txnLogC)
   486  }
   487  
   488  // newDB returns a database connection using a new session, along with
   489  // a closer function for the session. This is useful where you need to work
   490  // with various collections in a single session, so don't want to call
   491  // getCollection multiple times.
   492  func (st *State) newDB() (Database, func()) {
   493  	return st.database.Copy()
   494  }
   495  
   496  // Ping probes the state's database connection to ensure
   497  // that it is still alive.
   498  func (st *State) Ping() error {
   499  	return st.session.Ping()
   500  }
   501  
   502  // MongoVersion return the string repre
   503  func (st *State) MongoVersion() (string, error) {
   504  	binfo, err := st.session.BuildInfo()
   505  	if err != nil {
   506  		return "", errors.Annotate(err, "cannot obtain mongo build info")
   507  	}
   508  	return binfo.Version, nil
   509  }
   510  
   511  // MongoSession returns the underlying mongodb session
   512  // used by the state. It is exposed so that external code
   513  // can maintain the mongo replica set and should not
   514  // otherwise be used.
   515  func (st *State) MongoSession() *mgo.Session {
   516  	return st.session
   517  }
   518  
   519  func (st *State) Watch() *Multiwatcher {
   520  	st.mu.Lock()
   521  	if st.allManager == nil {
   522  		st.allManager = newStoreManager(newAllWatcherStateBacking(st))
   523  	}
   524  	st.mu.Unlock()
   525  	return NewMultiwatcher(st.allManager)
   526  }
   527  
   528  func (st *State) WatchAllModels() *Multiwatcher {
   529  	st.mu.Lock()
   530  	if st.allModelManager == nil {
   531  		st.allModelWatcherBacking = NewAllModelWatcherStateBacking(st)
   532  		st.allModelManager = newStoreManager(st.allModelWatcherBacking)
   533  	}
   534  	st.mu.Unlock()
   535  	return NewMultiwatcher(st.allModelManager)
   536  }
   537  
   538  // versionInconsistentError indicates one or more agents have a
   539  // different version from the current one (even empty, when not yet
   540  // set).
   541  type versionInconsistentError struct {
   542  	currentVersion version.Number
   543  	agents         []string
   544  }
   545  
   546  func (e *versionInconsistentError) Error() string {
   547  	sort.Strings(e.agents)
   548  	return fmt.Sprintf("some agents have not upgraded to the current model version %s: %s", e.currentVersion, strings.Join(e.agents, ", "))
   549  }
   550  
   551  // newVersionInconsistentError returns a new instance of
   552  // versionInconsistentError.
   553  func newVersionInconsistentError(currentVersion version.Number, agents []string) *versionInconsistentError {
   554  	return &versionInconsistentError{currentVersion, agents}
   555  }
   556  
   557  // IsVersionInconsistentError returns if the given error is
   558  // versionInconsistentError.
   559  func IsVersionInconsistentError(e interface{}) bool {
   560  	value := e
   561  	// In case of a wrapped error, check the cause first.
   562  	cause := errors.Cause(e.(error))
   563  	if cause != nil {
   564  		value = cause
   565  	}
   566  	_, ok := value.(*versionInconsistentError)
   567  	return ok
   568  }
   569  
   570  func (st *State) checkCanUpgrade(currentVersion, newVersion string) error {
   571  	matchCurrent := "^" + regexp.QuoteMeta(currentVersion) + "-"
   572  	matchNew := "^" + regexp.QuoteMeta(newVersion) + "-"
   573  	// Get all machines and units with a different or empty version.
   574  	sel := bson.D{{"$or", []bson.D{
   575  		{{"tools", bson.D{{"$exists", false}}}},
   576  		{{"$and", []bson.D{
   577  			{{"tools.version", bson.D{{"$not", bson.RegEx{matchCurrent, ""}}}}},
   578  			{{"tools.version", bson.D{{"$not", bson.RegEx{matchNew, ""}}}}},
   579  		}}},
   580  	}}}
   581  	var agentTags []string
   582  	for _, name := range []string{machinesC, unitsC} {
   583  		collection, closer := st.getCollection(name)
   584  		defer closer()
   585  		var doc struct {
   586  			DocID string `bson:"_id"`
   587  		}
   588  		iter := collection.Find(sel).Select(bson.D{{"_id", 1}}).Iter()
   589  		for iter.Next(&doc) {
   590  			localID, err := st.strictLocalID(doc.DocID)
   591  			if err != nil {
   592  				return errors.Trace(err)
   593  			}
   594  			switch name {
   595  			case machinesC:
   596  				agentTags = append(agentTags, names.NewMachineTag(localID).String())
   597  			case unitsC:
   598  				agentTags = append(agentTags, names.NewUnitTag(localID).String())
   599  			}
   600  		}
   601  		if err := iter.Close(); err != nil {
   602  			return errors.Trace(err)
   603  		}
   604  	}
   605  	if len(agentTags) > 0 {
   606  		err := newVersionInconsistentError(version.MustParse(currentVersion), agentTags)
   607  		return errors.Trace(err)
   608  	}
   609  	return nil
   610  }
   611  
   612  var errUpgradeInProgress = errors.New(params.CodeUpgradeInProgress)
   613  
   614  // IsUpgradeInProgressError returns true if the error is caused by an
   615  // in-progress upgrade.
   616  func IsUpgradeInProgressError(err error) bool {
   617  	return errors.Cause(err) == errUpgradeInProgress
   618  }
   619  
   620  // SetModelAgentVersion changes the agent version for the model to the
   621  // given version, only if the model is in a stable state (all agents are
   622  // running the current version). If this is a hosted model, newVersion
   623  // cannot be higher than the controller version.
   624  func (st *State) SetModelAgentVersion(newVersion version.Number) (err error) {
   625  	if newVersion.Compare(jujuversion.Current) > 0 && !st.IsController() {
   626  		return errors.Errorf("a hosted model cannot have a higher version than the server model: %s > %s",
   627  			newVersion.String(),
   628  			jujuversion.Current,
   629  		)
   630  	}
   631  
   632  	buildTxn := func(attempt int) ([]txn.Op, error) {
   633  		settings, err := readSettings(st, settingsC, modelGlobalKey)
   634  		if err != nil {
   635  			return nil, errors.Trace(err)
   636  		}
   637  		agentVersion, ok := settings.Get("agent-version")
   638  		if !ok {
   639  			return nil, errors.Errorf("no agent version set in the model")
   640  		}
   641  		currentVersion, ok := agentVersion.(string)
   642  		if !ok {
   643  			return nil, errors.Errorf("invalid agent version format: expected string, got %v", agentVersion)
   644  		}
   645  		if newVersion.String() == currentVersion {
   646  			// Nothing to do.
   647  			return nil, jujutxn.ErrNoOperations
   648  		}
   649  
   650  		if err := st.checkCanUpgrade(currentVersion, newVersion.String()); err != nil {
   651  			return nil, errors.Trace(err)
   652  		}
   653  
   654  		ops := []txn.Op{
   655  			// Can't set agent-version if there's an active upgradeInfo doc.
   656  			{
   657  				C:      upgradeInfoC,
   658  				Id:     currentUpgradeId,
   659  				Assert: txn.DocMissing,
   660  			}, {
   661  				C:      settingsC,
   662  				Id:     st.docID(modelGlobalKey),
   663  				Assert: bson.D{{"version", settings.version}},
   664  				Update: bson.D{
   665  					{"$set", bson.D{{"settings.agent-version", newVersion.String()}}},
   666  				},
   667  			},
   668  		}
   669  		return ops, nil
   670  	}
   671  	if err = st.run(buildTxn); err == jujutxn.ErrExcessiveContention {
   672  		// Although there is a small chance of a race here, try to
   673  		// return a more helpful error message in the case of an
   674  		// active upgradeInfo document being in place.
   675  		if upgrading, _ := st.IsUpgrading(); upgrading {
   676  			err = errUpgradeInProgress
   677  		} else {
   678  			err = errors.Annotate(err, "cannot set agent version")
   679  		}
   680  	}
   681  	return errors.Trace(err)
   682  }
   683  
   684  // ModelConstraints returns the current model constraints.
   685  func (st *State) ModelConstraints() (constraints.Value, error) {
   686  	cons, err := readConstraints(st, modelGlobalKey)
   687  	return cons, errors.Trace(err)
   688  }
   689  
   690  // SetModelConstraints replaces the current model constraints.
   691  func (st *State) SetModelConstraints(cons constraints.Value) error {
   692  	unsupported, err := st.validateConstraints(cons)
   693  	if len(unsupported) > 0 {
   694  		logger.Warningf(
   695  			"setting model constraints: unsupported constraints: %v", strings.Join(unsupported, ","))
   696  	} else if err != nil {
   697  		return errors.Trace(err)
   698  	}
   699  	return writeConstraints(st, modelGlobalKey, cons)
   700  }
   701  
   702  func (st *State) allMachines(machinesCollection mongo.Collection) ([]*Machine, error) {
   703  	mdocs := machineDocSlice{}
   704  	err := machinesCollection.Find(nil).All(&mdocs)
   705  	if err != nil {
   706  		return nil, errors.Annotatef(err, "cannot get all machines")
   707  	}
   708  	sort.Sort(mdocs)
   709  	machines := make([]*Machine, len(mdocs))
   710  	for i, doc := range mdocs {
   711  		machines[i] = newMachine(st, &doc)
   712  	}
   713  	return machines, nil
   714  }
   715  
   716  // AllMachines returns all machines in the model
   717  // ordered by id.
   718  func (st *State) AllMachines() ([]*Machine, error) {
   719  	machinesCollection, closer := st.getCollection(machinesC)
   720  	defer closer()
   721  	return st.allMachines(machinesCollection)
   722  }
   723  
   724  // AllMachinesFor returns all machines for the model represented
   725  // by the given modeluuid
   726  func (st *State) AllMachinesFor(modelUUID string) ([]*Machine, error) {
   727  	machinesCollection, closer := st.getCollectionFor(modelUUID, machinesC)
   728  	defer closer()
   729  	return st.allMachines(machinesCollection)
   730  }
   731  
   732  type machineDocSlice []machineDoc
   733  
   734  func (ms machineDocSlice) Len() int      { return len(ms) }
   735  func (ms machineDocSlice) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] }
   736  func (ms machineDocSlice) Less(i, j int) bool {
   737  	return machineIdLessThan(ms[i].Id, ms[j].Id)
   738  }
   739  
   740  // machineIdLessThan returns true if id1 < id2, false otherwise.
   741  // Machine ids may include "/" separators if they are for a container so
   742  // the comparison is done by comparing the id component values from
   743  // left to right (most significant part to least significant). Ids for
   744  // host machines are always less than ids for their containers.
   745  func machineIdLessThan(id1, id2 string) bool {
   746  	// Most times, we are dealing with host machines and not containers, so we will
   747  	// try interpreting the ids as ints - this will be faster than dealing with the
   748  	// container ids below.
   749  	mint1, err1 := strconv.Atoi(id1)
   750  	mint2, err2 := strconv.Atoi(id2)
   751  	if err1 == nil && err2 == nil {
   752  		return mint1 < mint2
   753  	}
   754  	// We have at least one container id so it gets complicated.
   755  	idParts1 := strings.Split(id1, "/")
   756  	idParts2 := strings.Split(id2, "/")
   757  	nrParts1 := len(idParts1)
   758  	nrParts2 := len(idParts2)
   759  	minLen := nrParts1
   760  	if nrParts2 < minLen {
   761  		minLen = nrParts2
   762  	}
   763  	for x := 0; x < minLen; x++ {
   764  		m1 := idParts1[x]
   765  		m2 := idParts2[x]
   766  		if m1 == m2 {
   767  			continue
   768  		}
   769  		// See if the id part is a container type, and if so compare directly.
   770  		if x%2 == 1 {
   771  			return m1 < m2
   772  		}
   773  		// Compare the integer ids.
   774  		// There's nothing we can do with errors at this point.
   775  		mint1, _ := strconv.Atoi(m1)
   776  		mint2, _ := strconv.Atoi(m2)
   777  		return mint1 < mint2
   778  	}
   779  	return nrParts1 < nrParts2
   780  }
   781  
   782  // Machine returns the machine with the given id.
   783  func (st *State) Machine(id string) (*Machine, error) {
   784  	mdoc, err := st.getMachineDoc(id)
   785  	if err != nil {
   786  		return nil, err
   787  	}
   788  	return newMachine(st, mdoc), nil
   789  }
   790  
   791  func (st *State) getMachineDoc(id string) (*machineDoc, error) {
   792  	machinesCollection, closer := st.getCollection(machinesC)
   793  	defer closer()
   794  
   795  	var err error
   796  	mdoc := &machineDoc{}
   797  	err = machinesCollection.FindId(id).One(mdoc)
   798  
   799  	switch err {
   800  	case nil:
   801  		return mdoc, nil
   802  	case mgo.ErrNotFound:
   803  		return nil, errors.NotFoundf("machine %s", id)
   804  	default:
   805  		return nil, errors.Annotatef(err, "cannot get machine %s", id)
   806  	}
   807  }
   808  
   809  // FindEntity returns the entity with the given tag.
   810  //
   811  // The returned value can be of type *Machine, *Unit,
   812  // *User, *Service, *Model, or *Action, depending
   813  // on the tag.
   814  func (st *State) FindEntity(tag names.Tag) (Entity, error) {
   815  	id := tag.Id()
   816  	switch tag := tag.(type) {
   817  	case names.MachineTag:
   818  		return st.Machine(id)
   819  	case names.UnitTag:
   820  		return st.Unit(id)
   821  	case names.UserTag:
   822  		return st.User(tag)
   823  	case names.ApplicationTag:
   824  		return st.Application(id)
   825  	case names.ModelTag:
   826  		env, err := st.Model()
   827  		if err != nil {
   828  			return nil, errors.Trace(err)
   829  		}
   830  		// Return an invalid entity error if the requested model is not
   831  		// the current one.
   832  		if id != env.UUID() {
   833  			if utils.IsValidUUIDString(id) {
   834  				return nil, errors.NotFoundf("model %q", id)
   835  			}
   836  			// TODO(axw) 2013-12-04 #1257587
   837  			// We should not accept model tags that do not match the
   838  			// model's UUID. We accept anything for now, to cater
   839  			// both for past usage, and for potentially supporting aliases.
   840  			logger.Warningf("model-tag does not match current model UUID: %q != %q", id, env.UUID())
   841  			conf, err := st.ModelConfig()
   842  			if err != nil {
   843  				logger.Warningf("ModelConfig failed: %v", err)
   844  			} else if id != conf.Name() {
   845  				logger.Warningf("model-tag does not match current model name: %q != %q", id, conf.Name())
   846  			}
   847  		}
   848  		return env, nil
   849  	case names.RelationTag:
   850  		return st.KeyRelation(id)
   851  	case names.ActionTag:
   852  		return st.ActionByTag(tag)
   853  	case names.CharmTag:
   854  		if url, err := charm.ParseURL(id); err != nil {
   855  			logger.Warningf("Parsing charm URL %q failed: %v", id, err)
   856  			return nil, errors.NotFoundf("could not find charm %q in state", id)
   857  		} else {
   858  			return st.Charm(url)
   859  		}
   860  	case names.VolumeTag:
   861  		return st.Volume(tag)
   862  	case names.FilesystemTag:
   863  		return st.Filesystem(tag)
   864  	default:
   865  		return nil, errors.Errorf("unsupported tag %T", tag)
   866  	}
   867  }
   868  
   869  // tagToCollectionAndId, given an entity tag, returns the collection name and id
   870  // of the entity document.
   871  func (st *State) tagToCollectionAndId(tag names.Tag) (string, interface{}, error) {
   872  	if tag == nil {
   873  		return "", nil, errors.Errorf("tag is nil")
   874  	}
   875  	coll := ""
   876  	id := tag.Id()
   877  	switch tag := tag.(type) {
   878  	case names.MachineTag:
   879  		coll = machinesC
   880  		id = st.docID(id)
   881  	case names.ApplicationTag:
   882  		coll = applicationsC
   883  		id = st.docID(id)
   884  	case names.UnitTag:
   885  		coll = unitsC
   886  		id = st.docID(id)
   887  	case names.UserTag:
   888  		coll = usersC
   889  		if !tag.IsLocal() {
   890  			return "", nil, fmt.Errorf("%q is not a local user", tag.Canonical())
   891  		}
   892  		id = tag.Name()
   893  	case names.RelationTag:
   894  		coll = relationsC
   895  		id = st.docID(id)
   896  	case names.ModelTag:
   897  		coll = modelsC
   898  	case names.ActionTag:
   899  		coll = actionsC
   900  		id = tag.Id()
   901  	case names.CharmTag:
   902  		coll = charmsC
   903  		id = tag.Id()
   904  	default:
   905  		return "", nil, errors.Errorf("%q is not a valid collection tag", tag)
   906  	}
   907  	return coll, id, nil
   908  }
   909  
   910  // addPeerRelationsOps returns the operations necessary to add the
   911  // specified service peer relations to the state.
   912  func (st *State) addPeerRelationsOps(applicationname string, peers map[string]charm.Relation) ([]txn.Op, error) {
   913  	var ops []txn.Op
   914  	for _, rel := range peers {
   915  		relId, err := st.sequence("relation")
   916  		if err != nil {
   917  			return nil, errors.Trace(err)
   918  		}
   919  		eps := []Endpoint{{
   920  			ApplicationName: applicationname,
   921  			Relation:        rel,
   922  		}}
   923  		relKey := relationKey(eps)
   924  		relDoc := &relationDoc{
   925  			DocID:     st.docID(relKey),
   926  			Key:       relKey,
   927  			ModelUUID: st.ModelUUID(),
   928  			Id:        relId,
   929  			Endpoints: eps,
   930  			Life:      Alive,
   931  		}
   932  		ops = append(ops, txn.Op{
   933  			C:      relationsC,
   934  			Id:     relDoc.DocID,
   935  			Assert: txn.DocMissing,
   936  			Insert: relDoc,
   937  		})
   938  	}
   939  	return ops, nil
   940  }
   941  
   942  type AddApplicationArgs struct {
   943  	Name             string
   944  	Series           string
   945  	Charm            *Charm
   946  	Channel          csparams.Channel
   947  	Storage          map[string]StorageConstraints
   948  	EndpointBindings map[string]string
   949  	Settings         charm.Settings
   950  	NumUnits         int
   951  	Placement        []*instance.Placement
   952  	Constraints      constraints.Value
   953  	Resources        map[string]string
   954  }
   955  
   956  // AddApplication creates a new application, running the supplied charm, with the
   957  // supplied name (which must be unique). If the charm defines peer relations,
   958  // they will be created automatically.
   959  func (st *State) AddApplication(args AddApplicationArgs) (_ *Application, err error) {
   960  	defer errors.DeferredAnnotatef(&err, "cannot add application %q", args.Name)
   961  	// Sanity checks.
   962  	if !names.IsValidApplication(args.Name) {
   963  		return nil, errors.Errorf("invalid name")
   964  	}
   965  	if args.Charm == nil {
   966  		return nil, errors.Errorf("charm is nil")
   967  	}
   968  
   969  	if err := validateCharmVersion(args.Charm); err != nil {
   970  		return nil, errors.Trace(err)
   971  	}
   972  
   973  	if exists, err := isNotDead(st, applicationsC, args.Name); err != nil {
   974  		return nil, errors.Trace(err)
   975  	} else if exists {
   976  		return nil, errors.Errorf("application already exists")
   977  	}
   978  	if err := checkModelActive(st); err != nil {
   979  		return nil, errors.Trace(err)
   980  	}
   981  	if args.Storage == nil {
   982  		args.Storage = make(map[string]StorageConstraints)
   983  	}
   984  	if err := addDefaultStorageConstraints(st, args.Storage, args.Charm.Meta()); err != nil {
   985  		return nil, errors.Trace(err)
   986  	}
   987  	if err := validateStorageConstraints(st, args.Storage, args.Charm.Meta()); err != nil {
   988  		return nil, errors.Trace(err)
   989  	}
   990  	storagePools := make(set.Strings)
   991  	for _, storageParams := range args.Storage {
   992  		storagePools.Add(storageParams.Pool)
   993  	}
   994  
   995  	if args.Series == "" {
   996  		// args.Series is not set, so use the series in the URL.
   997  		args.Series = args.Charm.URL().Series
   998  		if args.Series == "" {
   999  			// Should not happen, but just in case.
  1000  			return nil, errors.New("series is empty")
  1001  		}
  1002  	} else {
  1003  		// User has specified series. Overriding supported series is
  1004  		// handled by the client, so args.Series is not necessarily
  1005  		// one of the charm's supported series. We require that the
  1006  		// specified series is of the same operating system as one of
  1007  		// the supported series. For old-style charms with the series
  1008  		// in the URL, that series is the one and only supported
  1009  		// series.
  1010  		var supportedSeries []string
  1011  		if series := args.Charm.URL().Series; series != "" {
  1012  			supportedSeries = []string{series}
  1013  		} else {
  1014  			supportedSeries = args.Charm.Meta().Series
  1015  		}
  1016  		if len(supportedSeries) > 0 {
  1017  			seriesOS, err := series.GetOSFromSeries(args.Series)
  1018  			if err != nil {
  1019  				return nil, errors.Trace(err)
  1020  			}
  1021  			supportedOperatingSystems := make(map[os.OSType]bool)
  1022  			for _, supportedSeries := range supportedSeries {
  1023  				os, err := series.GetOSFromSeries(supportedSeries)
  1024  				if err != nil {
  1025  					return nil, errors.Trace(err)
  1026  				}
  1027  				supportedOperatingSystems[os] = true
  1028  			}
  1029  			if !supportedOperatingSystems[seriesOS] {
  1030  				return nil, errors.NewNotSupported(errors.Errorf(
  1031  					"series %q (OS %q) not supported by charm, supported series are %q",
  1032  					args.Series, seriesOS, strings.Join(supportedSeries, ", "),
  1033  				), "")
  1034  			}
  1035  		}
  1036  	}
  1037  
  1038  	// Ignore constraints that result from this call as
  1039  	// these would be accumulation of model and application constraints
  1040  	// but we only want application constraints to be persisted here.
  1041  	_, err = st.resolveConstraints(args.Constraints)
  1042  	if err != nil {
  1043  		return nil, errors.Trace(err)
  1044  	}
  1045  
  1046  	for _, placement := range args.Placement {
  1047  		data, err := st.parsePlacement(placement)
  1048  		if err != nil {
  1049  			return nil, errors.Trace(err)
  1050  		}
  1051  		switch data.placementType() {
  1052  		case machinePlacement:
  1053  			// Ensure that the machine and charm series match.
  1054  			m, err := st.Machine(data.machineId)
  1055  			if err != nil {
  1056  				return nil, errors.Trace(err)
  1057  			}
  1058  			subordinate := args.Charm.Meta().Subordinate
  1059  			if err := validateUnitMachineAssignment(
  1060  				m, args.Series, subordinate, storagePools,
  1061  			); err != nil {
  1062  				return nil, errors.Annotatef(
  1063  					err, "cannot deploy to machine %s", m,
  1064  				)
  1065  			}
  1066  
  1067  		case directivePlacement:
  1068  			if err := st.precheckInstance(args.Series, args.Constraints, data.directive); err != nil {
  1069  				return nil, errors.Trace(err)
  1070  			}
  1071  		}
  1072  	}
  1073  
  1074  	applicationID := st.docID(args.Name)
  1075  
  1076  	// Create the service addition operations.
  1077  	peers := args.Charm.Meta().Peers
  1078  
  1079  	// The doc defaults to CharmModifiedVersion = 0, which is correct, since it
  1080  	// has, by definition, at its initial state.
  1081  	svcDoc := &applicationDoc{
  1082  		DocID:         applicationID,
  1083  		Name:          args.Name,
  1084  		ModelUUID:     st.ModelUUID(),
  1085  		Series:        args.Series,
  1086  		Subordinate:   args.Charm.Meta().Subordinate,
  1087  		CharmURL:      args.Charm.URL(),
  1088  		Channel:       string(args.Channel),
  1089  		RelationCount: len(peers),
  1090  		Life:          Alive,
  1091  	}
  1092  
  1093  	svc := newApplication(st, svcDoc)
  1094  
  1095  	endpointBindingsOp, err := createEndpointBindingsOp(
  1096  		st, svc.globalKey(),
  1097  		args.EndpointBindings, args.Charm.Meta(),
  1098  	)
  1099  	if err != nil {
  1100  		return nil, errors.Trace(err)
  1101  	}
  1102  
  1103  	statusDoc := statusDoc{
  1104  		ModelUUID:  st.ModelUUID(),
  1105  		Status:     status.Waiting,
  1106  		StatusInfo: status.MessageWaitForMachine,
  1107  		Updated:    st.clock.Now().UnixNano(),
  1108  		// This exists to preserve questionable unit-aggregation behaviour
  1109  		// while we work out how to switch to an implementation that makes
  1110  		// sense. It is also set in AddMissingServiceStatuses.
  1111  		NeverSet: true,
  1112  	}
  1113  
  1114  	// The addServiceOps does not include the environment alive assertion,
  1115  	// so we add it here.
  1116  	ops := []txn.Op{
  1117  		assertModelActiveOp(st.ModelUUID()),
  1118  		endpointBindingsOp,
  1119  	}
  1120  	addOps, err := addApplicationOps(st, addApplicationOpsArgs{
  1121  		applicationDoc: svcDoc,
  1122  		statusDoc:      statusDoc,
  1123  		constraints:    args.Constraints,
  1124  		storage:        args.Storage,
  1125  		settings:       map[string]interface{}(args.Settings),
  1126  	})
  1127  	if err != nil {
  1128  		return nil, errors.Trace(err)
  1129  	}
  1130  	ops = append(ops, addOps...)
  1131  
  1132  	// Collect peer relation addition operations.
  1133  	//
  1134  	// TODO(dimitern): Ensure each st.Endpoint has a space name associated in a
  1135  	// follow-up.
  1136  	peerOps, err := st.addPeerRelationsOps(args.Name, peers)
  1137  	if err != nil {
  1138  		return nil, errors.Trace(err)
  1139  	}
  1140  	ops = append(ops, peerOps...)
  1141  
  1142  	if len(args.Resources) > 0 {
  1143  		// Collect pending resource resolution operations.
  1144  		resources, err := st.Resources()
  1145  		if err != nil {
  1146  			return nil, errors.Trace(err)
  1147  		}
  1148  		resOps, err := resources.NewResolvePendingResourcesOps(args.Name, args.Resources)
  1149  		if err != nil {
  1150  			return nil, errors.Trace(err)
  1151  		}
  1152  		ops = append(ops, resOps...)
  1153  	}
  1154  
  1155  	// Collect unit-adding operations.
  1156  	for x := 0; x < args.NumUnits; x++ {
  1157  		unitName, unitOps, err := svc.addServiceUnitOps(applicationAddUnitOpsArgs{cons: args.Constraints, storageCons: args.Storage})
  1158  		if err != nil {
  1159  			return nil, errors.Trace(err)
  1160  		}
  1161  		ops = append(ops, unitOps...)
  1162  		placement := instance.Placement{}
  1163  		if x < len(args.Placement) {
  1164  			placement = *args.Placement[x]
  1165  		}
  1166  		ops = append(ops, assignUnitOps(unitName, placement)...)
  1167  	}
  1168  	// At the last moment before inserting the service, prime status history.
  1169  	probablyUpdateStatusHistory(st, svc.globalKey(), statusDoc)
  1170  
  1171  	if err := st.runTransaction(ops); err == txn.ErrAborted {
  1172  		if err := checkModelActive(st); err != nil {
  1173  			return nil, errors.Trace(err)
  1174  		}
  1175  		// TODO(fwereade): 2016-09-09 lp:1621754
  1176  		// This is not always correct -- there are a million
  1177  		// operations collected in this func, not *all* of them
  1178  		// imply that this is the problem. (e.g. the charm being
  1179  		// destroyed just as we add application will fail, but
  1180  		// not because "application already exists")
  1181  		return nil, errors.Errorf("application already exists")
  1182  	} else if err != nil {
  1183  		return nil, errors.Trace(err)
  1184  	}
  1185  	// Refresh to pick the txn-revno.
  1186  	if err = svc.Refresh(); err != nil {
  1187  		return nil, errors.Trace(err)
  1188  	}
  1189  
  1190  	return svc, nil
  1191  }
  1192  
  1193  // TODO(natefinch) DEMO code, revisit after demo!
  1194  var AddServicePostFuncs = map[string]func(*State, AddApplicationArgs) error{}
  1195  
  1196  // assignUnitOps returns the db ops to save unit assignment for use by the
  1197  // UnitAssigner worker.
  1198  func assignUnitOps(unitName string, placement instance.Placement) []txn.Op {
  1199  	udoc := assignUnitDoc{
  1200  		DocId:     unitName,
  1201  		Scope:     placement.Scope,
  1202  		Directive: placement.Directive,
  1203  	}
  1204  	return []txn.Op{{
  1205  		C:      assignUnitC,
  1206  		Id:     udoc.DocId,
  1207  		Assert: txn.DocMissing,
  1208  		Insert: udoc,
  1209  	}}
  1210  }
  1211  
  1212  // AssignStagedUnits gets called by the UnitAssigner worker, and runs the given
  1213  // assignments.
  1214  func (st *State) AssignStagedUnits(ids []string) ([]UnitAssignmentResult, error) {
  1215  	query := bson.D{{"_id", bson.D{{"$in", ids}}}}
  1216  	unitAssignments, err := st.unitAssignments(query)
  1217  	if err != nil {
  1218  		return nil, errors.Annotate(err, "getting staged unit assignments")
  1219  	}
  1220  	results := make([]UnitAssignmentResult, len(unitAssignments))
  1221  	for i, a := range unitAssignments {
  1222  		err := st.assignStagedUnit(a)
  1223  		results[i].Unit = a.Unit
  1224  		results[i].Error = err
  1225  	}
  1226  	return results, nil
  1227  }
  1228  
  1229  // UnitAssignments returns all staged unit assignments in the model.
  1230  func (st *State) AllUnitAssignments() ([]UnitAssignment, error) {
  1231  	return st.unitAssignments(nil)
  1232  }
  1233  
  1234  func (st *State) unitAssignments(query bson.D) ([]UnitAssignment, error) {
  1235  	col, close := st.getCollection(assignUnitC)
  1236  	defer close()
  1237  
  1238  	var docs []assignUnitDoc
  1239  	if err := col.Find(query).All(&docs); err != nil {
  1240  		return nil, errors.Annotatef(err, "cannot get unit assignment docs")
  1241  	}
  1242  	results := make([]UnitAssignment, len(docs))
  1243  	for i, doc := range docs {
  1244  		results[i] = UnitAssignment{
  1245  			st.localID(doc.DocId),
  1246  			doc.Scope,
  1247  			doc.Directive,
  1248  		}
  1249  	}
  1250  	return results, nil
  1251  }
  1252  
  1253  func removeStagedAssignmentOp(id string) txn.Op {
  1254  	return txn.Op{
  1255  		C:      assignUnitC,
  1256  		Id:     id,
  1257  		Remove: true,
  1258  	}
  1259  }
  1260  
  1261  func (st *State) assignStagedUnit(a UnitAssignment) error {
  1262  	u, err := st.Unit(a.Unit)
  1263  	if err != nil {
  1264  		return errors.Trace(err)
  1265  	}
  1266  	if a.Scope == "" && a.Directive == "" {
  1267  		return errors.Trace(st.AssignUnit(u, AssignCleanEmpty))
  1268  	}
  1269  
  1270  	placement := &instance.Placement{Scope: a.Scope, Directive: a.Directive}
  1271  
  1272  	return errors.Trace(st.AssignUnitWithPlacement(u, placement))
  1273  }
  1274  
  1275  // AssignUnitWithPlacement chooses a machine using the given placement directive
  1276  // and then assigns the unit to it.
  1277  func (st *State) AssignUnitWithPlacement(unit *Unit, placement *instance.Placement) error {
  1278  	// TODO(natefinch) this should be done as a single transaction, not two.
  1279  	// Mark https://launchpad.net/bugs/1506994 fixed when done.
  1280  
  1281  	m, err := st.addMachineWithPlacement(unit, placement)
  1282  	if err != nil {
  1283  		return errors.Trace(err)
  1284  	}
  1285  	return unit.AssignToMachine(m)
  1286  }
  1287  
  1288  // placementData is a helper type that encodes some of the logic behind how an
  1289  // instance.Placement gets translated into a placement directive the providers
  1290  // understand.
  1291  type placementData struct {
  1292  	machineId     string
  1293  	directive     string
  1294  	containerType instance.ContainerType
  1295  }
  1296  
  1297  type placementType int
  1298  
  1299  const (
  1300  	containerPlacement placementType = iota
  1301  	directivePlacement
  1302  	machinePlacement
  1303  )
  1304  
  1305  // placementType returns the type of placement that this data represents.
  1306  func (p placementData) placementType() placementType {
  1307  	if p.containerType != "" {
  1308  		return containerPlacement
  1309  	}
  1310  	if p.directive != "" {
  1311  		return directivePlacement
  1312  	}
  1313  	return machinePlacement
  1314  }
  1315  
  1316  func (st *State) parsePlacement(placement *instance.Placement) (*placementData, error) {
  1317  	// Extract container type and parent from container placement directives.
  1318  	if container, err := instance.ParseContainerType(placement.Scope); err == nil {
  1319  		return &placementData{
  1320  			containerType: container,
  1321  			machineId:     placement.Directive,
  1322  		}, nil
  1323  	}
  1324  	switch placement.Scope {
  1325  	case st.ModelUUID():
  1326  		return &placementData{directive: placement.Directive}, nil
  1327  	case instance.MachineScope:
  1328  		return &placementData{machineId: placement.Directive}, nil
  1329  	default:
  1330  		return nil, errors.Errorf("placement scope: invalid model UUID %q", placement.Scope)
  1331  	}
  1332  }
  1333  
  1334  // addMachineWithPlacement finds a machine that matches the given placement directive for the given unit.
  1335  func (st *State) addMachineWithPlacement(unit *Unit, placement *instance.Placement) (*Machine, error) {
  1336  	unitCons, err := unit.Constraints()
  1337  	if err != nil {
  1338  		return nil, err
  1339  	}
  1340  
  1341  	data, err := st.parsePlacement(placement)
  1342  	if err != nil {
  1343  		return nil, errors.Trace(err)
  1344  	}
  1345  
  1346  	// Create any new machine marked as dirty so that
  1347  	// nothing else will grab it before we assign the unit to it.
  1348  	// TODO(natefinch) fix this when we put assignment in the same
  1349  	// transaction as adding a machine.  See bug
  1350  	// https://launchpad.net/bugs/1506994
  1351  
  1352  	switch data.placementType() {
  1353  	case containerPlacement:
  1354  		// If a container is to be used, create it.
  1355  		template := MachineTemplate{
  1356  			Series:      unit.Series(),
  1357  			Jobs:        []MachineJob{JobHostUnits},
  1358  			Dirty:       true,
  1359  			Constraints: *unitCons,
  1360  		}
  1361  		if data.machineId != "" {
  1362  			return st.AddMachineInsideMachine(template, data.machineId, data.containerType)
  1363  		}
  1364  		return st.AddMachineInsideNewMachine(template, template, data.containerType)
  1365  	case directivePlacement:
  1366  		// If a placement directive is to be used, do that here.
  1367  		template := MachineTemplate{
  1368  			Series:      unit.Series(),
  1369  			Jobs:        []MachineJob{JobHostUnits},
  1370  			Dirty:       true,
  1371  			Constraints: *unitCons,
  1372  			Placement:   data.directive,
  1373  		}
  1374  		return st.AddOneMachine(template)
  1375  	default:
  1376  		// Otherwise use an existing machine.
  1377  		return st.Machine(data.machineId)
  1378  	}
  1379  }
  1380  
  1381  // Service returns a service state by name.
  1382  func (st *State) Application(name string) (_ *Application, err error) {
  1383  	applications, closer := st.getCollection(applicationsC)
  1384  	defer closer()
  1385  
  1386  	if !names.IsValidApplication(name) {
  1387  		return nil, errors.Errorf("%q is not a valid application name", name)
  1388  	}
  1389  	sdoc := &applicationDoc{}
  1390  	err = applications.FindId(name).One(sdoc)
  1391  	if err == mgo.ErrNotFound {
  1392  		return nil, errors.NotFoundf("application %q", name)
  1393  	}
  1394  	if err != nil {
  1395  		return nil, errors.Annotatef(err, "cannot get application %q", name)
  1396  	}
  1397  	return newApplication(st, sdoc), nil
  1398  }
  1399  
  1400  // AllApplications returns all deployed services in the model.
  1401  func (st *State) AllApplications() (applications []*Application, err error) {
  1402  	applicationsCollection, closer := st.getCollection(applicationsC)
  1403  	defer closer()
  1404  
  1405  	sdocs := []applicationDoc{}
  1406  	err = applicationsCollection.Find(bson.D{}).All(&sdocs)
  1407  	if err != nil {
  1408  		return nil, errors.Errorf("cannot get all applications")
  1409  	}
  1410  	for _, v := range sdocs {
  1411  		applications = append(applications, newApplication(st, &v))
  1412  	}
  1413  	return applications, nil
  1414  }
  1415  
  1416  // InferEndpoints returns the endpoints corresponding to the supplied names.
  1417  // There must be 1 or 2 supplied names, of the form <service>[:<relation>].
  1418  // If the supplied names uniquely specify a possible relation, or if they
  1419  // uniquely specify a possible relation once all implicit relations have been
  1420  // filtered, the endpoints corresponding to that relation will be returned.
  1421  func (st *State) InferEndpoints(names ...string) ([]Endpoint, error) {
  1422  	// Collect all possible sane endpoint lists.
  1423  	var candidates [][]Endpoint
  1424  	switch len(names) {
  1425  	case 1:
  1426  		eps, err := st.endpoints(names[0], isPeer)
  1427  		if err != nil {
  1428  			return nil, errors.Trace(err)
  1429  		}
  1430  		for _, ep := range eps {
  1431  			candidates = append(candidates, []Endpoint{ep})
  1432  		}
  1433  	case 2:
  1434  		eps1, err := st.endpoints(names[0], notPeer)
  1435  		if err != nil {
  1436  			return nil, errors.Trace(err)
  1437  		}
  1438  		eps2, err := st.endpoints(names[1], notPeer)
  1439  		if err != nil {
  1440  			return nil, errors.Trace(err)
  1441  		}
  1442  		for _, ep1 := range eps1 {
  1443  			for _, ep2 := range eps2 {
  1444  				if ep1.CanRelateTo(ep2) && containerScopeOk(st, ep1, ep2) {
  1445  					candidates = append(candidates, []Endpoint{ep1, ep2})
  1446  				}
  1447  			}
  1448  		}
  1449  	default:
  1450  		return nil, errors.Errorf("cannot relate %d endpoints", len(names))
  1451  	}
  1452  	// If there's ambiguity, try discarding implicit relations.
  1453  	switch len(candidates) {
  1454  	case 0:
  1455  		return nil, errors.Errorf("no relations found")
  1456  	case 1:
  1457  		return candidates[0], nil
  1458  	}
  1459  	var filtered [][]Endpoint
  1460  outer:
  1461  	for _, cand := range candidates {
  1462  		for _, ep := range cand {
  1463  			if ep.IsImplicit() {
  1464  				continue outer
  1465  			}
  1466  		}
  1467  		filtered = append(filtered, cand)
  1468  	}
  1469  	if len(filtered) == 1 {
  1470  		return filtered[0], nil
  1471  	}
  1472  	keys := []string{}
  1473  	for _, cand := range candidates {
  1474  		keys = append(keys, fmt.Sprintf("%q", relationKey(cand)))
  1475  	}
  1476  	sort.Strings(keys)
  1477  	return nil, errors.Errorf("ambiguous relation: %q could refer to %s",
  1478  		strings.Join(names, " "), strings.Join(keys, "; "))
  1479  }
  1480  
  1481  func isPeer(ep Endpoint) bool {
  1482  	return ep.Role == charm.RolePeer
  1483  }
  1484  
  1485  func notPeer(ep Endpoint) bool {
  1486  	return ep.Role != charm.RolePeer
  1487  }
  1488  
  1489  func containerScopeOk(st *State, ep1, ep2 Endpoint) bool {
  1490  	if ep1.Scope != charm.ScopeContainer && ep2.Scope != charm.ScopeContainer {
  1491  		return true
  1492  	}
  1493  	var subordinateCount int
  1494  	for _, ep := range []Endpoint{ep1, ep2} {
  1495  		svc, err := st.Application(ep.ApplicationName)
  1496  		if err != nil {
  1497  			return false
  1498  		}
  1499  		if svc.doc.Subordinate {
  1500  			subordinateCount++
  1501  		}
  1502  	}
  1503  	return subordinateCount >= 1
  1504  }
  1505  
  1506  // endpoints returns all endpoints that could be intended by the
  1507  // supplied endpoint name, and which cause the filter param to
  1508  // return true.
  1509  func (st *State) endpoints(name string, filter func(ep Endpoint) bool) ([]Endpoint, error) {
  1510  	var svcName, relName string
  1511  	if i := strings.Index(name, ":"); i == -1 {
  1512  		svcName = name
  1513  	} else if i != 0 && i != len(name)-1 {
  1514  		svcName = name[:i]
  1515  		relName = name[i+1:]
  1516  	} else {
  1517  		return nil, errors.Errorf("invalid endpoint %q", name)
  1518  	}
  1519  	svc, err := st.Application(svcName)
  1520  	if err != nil {
  1521  		return nil, errors.Trace(err)
  1522  	}
  1523  	eps := []Endpoint{}
  1524  	if relName != "" {
  1525  		ep, err := svc.Endpoint(relName)
  1526  		if err != nil {
  1527  			return nil, errors.Trace(err)
  1528  		}
  1529  		eps = append(eps, ep)
  1530  	} else {
  1531  		eps, err = svc.Endpoints()
  1532  		if err != nil {
  1533  			return nil, errors.Trace(err)
  1534  		}
  1535  	}
  1536  	final := []Endpoint{}
  1537  	for _, ep := range eps {
  1538  		if filter(ep) {
  1539  			final = append(final, ep)
  1540  		}
  1541  	}
  1542  	return final, nil
  1543  }
  1544  
  1545  // AddRelation creates a new relation with the given endpoints.
  1546  func (st *State) AddRelation(eps ...Endpoint) (r *Relation, err error) {
  1547  	key := relationKey(eps)
  1548  	defer errors.DeferredAnnotatef(&err, "cannot add relation %q", key)
  1549  	// Enforce basic endpoint sanity. The epCount restrictions may be relaxed
  1550  	// in the future; if so, this method is likely to need significant rework.
  1551  	if len(eps) != 2 {
  1552  		return nil, errors.Errorf("relation must have two endpoints")
  1553  	}
  1554  	if !eps[0].CanRelateTo(eps[1]) {
  1555  		return nil, errors.Errorf("endpoints do not relate")
  1556  	}
  1557  	// If either endpoint has container scope, so must the other; and the
  1558  	// services's series must also match, because they'll be deployed to
  1559  	// the same machines.
  1560  	matchSeries := true
  1561  	if eps[0].Scope == charm.ScopeContainer {
  1562  		eps[1].Scope = charm.ScopeContainer
  1563  	} else if eps[1].Scope == charm.ScopeContainer {
  1564  		eps[0].Scope = charm.ScopeContainer
  1565  	} else {
  1566  		matchSeries = false
  1567  	}
  1568  	// We only get a unique relation id once, to save on roundtrips. If it's
  1569  	// -1, we haven't got it yet (we don't get it at this stage, because we
  1570  	// still don't know whether it's sane to even attempt creation).
  1571  	id := -1
  1572  	// If a service's charm is upgraded while we're trying to add a relation,
  1573  	// we'll need to re-validate service sanity.
  1574  	var doc *relationDoc
  1575  	buildTxn := func(attempt int) ([]txn.Op, error) {
  1576  		// Perform initial relation sanity check.
  1577  		if exists, err := isNotDead(st, relationsC, key); err != nil {
  1578  			return nil, errors.Trace(err)
  1579  		} else if exists {
  1580  			return nil, errors.Errorf("relation already exists")
  1581  		}
  1582  		// Collect per-service operations, checking sanity as we go.
  1583  		var ops []txn.Op
  1584  		var subordinateCount int
  1585  		series := map[string]bool{}
  1586  		for _, ep := range eps {
  1587  			svc, err := st.Application(ep.ApplicationName)
  1588  			if errors.IsNotFound(err) {
  1589  				return nil, errors.Errorf("application %q does not exist", ep.ApplicationName)
  1590  			} else if err != nil {
  1591  				return nil, errors.Trace(err)
  1592  			} else if svc.doc.Life != Alive {
  1593  				return nil, errors.Errorf("application %q is not alive", ep.ApplicationName)
  1594  			}
  1595  			if svc.doc.Subordinate {
  1596  				subordinateCount++
  1597  			}
  1598  			series[svc.doc.Series] = true
  1599  			ch, _, err := svc.Charm()
  1600  			if err != nil {
  1601  				return nil, errors.Trace(err)
  1602  			}
  1603  			if !ep.ImplementedBy(ch) {
  1604  				return nil, errors.Errorf("%q does not implement %q", ep.ApplicationName, ep)
  1605  			}
  1606  			ops = append(ops, txn.Op{
  1607  				C:      applicationsC,
  1608  				Id:     st.docID(ep.ApplicationName),
  1609  				Assert: bson.D{{"life", Alive}, {"charmurl", ch.URL()}},
  1610  				Update: bson.D{{"$inc", bson.D{{"relationcount", 1}}}},
  1611  			})
  1612  		}
  1613  		if matchSeries && len(series) != 1 {
  1614  			return nil, errors.Errorf("principal and subordinate applications' series must match")
  1615  		}
  1616  		if eps[0].Scope == charm.ScopeContainer && subordinateCount < 1 {
  1617  			return nil, errors.Errorf("container scoped relation requires at least one subordinate application")
  1618  		}
  1619  
  1620  		// Create a new unique id if that has not already been done, and add
  1621  		// an operation to create the relation document.
  1622  		if id == -1 {
  1623  			var err error
  1624  			if id, err = st.sequence("relation"); err != nil {
  1625  				return nil, errors.Trace(err)
  1626  			}
  1627  		}
  1628  		docID := st.docID(key)
  1629  		doc = &relationDoc{
  1630  			DocID:     docID,
  1631  			Key:       key,
  1632  			ModelUUID: st.ModelUUID(),
  1633  			Id:        id,
  1634  			Endpoints: eps,
  1635  			Life:      Alive,
  1636  		}
  1637  		ops = append(ops, txn.Op{
  1638  			C:      relationsC,
  1639  			Id:     docID,
  1640  			Assert: txn.DocMissing,
  1641  			Insert: doc,
  1642  		})
  1643  		return ops, nil
  1644  	}
  1645  	if err = st.run(buildTxn); err == nil {
  1646  		return &Relation{st, *doc}, nil
  1647  	}
  1648  	return nil, errors.Trace(err)
  1649  }
  1650  
  1651  // EndpointsRelation returns the existing relation with the given endpoints.
  1652  func (st *State) EndpointsRelation(endpoints ...Endpoint) (*Relation, error) {
  1653  	return st.KeyRelation(relationKey(endpoints))
  1654  }
  1655  
  1656  // KeyRelation returns the existing relation with the given key (which can
  1657  // be derived unambiguously from the relation's endpoints).
  1658  func (st *State) KeyRelation(key string) (*Relation, error) {
  1659  	relations, closer := st.getCollection(relationsC)
  1660  	defer closer()
  1661  
  1662  	doc := relationDoc{}
  1663  	err := relations.FindId(key).One(&doc)
  1664  	if err == mgo.ErrNotFound {
  1665  		return nil, errors.NotFoundf("relation %q", key)
  1666  	}
  1667  	if err != nil {
  1668  		return nil, errors.Annotatef(err, "cannot get relation %q", key)
  1669  	}
  1670  	return newRelation(st, &doc), nil
  1671  }
  1672  
  1673  // Relation returns the existing relation with the given id.
  1674  func (st *State) Relation(id int) (*Relation, error) {
  1675  	relations, closer := st.getCollection(relationsC)
  1676  	defer closer()
  1677  
  1678  	doc := relationDoc{}
  1679  	err := relations.Find(bson.D{{"id", id}}).One(&doc)
  1680  	if err == mgo.ErrNotFound {
  1681  		return nil, errors.NotFoundf("relation %d", id)
  1682  	}
  1683  	if err != nil {
  1684  		return nil, errors.Annotatef(err, "cannot get relation %d", id)
  1685  	}
  1686  	return newRelation(st, &doc), nil
  1687  }
  1688  
  1689  // AllRelations returns all relations in the model ordered by id.
  1690  func (st *State) AllRelations() (relations []*Relation, err error) {
  1691  	relationsCollection, closer := st.getCollection(relationsC)
  1692  	defer closer()
  1693  
  1694  	docs := relationDocSlice{}
  1695  	err = relationsCollection.Find(nil).All(&docs)
  1696  	if err != nil {
  1697  		return nil, errors.Annotate(err, "cannot get all relations")
  1698  	}
  1699  	sort.Sort(docs)
  1700  	for _, v := range docs {
  1701  		relations = append(relations, newRelation(st, &v))
  1702  	}
  1703  	return
  1704  }
  1705  
  1706  type relationDocSlice []relationDoc
  1707  
  1708  func (rdc relationDocSlice) Len() int      { return len(rdc) }
  1709  func (rdc relationDocSlice) Swap(i, j int) { rdc[i], rdc[j] = rdc[j], rdc[i] }
  1710  func (rdc relationDocSlice) Less(i, j int) bool {
  1711  	return rdc[i].Id < rdc[j].Id
  1712  }
  1713  
  1714  // Unit returns a unit by name.
  1715  func (st *State) Unit(name string) (*Unit, error) {
  1716  	if !names.IsValidUnit(name) {
  1717  		return nil, errors.Errorf("%q is not a valid unit name", name)
  1718  	}
  1719  	units, closer := st.getCollection(unitsC)
  1720  	defer closer()
  1721  
  1722  	doc := unitDoc{}
  1723  	err := units.FindId(name).One(&doc)
  1724  	if err == mgo.ErrNotFound {
  1725  		return nil, errors.NotFoundf("unit %q", name)
  1726  	}
  1727  	if err != nil {
  1728  		return nil, errors.Annotatef(err, "cannot get unit %q", name)
  1729  	}
  1730  	return newUnit(st, &doc), nil
  1731  }
  1732  
  1733  // UnitsFor returns the units placed in the given machine id.
  1734  func (st *State) UnitsFor(machineId string) ([]*Unit, error) {
  1735  	if !names.IsValidMachine(machineId) {
  1736  		return nil, errors.Errorf("%q is not a valid machine id", machineId)
  1737  	}
  1738  	m := &Machine{
  1739  		st: st,
  1740  		doc: machineDoc{
  1741  			Id: machineId,
  1742  		},
  1743  	}
  1744  	return m.Units()
  1745  }
  1746  
  1747  // AssignUnit places the unit on a machine. Depending on the policy, and the
  1748  // state of the model, this may lead to new instances being launched
  1749  // within the model.
  1750  func (st *State) AssignUnit(u *Unit, policy AssignmentPolicy) (err error) {
  1751  	if !u.IsPrincipal() {
  1752  		return errors.Errorf("subordinate unit %q cannot be assigned directly to a machine", u)
  1753  	}
  1754  	defer errors.DeferredAnnotatef(&err, "cannot assign unit %q to machine", u)
  1755  	var m *Machine
  1756  	switch policy {
  1757  	case AssignLocal:
  1758  		m, err = st.Machine("0")
  1759  		if err != nil {
  1760  			return errors.Trace(err)
  1761  		}
  1762  		return u.AssignToMachine(m)
  1763  	case AssignClean:
  1764  		if _, err = u.AssignToCleanMachine(); errors.Cause(err) != noCleanMachines {
  1765  			return errors.Trace(err)
  1766  		}
  1767  		return u.AssignToNewMachineOrContainer()
  1768  	case AssignCleanEmpty:
  1769  		if _, err = u.AssignToCleanEmptyMachine(); errors.Cause(err) != noCleanMachines {
  1770  			return errors.Trace(err)
  1771  		}
  1772  		return u.AssignToNewMachineOrContainer()
  1773  	case AssignNew:
  1774  		return errors.Trace(u.AssignToNewMachine())
  1775  	}
  1776  	return errors.Errorf("unknown unit assignment policy: %q", policy)
  1777  }
  1778  
  1779  // StartSync forces watchers to resynchronize their state with the
  1780  // database immediately. This will happen periodically automatically.
  1781  func (st *State) StartSync() {
  1782  	st.workers.TxnLogWatcher().StartSync()
  1783  	st.workers.PresenceWatcher().Sync()
  1784  }
  1785  
  1786  // SetAdminMongoPassword sets the administrative password
  1787  // to access the state. If the password is non-empty,
  1788  // all subsequent attempts to access the state must
  1789  // be authorized; otherwise no authorization is required.
  1790  func (st *State) SetAdminMongoPassword(password string) error {
  1791  	err := mongo.SetAdminMongoPassword(st.session, mongo.AdminUser, password)
  1792  	return errors.Trace(err)
  1793  }
  1794  
  1795  type controllersDoc struct {
  1796  	Id               string `bson:"_id"`
  1797  	CloudName        string `bson:"cloud"`
  1798  	ModelUUID        string `bson:"model-uuid"`
  1799  	MachineIds       []string
  1800  	VotingMachineIds []string
  1801  	MongoSpaceName   string `bson:"mongo-space-name"`
  1802  	MongoSpaceState  string `bson:"mongo-space-state"`
  1803  }
  1804  
  1805  // ControllerInfo holds information about currently
  1806  // configured controller machines.
  1807  type ControllerInfo struct {
  1808  	// CloudName is the name of the cloud to which this controller is deployed.
  1809  	CloudName string
  1810  
  1811  	// ModelTag identifies the initial model. Only the initial
  1812  	// model is able to have machines that manage state. The initial
  1813  	// model is the model that is created when bootstrapping.
  1814  	ModelTag names.ModelTag
  1815  
  1816  	// MachineIds holds the ids of all machines configured
  1817  	// to run a controller. It includes all the machine
  1818  	// ids in VotingMachineIds.
  1819  	MachineIds []string
  1820  
  1821  	// VotingMachineIds holds the ids of all machines
  1822  	// configured to run a controller and to have a vote
  1823  	// in peer election.
  1824  	VotingMachineIds []string
  1825  
  1826  	// MongoSpaceName is the space that contains all Mongo servers.
  1827  	MongoSpaceName string
  1828  
  1829  	// MongoSpaceState records the state of the mongo space selection state machine. Valid states are:
  1830  	// * We haven't looked for a Mongo space yet (MongoSpaceUnknown)
  1831  	// * We have looked for a Mongo space, but we didn't find one (MongoSpaceInvalid)
  1832  	// * We have looked for and found a Mongo space (MongoSpaceValid)
  1833  	// * We didn't try to find a Mongo space because the provider doesn't support spaces (MongoSpaceUnsupported)
  1834  	MongoSpaceState MongoSpaceStates
  1835  }
  1836  
  1837  type MongoSpaceStates string
  1838  
  1839  const (
  1840  	MongoSpaceUnknown     MongoSpaceStates = ""
  1841  	MongoSpaceValid       MongoSpaceStates = "valid"
  1842  	MongoSpaceInvalid     MongoSpaceStates = "invalid"
  1843  	MongoSpaceUnsupported MongoSpaceStates = "unsupported"
  1844  )
  1845  
  1846  // ControllerInfo returns information about
  1847  // the currently configured controller machines.
  1848  func (st *State) ControllerInfo() (*ControllerInfo, error) {
  1849  	session := st.session.Copy()
  1850  	defer session.Close()
  1851  	return readRawControllerInfo(st.session)
  1852  }
  1853  
  1854  // readRawControllerInfo reads ControllerInfo direct from the supplied session,
  1855  // falling back to the bootstrap model document to extract the UUID when
  1856  // required.
  1857  func readRawControllerInfo(session *mgo.Session) (*ControllerInfo, error) {
  1858  	db := session.DB(jujuDB)
  1859  	controllers := db.C(controllersC)
  1860  
  1861  	var doc controllersDoc
  1862  	err := controllers.Find(bson.D{{"_id", modelGlobalKey}}).One(&doc)
  1863  	if err == mgo.ErrNotFound {
  1864  		return nil, errors.NotFoundf("controllers document")
  1865  	}
  1866  	if err != nil {
  1867  		return nil, errors.Annotatef(err, "cannot get controllers document")
  1868  	}
  1869  	return &ControllerInfo{
  1870  		CloudName:        doc.CloudName,
  1871  		ModelTag:         names.NewModelTag(doc.ModelUUID),
  1872  		MachineIds:       doc.MachineIds,
  1873  		VotingMachineIds: doc.VotingMachineIds,
  1874  		MongoSpaceName:   doc.MongoSpaceName,
  1875  		MongoSpaceState:  MongoSpaceStates(doc.MongoSpaceState),
  1876  	}, nil
  1877  }
  1878  
  1879  const stateServingInfoKey = "stateServingInfo"
  1880  
  1881  // StateServingInfo returns information for running a controller machine
  1882  func (st *State) StateServingInfo() (StateServingInfo, error) {
  1883  	controllers, closer := st.getCollection(controllersC)
  1884  	defer closer()
  1885  
  1886  	var info StateServingInfo
  1887  	err := controllers.Find(bson.D{{"_id", stateServingInfoKey}}).One(&info)
  1888  	if err != nil {
  1889  		return info, errors.Trace(err)
  1890  	}
  1891  	if info.StatePort == 0 {
  1892  		return StateServingInfo{}, errors.NotFoundf("state serving info")
  1893  	}
  1894  	return info, nil
  1895  }
  1896  
  1897  // SetStateServingInfo stores information needed for running a controller
  1898  func (st *State) SetStateServingInfo(info StateServingInfo) error {
  1899  	if info.StatePort == 0 || info.APIPort == 0 ||
  1900  		info.Cert == "" || info.PrivateKey == "" {
  1901  		return errors.Errorf("incomplete state serving info set in state")
  1902  	}
  1903  	if info.CAPrivateKey == "" {
  1904  		// No CA certificate key means we can't generate new controller
  1905  		// certificates when needed to add to the certificate SANs.
  1906  		// Older Juju deployments discard the key because no one realised
  1907  		// the certificate was flawed, so at best we can log a warning
  1908  		// until an upgrade process is written.
  1909  		logger.Warningf("state serving info has no CA certificate key")
  1910  	}
  1911  	ops := []txn.Op{{
  1912  		C:      controllersC,
  1913  		Id:     stateServingInfoKey,
  1914  		Update: bson.D{{"$set", info}},
  1915  	}}
  1916  	if err := st.runTransaction(ops); err != nil {
  1917  		return errors.Annotatef(err, "cannot set state serving info")
  1918  	}
  1919  	return nil
  1920  }
  1921  
  1922  // SetSystemIdentity sets the system identity value in the database
  1923  // if and only iff it is empty.
  1924  func SetSystemIdentity(st *State, identity string) error {
  1925  	ops := []txn.Op{{
  1926  		C:      controllersC,
  1927  		Id:     stateServingInfoKey,
  1928  		Assert: bson.D{{"systemidentity", ""}},
  1929  		Update: bson.D{{"$set", bson.D{{"systemidentity", identity}}}},
  1930  	}}
  1931  
  1932  	if err := st.runTransaction(ops); err != nil {
  1933  		return errors.Trace(err)
  1934  	}
  1935  	return nil
  1936  }
  1937  
  1938  // SetOrGetMongoSpaceName attempts to set the Mongo space or, if that fails, look
  1939  // up the current Mongo space. Either way, it always returns what is in the
  1940  // database by the end of the call.
  1941  func (st *State) SetOrGetMongoSpaceName(mongoSpaceName network.SpaceName) (network.SpaceName, error) {
  1942  	err := st.setMongoSpaceName(mongoSpaceName)
  1943  	if err == txn.ErrAborted {
  1944  		// Failed to set the new space name. Return what is already stored in state.
  1945  		controllerInfo, err := st.ControllerInfo()
  1946  		if err != nil {
  1947  			return network.SpaceName(""), errors.Trace(err)
  1948  		}
  1949  		return network.SpaceName(controllerInfo.MongoSpaceName), nil
  1950  	} else if err != nil {
  1951  		return network.SpaceName(""), errors.Trace(err)
  1952  	}
  1953  	return mongoSpaceName, nil
  1954  }
  1955  
  1956  // SetMongoSpaceState attempts to set the Mongo space state or, if that fails, look
  1957  // up the current Mongo state. Either way, it always returns what is in the
  1958  // database by the end of the call.
  1959  func (st *State) SetMongoSpaceState(mongoSpaceState MongoSpaceStates) error {
  1960  
  1961  	if mongoSpaceState != MongoSpaceUnknown &&
  1962  		mongoSpaceState != MongoSpaceValid &&
  1963  		mongoSpaceState != MongoSpaceInvalid &&
  1964  		mongoSpaceState != MongoSpaceUnsupported {
  1965  		return errors.NotValidf("mongoSpaceState: %s", mongoSpaceState)
  1966  	}
  1967  
  1968  	err := st.setMongoSpaceState(mongoSpaceState)
  1969  	if err != nil {
  1970  		return errors.Trace(err)
  1971  	}
  1972  	return nil
  1973  }
  1974  
  1975  func (st *State) setMongoSpaceName(mongoSpaceName network.SpaceName) error {
  1976  	ops := []txn.Op{{
  1977  		C:      controllersC,
  1978  		Id:     modelGlobalKey,
  1979  		Assert: bson.D{{"mongo-space-state", string(MongoSpaceUnknown)}},
  1980  		Update: bson.D{{
  1981  			"$set",
  1982  			bson.D{
  1983  				{"mongo-space-name", string(mongoSpaceName)},
  1984  				{"mongo-space-state", MongoSpaceValid},
  1985  			},
  1986  		}},
  1987  	}}
  1988  
  1989  	return st.runTransaction(ops)
  1990  }
  1991  
  1992  func (st *State) setMongoSpaceState(mongoSpaceState MongoSpaceStates) error {
  1993  	ops := []txn.Op{{
  1994  		C:      controllersC,
  1995  		Id:     modelGlobalKey,
  1996  		Update: bson.D{{"$set", bson.D{{"mongo-space-state", mongoSpaceState}}}},
  1997  	}}
  1998  
  1999  	return st.runTransaction(ops)
  2000  }
  2001  
  2002  func (st *State) networkEntityGlobalKeyOp(globalKey string, providerId network.Id) txn.Op {
  2003  	key := st.networkEntityGlobalKey(globalKey, providerId)
  2004  	return txn.Op{
  2005  		C:      providerIDsC,
  2006  		Id:     key,
  2007  		Assert: txn.DocMissing,
  2008  		Insert: providerIdDoc{ID: key},
  2009  	}
  2010  }
  2011  
  2012  func (st *State) networkEntityGlobalKeyRemoveOp(globalKey string, providerId network.Id) txn.Op {
  2013  	key := st.networkEntityGlobalKey(globalKey, providerId)
  2014  	return txn.Op{
  2015  		C:      providerIDsC,
  2016  		Id:     key,
  2017  		Remove: true,
  2018  	}
  2019  }
  2020  
  2021  func (st *State) networkEntityGlobalKey(globalKey string, providerId network.Id) string {
  2022  	return st.docID(globalKey + ":" + string(providerId))
  2023  }
  2024  
  2025  // PutAuditEntryFn returns a function which will persist
  2026  // audit.AuditEntry instances to the database.
  2027  func (st *State) PutAuditEntryFn() func(audit.AuditEntry) error {
  2028  	insert := func(collectionName string, docs ...interface{}) error {
  2029  		collection, closeCollection := st.getCollection(collectionName)
  2030  		defer closeCollection()
  2031  
  2032  		writeableCollection := collection.Writeable()
  2033  
  2034  		return errors.Trace(writeableCollection.Insert(docs...))
  2035  	}
  2036  	return stateaudit.PutAuditEntryFn(auditingC, insert)
  2037  }
  2038  
  2039  var tagPrefix = map[byte]string{
  2040  	'm': names.MachineTagKind + "-",
  2041  	'a': names.ApplicationTagKind + "-",
  2042  	'u': names.UnitTagKind + "-",
  2043  	'e': names.ModelTagKind + "-",
  2044  	'r': names.RelationTagKind + "-",
  2045  }
  2046  
  2047  func tagForGlobalKey(key string) (string, bool) {
  2048  	if len(key) < 3 || key[1] != '#' {
  2049  		return "", false
  2050  	}
  2051  	p, ok := tagPrefix[key[0]]
  2052  	if !ok {
  2053  		return "", false
  2054  	}
  2055  	return p + key[2:], true
  2056  }
  2057  
  2058  // SetClockForTesting is an exported function to allow other packages
  2059  // to set the internal clock for the State instance. It is named such
  2060  // that it should be obvious if it is ever called from a non-test packgae.
  2061  func (st *State) SetClockForTesting(clock clock.Clock) error {
  2062  	st.clock = clock
  2063  	// Need to restart the lease workers so they get the new clock.
  2064  	st.workers.Kill()
  2065  	err := st.workers.Wait()
  2066  	if err != nil {
  2067  		return errors.Trace(err)
  2068  	}
  2069  	err = st.start(st.controllerTag)
  2070  	if err != nil {
  2071  		return errors.Trace(err)
  2072  	}
  2073  	return nil
  2074  }