github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/state.go (about)

     1  // Copyright 2012-2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state
     5  
     6  import (
     7  	"fmt"
     8  	"regexp"
     9  	"sort"
    10  	"strconv"
    11  	"strings"
    12  	"time"
    13  
    14  	"github.com/juju/charm/v12"
    15  	"github.com/juju/clock"
    16  	"github.com/juju/collections/set"
    17  	"github.com/juju/errors"
    18  	"github.com/juju/loggo"
    19  	"github.com/juju/mgo/v3"
    20  	"github.com/juju/mgo/v3/bson"
    21  	"github.com/juju/mgo/v3/txn"
    22  	"github.com/juju/names/v5"
    23  	"github.com/juju/pubsub/v2"
    24  	jujutxn "github.com/juju/txn/v3"
    25  	"github.com/juju/utils/v3"
    26  	"github.com/juju/version/v2"
    27  
    28  	corebase "github.com/juju/juju/core/base"
    29  	corecharm "github.com/juju/juju/core/charm"
    30  	"github.com/juju/juju/core/config"
    31  	"github.com/juju/juju/core/constraints"
    32  	"github.com/juju/juju/core/instance"
    33  	corenetwork "github.com/juju/juju/core/network"
    34  	"github.com/juju/juju/core/permission"
    35  	"github.com/juju/juju/core/status"
    36  	"github.com/juju/juju/mongo"
    37  	"github.com/juju/juju/state/cloudimagemetadata"
    38  	stateerrors "github.com/juju/juju/state/errors"
    39  	"github.com/juju/juju/state/watcher"
    40  	"github.com/juju/juju/storage"
    41  	jujuversion "github.com/juju/juju/version"
    42  )
    43  
    44  var logger = loggo.GetLogger("juju.state")
    45  
    46  const (
    47  	// jujuDB is the name of the main juju database.
    48  	jujuDB = "juju"
    49  
    50  	// blobstoreDB is the name of the blobstore GridFS database.
    51  	blobstoreDB = "blobstore"
    52  )
    53  
    54  type providerIdDoc struct {
    55  	ID string `bson:"_id"` // format: "<model-uuid>:<global-key>:<provider-id>"
    56  }
    57  
    58  // State represents the state of an model
    59  // managed by juju.
    60  type State struct {
    61  	stateClock             clock.Clock
    62  	modelTag               names.ModelTag
    63  	controllerModelTag     names.ModelTag
    64  	controllerTag          names.ControllerTag
    65  	session                *mgo.Session
    66  	database               Database
    67  	policy                 Policy
    68  	newPolicy              NewPolicyFunc
    69  	runTransactionObserver RunTransactionObserverFunc
    70  	maxTxnAttempts         int
    71  
    72  	// workers is responsible for keeping the various sub-workers
    73  	// available by starting new ones as they fail. It doesn't do
    74  	// that yet, but having a type that collects them together is the
    75  	// first step.
    76  	workers *workers
    77  
    78  	// TODO(anastasiamac 2015-07-16) As state gets broken up, remove this.
    79  	CloudImageMetadataStorage cloudimagemetadata.Storage
    80  }
    81  
    82  func (st *State) newStateNoWorkers(modelUUID string) (*State, error) {
    83  	session := st.session.Copy()
    84  	newSt, err := newState(
    85  		st.controllerTag,
    86  		names.NewModelTag(modelUUID),
    87  		st.controllerModelTag,
    88  		session,
    89  		st.newPolicy,
    90  		st.stateClock,
    91  		st.runTransactionObserver,
    92  		st.maxTxnAttempts,
    93  	)
    94  	// We explicitly don't start the workers.
    95  	if err != nil {
    96  		session.Close()
    97  		return nil, errors.Trace(err)
    98  	}
    99  	return newSt, nil
   100  }
   101  
   102  // IsController returns true if this state instance has the bootstrap
   103  // model UUID.
   104  func (st *State) IsController() bool {
   105  	return st.modelTag == st.controllerModelTag
   106  }
   107  
   108  // ControllerUUID returns the UUID for the controller
   109  // of this state instance.
   110  func (st *State) ControllerUUID() string {
   111  	return st.controllerTag.Id()
   112  }
   113  
   114  // ControllerTag returns the tag form of the ControllerUUID.
   115  func (st *State) ControllerTag() names.ControllerTag {
   116  	return st.controllerTag
   117  }
   118  
   119  // ControllerTimestamp returns the current timestamp of the backend
   120  // controller.
   121  func (st *State) ControllerTimestamp() (*time.Time, error) {
   122  	now := st.clock().Now()
   123  	return &now, nil
   124  }
   125  
   126  // ControllerModelUUID returns the UUID of the model that was
   127  // bootstrapped.  This is the only model that can have controller
   128  // machines.  The owner of this model is also considered "special", in
   129  // that they are the only user that is able to create other users
   130  // (until we have more fine grained permissions), and they cannot be
   131  // disabled.
   132  func (st *State) ControllerModelUUID() string {
   133  	return st.controllerModelTag.Id()
   134  }
   135  
   136  // ControllerModelTag returns the tag form the return value of
   137  // ControllerModelUUID.
   138  func (st *State) ControllerModelTag() names.ModelTag {
   139  	return st.controllerModelTag
   140  }
   141  
   142  // ControllerOwner returns the owner of the controller model.
   143  func (st *State) ControllerOwner() (names.UserTag, error) {
   144  	models, closer := st.db().GetCollection(modelsC)
   145  	defer closer()
   146  	var doc map[string]string
   147  	err := models.FindId(st.ControllerModelUUID()).Select(bson.M{"owner": 1}).One(&doc)
   148  	if err != nil {
   149  		return names.UserTag{}, errors.Annotate(err, "loading controller model")
   150  	}
   151  	owner := doc["owner"]
   152  	if owner == "" {
   153  		return names.UserTag{}, errors.New("model owner missing")
   154  	}
   155  	return names.NewUserTag(owner), nil
   156  }
   157  
   158  func ControllerAccess(st *State, tag names.Tag) (permission.UserAccess, error) {
   159  	return st.UserAccess(tag.(names.UserTag), st.controllerTag)
   160  }
   161  
   162  // setDyingModelToDead sets current dying model to dead.
   163  func (st *State) setDyingModelToDead() error {
   164  	buildTxn := func(attempt int) ([]txn.Op, error) {
   165  		model, err := st.Model()
   166  		if err != nil {
   167  			return nil, errors.Trace(err)
   168  		}
   169  		if model.Life() != Dying {
   170  			return nil, errors.Trace(ErrModelNotDying)
   171  		}
   172  		ops := []txn.Op{{
   173  			C:      modelsC,
   174  			Id:     st.ModelUUID(),
   175  			Assert: isDyingDoc,
   176  			Update: bson.M{"$set": bson.M{
   177  				"life":          Dead,
   178  				"time-of-death": st.nowToTheSecond(),
   179  			}},
   180  		}, {
   181  			// Cleanup the owner:modelName unique key.
   182  			C:      usermodelnameC,
   183  			Id:     model.uniqueIndexID(),
   184  			Remove: true,
   185  		}}
   186  		return ops, nil
   187  	}
   188  	if err := st.db().Run(buildTxn); err != nil {
   189  		return errors.Trace(err)
   190  	}
   191  	return nil
   192  }
   193  
   194  // RemoveDyingModel sets current model to dead then removes all documents from
   195  // multi-model collections.
   196  func (st *State) RemoveDyingModel() error {
   197  	model, err := st.Model()
   198  	if err != nil {
   199  		return errors.Trace(err)
   200  	}
   201  	if model.Life() == Alive {
   202  		return errors.Errorf("can't remove model: model still alive")
   203  	}
   204  	if model.Life() == Dying {
   205  		// set model to dead if it's dying.
   206  		if err = st.setDyingModelToDead(); err != nil {
   207  			return errors.Trace(err)
   208  		}
   209  	}
   210  	err = st.removeAllModelDocs(bson.D{{"life", Dead}})
   211  	if errors.Cause(err) == txn.ErrAborted {
   212  		return errors.Wrap(err, errors.New("can't remove model: model not dead"))
   213  	}
   214  	return errors.Trace(err)
   215  }
   216  
   217  // RemoveImportingModelDocs removes all documents from multi-model collections
   218  // for the current model. This method asserts that the model's migration mode
   219  // is "importing".
   220  func (st *State) RemoveImportingModelDocs() error {
   221  	err := st.removeAllModelDocs(bson.D{{"migration-mode", MigrationModeImporting}})
   222  	if errors.Cause(err) == txn.ErrAborted {
   223  		return errors.New("can't remove model: model not being imported for migration")
   224  	}
   225  	return errors.Trace(err)
   226  }
   227  
   228  // RemoveExportingModelDocs removes all documents from multi-model collections
   229  // for the current model. This method asserts that the model's migration mode
   230  // is "exporting".
   231  func (st *State) RemoveExportingModelDocs() error {
   232  	err := st.removeAllModelDocs(bson.D{{"migration-mode", MigrationModeExporting}})
   233  	if errors.Cause(err) == txn.ErrAborted {
   234  		return errors.Wrap(err, errors.New("can't remove model: model not being exported for migration"))
   235  	}
   236  	return errors.Trace(err)
   237  }
   238  
   239  func cleanupSecretBackendRefCountAfterModelMigrationDone(st *State) error {
   240  	col, closer := st.db().GetCollection(secretRevisionsC)
   241  	defer closer()
   242  	pipe := col.Pipe([]bson.M{
   243  		{
   244  			"$match": bson.M{
   245  				"value-reference.backend-id": bson.M{
   246  					"$exists": true,
   247  					"$ne":     "",
   248  				},
   249  			},
   250  		},
   251  		{
   252  			"$group": bson.M{
   253  				"_id": "$value-reference.backend-id", "count": bson.M{"$sum": 1},
   254  			},
   255  		},
   256  	})
   257  	var result []struct {
   258  		ID    string `bson:"_id"`
   259  		Count int    `bson:"count"`
   260  	}
   261  	if err := pipe.All(&result); err != nil {
   262  		return errors.Trace(err)
   263  	}
   264  	if len(result) == 0 {
   265  		return nil
   266  	}
   267  
   268  	var ops []txn.Op
   269  	for _, r := range result {
   270  		for i := r.Count; i > 0; i-- {
   271  			refOps, err := st.decSecretBackendRefCountOp(r.ID)
   272  			if err != nil {
   273  				return errors.Trace(err)
   274  			}
   275  			ops = append(ops, refOps...)
   276  		}
   277  	}
   278  	return st.db().RunTransaction(ops)
   279  }
   280  
   281  func (st *State) removeAllModelDocs(modelAssertion bson.D) error {
   282  	// Remove permissions first, because we potentially
   283  	// remove parent documents in the following stage.
   284  	if err := st.removeAllModelPermissions(); err != nil {
   285  		return errors.Annotate(err, "removing permissions")
   286  	}
   287  
   288  	if err := cleanupSecretBackendRefCountAfterModelMigrationDone(st); err != nil {
   289  		// We have to do this before secrets get removed.
   290  		return errors.Trace(err)
   291  	}
   292  
   293  	// Remove each collection in its own transaction.
   294  	modelUUID := st.ModelUUID()
   295  	for name, info := range st.database.Schema() {
   296  		if info.global || info.rawAccess {
   297  			continue
   298  		}
   299  
   300  		ops, err := st.removeAllInCollectionOps(name)
   301  		if err != nil {
   302  			return errors.Trace(err)
   303  		}
   304  		if len(ops) == 0 {
   305  			// Nothing to delete.
   306  			continue
   307  		}
   308  		// Make sure we gate everything on the model assertion.
   309  		ops = append([]txn.Op{{
   310  			C:      modelsC,
   311  			Id:     modelUUID,
   312  			Assert: modelAssertion,
   313  		}}, ops...)
   314  		err = st.db().RunTransaction(ops)
   315  		if err != nil {
   316  			return errors.Annotatef(err, "removing from collection %q", name)
   317  		}
   318  	}
   319  
   320  	// Remove from the raw (non-transactional) collections.
   321  	for name, info := range st.database.Schema() {
   322  		if !info.global && info.rawAccess {
   323  			if err := st.removeAllInCollectionRaw(name); err != nil {
   324  				return errors.Trace(err)
   325  			}
   326  		}
   327  	}
   328  
   329  	// Logs are in a separate database so don't get caught by that loop.
   330  	_ = removeModelLogs(st.MongoSession(), modelUUID)
   331  
   332  	// Now remove the model.
   333  	model, err := st.Model()
   334  	if err != nil {
   335  		return errors.Trace(err)
   336  	}
   337  	ops := []txn.Op{{
   338  		// Cleanup the owner:envName unique key.
   339  		C:      usermodelnameC,
   340  		Id:     model.uniqueIndexID(),
   341  		Remove: true,
   342  	}, {
   343  		C:      modelEntityRefsC,
   344  		Id:     modelUUID,
   345  		Remove: true,
   346  	}, {
   347  		C:      modelsC,
   348  		Id:     modelUUID,
   349  		Assert: modelAssertion,
   350  		Remove: true,
   351  	}}
   352  
   353  	// Decrement the model count for the cloud to which this model belongs.
   354  	decCloudRefOp, err := decCloudModelRefOp(st, model.CloudName())
   355  	if err != nil {
   356  		return errors.Trace(err)
   357  	}
   358  	ops = append(ops, decCloudRefOp)
   359  
   360  	if !st.IsController() {
   361  		ops = append(ops, decHostedModelCountOp())
   362  	}
   363  	return errors.Trace(st.db().RunTransaction(ops))
   364  }
   365  
   366  // removeAllModelPermissions removes all direct permissions documents for
   367  // this model, and all permissions for offers hosted by this model.
   368  func (st *State) removeAllModelPermissions() error {
   369  	var permOps []txn.Op
   370  	permPattern := bson.M{
   371  		"_id": bson.M{"$regex": "^" + permissionID(modelKey(st.ModelUUID()), "")},
   372  	}
   373  	ops, err := st.removeInCollectionOps(permissionsC, permPattern)
   374  	if err != nil {
   375  		return errors.Trace(err)
   376  	}
   377  	permOps = append(permOps, ops...)
   378  
   379  	applicationOffersCollection, closer := st.db().GetCollection(applicationOffersC)
   380  	defer closer()
   381  
   382  	var offerDocs []applicationOfferDoc
   383  	if err := applicationOffersCollection.Find(bson.D{}).All(&offerDocs); err != nil {
   384  		return errors.Annotate(err, "getting application offer documents")
   385  	}
   386  
   387  	for _, offer := range offerDocs {
   388  		permPattern = bson.M{
   389  			"_id": bson.M{"$regex": "^" + permissionID(applicationOfferKey(offer.OfferUUID), "")},
   390  		}
   391  		ops, err = st.removeInCollectionOps(permissionsC, permPattern)
   392  		if err != nil {
   393  			return errors.Trace(err)
   394  		}
   395  		permOps = append(permOps, ops...)
   396  	}
   397  	err = st.db().RunTransaction(permOps)
   398  	return errors.Trace(err)
   399  }
   400  
   401  // removeAllInCollectionRaw removes all the documents from the given
   402  // named collection.
   403  func (st *State) removeAllInCollectionRaw(name string) error {
   404  	coll, closer := st.db().GetCollection(name)
   405  	defer closer()
   406  	_, err := coll.Writeable().RemoveAll(nil)
   407  	return errors.Trace(err)
   408  }
   409  
   410  // removeAllInCollectionOps appends to ops operations to
   411  // remove all the documents in the given named collection.
   412  func (st *State) removeAllInCollectionOps(name string) ([]txn.Op, error) {
   413  	return st.removeInCollectionOps(name, nil)
   414  }
   415  
   416  // removeInCollectionOps generates operations to remove all documents
   417  // from the named collection matching a specific selector.
   418  func (st *State) removeInCollectionOps(name string, sel interface{}) ([]txn.Op, error) {
   419  	coll, closer := st.db().GetCollection(name)
   420  	defer closer()
   421  
   422  	var ids []bson.M
   423  	err := coll.Find(sel).Select(bson.D{{"_id", 1}}).All(&ids)
   424  	if err != nil {
   425  		return nil, errors.Trace(err)
   426  	}
   427  	var ops []txn.Op
   428  	for _, id := range ids {
   429  		ops = append(ops, txn.Op{
   430  			C:      name,
   431  			Id:     id["_id"],
   432  			Remove: true,
   433  		})
   434  	}
   435  	return ops, nil
   436  }
   437  
   438  // startWorkers starts the worker backends on the *State
   439  //   - txn log watcher
   440  //   - txn log pruner
   441  //
   442  // startWorkers will close the *State if it fails.
   443  func (st *State) startWorkers(hub *pubsub.SimpleHub) (err error) {
   444  	defer func() {
   445  		if err == nil {
   446  			return
   447  		}
   448  		if err2 := st.Close(); err2 != nil {
   449  			logger.Errorf("closing State for %s: %v", st.modelTag, err2)
   450  		}
   451  	}()
   452  
   453  	logger.Infof("starting standard state workers")
   454  	workers, err := newWorkers(st, hub)
   455  	if err != nil {
   456  		return errors.Trace(err)
   457  	}
   458  	st.workers = workers
   459  	logger.Infof("started state workers for %s successfully", st.modelTag)
   460  	return nil
   461  }
   462  
   463  // ModelUUID returns the model UUID for the model
   464  // controlled by this state instance.
   465  func (st *State) ModelUUID() string {
   466  	return st.modelTag.Id()
   467  }
   468  
   469  // userModelNameIndex returns a string to be used as a usermodelnameC unique index.
   470  func userModelNameIndex(username, modelName string) string {
   471  	return strings.ToLower(username) + ":" + modelName
   472  }
   473  
   474  // EnsureModelRemoved returns an error if any multi-model
   475  // documents for this model are found. It is intended only to be used in
   476  // tests and exported so it can be used in the tests of other packages.
   477  func (st *State) EnsureModelRemoved() error {
   478  	found := map[string]int{}
   479  	var foundOrdered []string
   480  	for name, info := range st.database.Schema() {
   481  		if info.global {
   482  			continue
   483  		}
   484  
   485  		if err := func(name string, info CollectionInfo) error {
   486  			coll, closer := st.db().GetCollection(name)
   487  			defer closer()
   488  
   489  			n, err := coll.Find(nil).Count()
   490  			if err != nil {
   491  				return errors.Trace(err)
   492  			}
   493  
   494  			if n != 0 {
   495  				found[name] = n
   496  				foundOrdered = append(foundOrdered, name)
   497  			}
   498  			return nil
   499  		}(name, info); err != nil {
   500  			return errors.Trace(err)
   501  		}
   502  	}
   503  
   504  	if len(found) != 0 {
   505  		errMessage := fmt.Sprintf("found documents for model with uuid %s:", st.ModelUUID())
   506  		sort.Strings(foundOrdered)
   507  		for _, name := range foundOrdered {
   508  			number := found[name]
   509  			errMessage += fmt.Sprintf(" %d %s doc,", number, name)
   510  		}
   511  		// Remove trailing comma.
   512  		errMessage = errMessage[:len(errMessage)-1]
   513  		return errors.New(errMessage)
   514  	}
   515  	return nil
   516  }
   517  
   518  // newDB returns a database connection using a new session, along with
   519  // a closer function for the session. This is useful where you need to work
   520  // with various collections in a single session, so don't want to call
   521  // getCollection multiple times.
   522  func (st *State) newDB() (Database, func()) {
   523  	return st.database.Copy()
   524  }
   525  
   526  // db returns the Database instance used by the State. It is part of
   527  // the modelBackend interface.
   528  func (st *State) db() Database {
   529  	return st.database
   530  }
   531  
   532  // txnLogWatcher returns the TxnLogWatcher for the State. It is part
   533  // of the modelBackend interface.
   534  func (st *State) txnLogWatcher() watcher.BaseWatcher {
   535  	return st.workers.txnLogWatcher()
   536  }
   537  
   538  // Ping probes the state's database connection to ensure
   539  // that it is still alive.
   540  func (st *State) Ping() error {
   541  	return st.session.Ping()
   542  }
   543  
   544  // MongoVersion return the string repre
   545  func (st *State) MongoVersion() (string, error) {
   546  	binfo, err := st.session.BuildInfo()
   547  	if err != nil {
   548  		return "", errors.Annotate(err, "cannot obtain mongo build info")
   549  	}
   550  	return binfo.Version, nil
   551  }
   552  
   553  // MongoSession returns the underlying mongodb session
   554  // used by the state. It is exposed so that external code
   555  // can maintain the mongo replica set and should not
   556  // otherwise be used.
   557  func (st *State) MongoSession() *mgo.Session {
   558  	return st.session
   559  }
   560  
   561  // WatchParams defines config to control which
   562  // entites are included when watching a model.
   563  type WatchParams struct {
   564  	// IncludeOffers controls whether application offers should be watched.
   565  	IncludeOffers bool
   566  }
   567  
   568  func (st *State) checkCanUpgradeCAAS(currentVersion, newVersion string) error {
   569  	// TODO(caas)
   570  	return nil
   571  }
   572  
   573  func (st *State) checkCanUpgradeIAAS(currentVersion, newVersion string) error {
   574  	matchCurrent := "^" + regexp.QuoteMeta(currentVersion) + "-"
   575  	matchNew := "^" + regexp.QuoteMeta(newVersion) + "-"
   576  	// Get all machines and units with a different or empty version.
   577  	sel := bson.D{{"$or", []bson.D{
   578  		{{"tools", bson.D{{"$exists", false}}}},
   579  		{{"$and", []bson.D{
   580  			{{"tools.version", bson.D{{"$not", bson.RegEx{matchCurrent, ""}}}}},
   581  			{{"tools.version", bson.D{{"$not", bson.RegEx{matchNew, ""}}}}},
   582  		}}},
   583  	}}}
   584  	var agentTags []string
   585  	for _, name := range []string{machinesC, unitsC} {
   586  		collection, closer := st.db().GetCollection(name)
   587  		defer closer()
   588  		var doc struct {
   589  			DocID string `bson:"_id"`
   590  		}
   591  		iter := collection.Find(sel).Select(bson.D{{"_id", 1}}).Iter()
   592  		defer iter.Close()
   593  		for iter.Next(&doc) {
   594  			localID, err := st.strictLocalID(doc.DocID)
   595  			if err != nil {
   596  				return errors.Trace(err)
   597  			}
   598  			switch name {
   599  			case machinesC:
   600  				agentTags = append(agentTags, names.NewMachineTag(localID).String())
   601  			case unitsC:
   602  				agentTags = append(agentTags, names.NewUnitTag(localID).String())
   603  			}
   604  		}
   605  		if err := iter.Close(); err != nil {
   606  			return errors.Trace(err)
   607  		}
   608  	}
   609  	if len(agentTags) > 0 {
   610  		err := newVersionInconsistentError(version.MustParse(currentVersion), agentTags)
   611  		return errors.Trace(err)
   612  	}
   613  	return nil
   614  }
   615  
   616  // SetModelAgentVersion changes the agent version for the model to the
   617  // given version, only if the model is in a stable state (all agents are
   618  // running the current version). If this is a hosted model, newVersion
   619  // cannot be higher than the controller version.
   620  func (st *State) SetModelAgentVersion(newVersion version.Number, stream *string, ignoreAgentVersions bool) (err error) {
   621  	if newVersion.Compare(jujuversion.Current) > 0 && !st.IsController() {
   622  		return errors.Errorf("model cannot be upgraded to %s while the controller is %s: upgrade 'controller' model first",
   623  			newVersion.String(),
   624  			jujuversion.Current,
   625  		)
   626  	}
   627  
   628  	model, err := st.Model()
   629  	if err != nil {
   630  		return errors.Trace(err)
   631  	}
   632  	isCAAS := model.Type() == ModelTypeCAAS
   633  	buildTxn := func(attempt int) ([]txn.Op, error) {
   634  		settings, err := readSettings(st.db(), settingsC, modelGlobalKey)
   635  		if err != nil {
   636  			return nil, errors.Annotatef(err, "model %q", st.modelTag.Id())
   637  		}
   638  		agentVersion, ok := settings.Get("agent-version")
   639  		if !ok {
   640  			return nil, errors.Errorf("no agent version set in the model")
   641  		}
   642  		currentVersion, ok := agentVersion.(string)
   643  		if !ok {
   644  			return nil, errors.Errorf("invalid agent version format: expected string, got %v", agentVersion)
   645  		}
   646  		if newVersion.String() == currentVersion {
   647  			// Nothing to do.
   648  			return nil, jujutxn.ErrNoOperations
   649  		}
   650  		agentStream, _ := settings.Get("agent-stream")
   651  		currentStream, _ := agentStream.(string)
   652  		newStream := currentStream
   653  		if stream != nil {
   654  			if (*stream != "" || currentStream != "released") && (*stream != "released" || currentStream != "") {
   655  				newStream = *stream
   656  			}
   657  		}
   658  
   659  		if !ignoreAgentVersions {
   660  			if isCAAS {
   661  				if err := st.checkCanUpgradeCAAS(currentVersion, newVersion.String()); err != nil {
   662  					return nil, errors.Trace(err)
   663  				}
   664  			} else {
   665  				if err := st.checkCanUpgradeIAAS(currentVersion, newVersion.String()); err != nil {
   666  					return nil, errors.Trace(err)
   667  				}
   668  			}
   669  		}
   670  
   671  		ops := []txn.Op{
   672  			// Can't set agent-version if there's an active upgradeInfo doc.
   673  			{
   674  				C:      upgradeInfoC,
   675  				Id:     currentUpgradeId,
   676  				Assert: txn.DocMissing,
   677  			}, {
   678  				C:      settingsC,
   679  				Id:     st.docID(modelGlobalKey),
   680  				Assert: bson.D{{"version", settings.version}},
   681  				Update: bson.D{
   682  					{"$set", bson.D{
   683  						{"settings.agent-version", newVersion.String()},
   684  						{"settings.agent-stream", newStream},
   685  					}},
   686  				},
   687  			},
   688  		}
   689  		return ops, nil
   690  	}
   691  	if err = st.db().Run(buildTxn); err == jujutxn.ErrExcessiveContention {
   692  		// Although there is a small chance of a race here, try to
   693  		// return a more helpful error message in the case of an
   694  		// active upgradeInfo document being in place.
   695  		if upgrading, _ := st.IsUpgrading(); upgrading {
   696  			err = stateerrors.ErrUpgradeInProgress
   697  		} else {
   698  			err = errors.Annotate(err, "cannot set agent version")
   699  		}
   700  	}
   701  	return errors.Trace(err)
   702  }
   703  
   704  // ModelConstraints returns the current model constraints.
   705  func (st *State) ModelConstraints() (constraints.Value, error) {
   706  	cons, err := readConstraints(st, modelGlobalKey)
   707  	return cons, errors.Trace(err)
   708  }
   709  
   710  // SetModelConstraints replaces the current model constraints.
   711  func (st *State) SetModelConstraints(cons constraints.Value) error {
   712  	unsupported, err := st.validateConstraints(cons)
   713  	if len(unsupported) > 0 {
   714  		logger.Warningf(
   715  			"setting model constraints: unsupported constraints: %v", strings.Join(unsupported, ","))
   716  	} else if err != nil {
   717  		return errors.Trace(err)
   718  	}
   719  	return writeConstraints(st, modelGlobalKey, cons)
   720  }
   721  
   722  func (st *State) allMachines(machinesCollection mongo.Collection) ([]*Machine, error) {
   723  	mdocs := machineDocSlice{}
   724  	err := machinesCollection.Find(nil).All(&mdocs)
   725  	if err != nil {
   726  		return nil, errors.Annotatef(err, "cannot get all machines")
   727  	}
   728  	sort.Sort(mdocs)
   729  	machines := make([]*Machine, len(mdocs))
   730  	for i, doc := range mdocs {
   731  		machines[i] = newMachine(st, &doc)
   732  	}
   733  	return machines, nil
   734  }
   735  
   736  // AllMachines returns all machines in the model
   737  // ordered by id.
   738  func (st *State) AllMachines() ([]*Machine, error) {
   739  	machinesCollection, closer := st.db().GetCollection(machinesC)
   740  	defer closer()
   741  	return st.allMachines(machinesCollection)
   742  }
   743  
   744  // MachineCountForBase counts the machines for the provided bases in the model.
   745  // The bases must all be for the one os.
   746  func (st *State) MachineCountForBase(base ...Base) (map[string]int, error) {
   747  	machinesCollection, closer := st.db().GetCollection(machinesC)
   748  	defer closer()
   749  
   750  	var (
   751  		os       string
   752  		channels []string
   753  	)
   754  	for _, b := range base {
   755  		if os != "" && os != b.OS {
   756  			return nil, errors.New("bases must all be for the same OS")
   757  		}
   758  		os = b.OS
   759  		channels = append(channels, b.Normalise().Channel)
   760  	}
   761  
   762  	var docs []machineDoc
   763  	err := machinesCollection.Find(bson.D{
   764  		{"base.channel", bson.D{{"$in", channels}}},
   765  		{"base.os", os},
   766  	}).Select(bson.M{"base": 1}).All(&docs)
   767  	if err != nil {
   768  		return nil, errors.Trace(err)
   769  	}
   770  	result := make(map[string]int)
   771  	for _, m := range docs {
   772  		b := m.Base.DisplayString()
   773  		result[b] = result[b] + 1
   774  	}
   775  	return result, nil
   776  }
   777  
   778  type machineDocSlice []machineDoc
   779  
   780  func (ms machineDocSlice) Len() int      { return len(ms) }
   781  func (ms machineDocSlice) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] }
   782  func (ms machineDocSlice) Less(i, j int) bool {
   783  	return machineIdLessThan(ms[i].Id, ms[j].Id)
   784  }
   785  
   786  // machineIdLessThan returns true if id1 < id2, false otherwise.
   787  // Machine ids may include "/" separators if they are for a container so
   788  // the comparison is done by comparing the id component values from
   789  // left to right (most significant part to least significant). Ids for
   790  // host machines are always less than ids for their containers.
   791  func machineIdLessThan(id1, id2 string) bool {
   792  	// Most times, we are dealing with host machines and not containers, so we will
   793  	// try interpreting the ids as ints - this will be faster than dealing with the
   794  	// container ids below.
   795  	mint1, err1 := strconv.Atoi(id1)
   796  	mint2, err2 := strconv.Atoi(id2)
   797  	if err1 == nil && err2 == nil {
   798  		return mint1 < mint2
   799  	}
   800  	// We have at least one container id so it gets complicated.
   801  	idParts1 := strings.Split(id1, "/")
   802  	idParts2 := strings.Split(id2, "/")
   803  	nrParts1 := len(idParts1)
   804  	nrParts2 := len(idParts2)
   805  	minLen := nrParts1
   806  	if nrParts2 < minLen {
   807  		minLen = nrParts2
   808  	}
   809  	for x := 0; x < minLen; x++ {
   810  		m1 := idParts1[x]
   811  		m2 := idParts2[x]
   812  		if m1 == m2 {
   813  			continue
   814  		}
   815  		// See if the id part is a container type, and if so compare directly.
   816  		if x%2 == 1 {
   817  			return m1 < m2
   818  		}
   819  		// Compare the integer ids.
   820  		// There's nothing we can do with errors at this point.
   821  		mint1, _ := strconv.Atoi(m1)
   822  		mint2, _ := strconv.Atoi(m2)
   823  		return mint1 < mint2
   824  	}
   825  	return nrParts1 < nrParts2
   826  }
   827  
   828  // Machine returns the machine with the given id.
   829  func (st *State) Machine(id string) (*Machine, error) {
   830  	mdoc, err := st.getMachineDoc(id)
   831  	if err != nil {
   832  		return nil, err
   833  	}
   834  	return newMachine(st, mdoc), nil
   835  }
   836  
   837  func (st *State) getMachineDoc(id string) (*machineDoc, error) {
   838  	machinesCollection, closer := st.db().GetCollection(machinesC)
   839  	defer closer()
   840  
   841  	var err error
   842  	mdoc := &machineDoc{}
   843  	err = machinesCollection.FindId(id).One(mdoc)
   844  
   845  	switch err {
   846  	case nil:
   847  		return mdoc, nil
   848  	case mgo.ErrNotFound:
   849  		return nil, errors.NotFoundf("machine %s", id)
   850  	default:
   851  		return nil, errors.Annotatef(err, "cannot get machine %s", id)
   852  	}
   853  }
   854  
   855  // FindEntity returns the entity with the given tag.
   856  //
   857  // The returned value can be of type *Machine, *Unit,
   858  // *User, *Application, *Model, or *Action, depending
   859  // on the tag.
   860  func (st *State) FindEntity(tag names.Tag) (Entity, error) {
   861  	id := tag.Id()
   862  	switch tag := tag.(type) {
   863  	case names.ControllerAgentTag:
   864  		return st.ControllerNode(id)
   865  	case names.MachineTag:
   866  		return st.Machine(id)
   867  	case names.UnitTag:
   868  		return st.Unit(id)
   869  	case names.UserTag:
   870  		return st.User(tag)
   871  	case names.ApplicationTag:
   872  		return st.Application(id)
   873  	case names.ModelTag:
   874  		model, err := st.Model()
   875  		if err != nil {
   876  			return nil, errors.Trace(err)
   877  		}
   878  		// Return an invalid entity error if the requested model is not
   879  		// the current one.
   880  		if id != model.UUID() {
   881  			if utils.IsValidUUIDString(id) {
   882  				return nil, errors.NotFoundf("model %q", id)
   883  			}
   884  			// TODO(axw) 2013-12-04 #1257587
   885  			// We should not accept model tags that do not match the
   886  			// model's UUID. We accept anything for now, to cater
   887  			// both for past usage, and for potentially supporting aliases.
   888  			logger.Warningf("model-tag does not match current model UUID: %q != %q", id, model.UUID())
   889  			conf, err := model.ModelConfig()
   890  			if err != nil {
   891  				logger.Warningf("ModelConfig failed: %v", err)
   892  			} else if id != conf.Name() {
   893  				logger.Warningf("model-tag does not match current model name: %q != %q", id, conf.Name())
   894  			}
   895  		}
   896  		return model, nil
   897  	case names.RelationTag:
   898  		return st.KeyRelation(id)
   899  	case names.ActionTag:
   900  		model, err := st.Model()
   901  		if err != nil {
   902  			return nil, errors.Trace(err)
   903  		}
   904  		return model.ActionByTag(tag)
   905  	case names.OperationTag:
   906  		model, err := st.Model()
   907  		if err != nil {
   908  			return nil, errors.Trace(err)
   909  		}
   910  		return model.Operation(tag.Id())
   911  	case names.CharmTag:
   912  		return st.Charm(id)
   913  	case names.VolumeTag:
   914  		sb, err := NewStorageBackend(st)
   915  		if err != nil {
   916  			return nil, errors.Trace(err)
   917  		}
   918  		return sb.Volume(tag)
   919  	case names.FilesystemTag:
   920  		sb, err := NewStorageBackend(st)
   921  		if err != nil {
   922  			return nil, errors.Trace(err)
   923  		}
   924  		return sb.Filesystem(tag)
   925  	default:
   926  		return nil, errors.Errorf("unsupported tag %T", tag)
   927  	}
   928  }
   929  
   930  // tagToCollectionAndId, given an entity tag, returns the collection name and id
   931  // of the entity document.
   932  func (st *State) tagToCollectionAndId(tag names.Tag) (string, interface{}, error) {
   933  	if tag == nil {
   934  		return "", nil, errors.Errorf("tag is nil")
   935  	}
   936  	coll := ""
   937  	id := tag.Id()
   938  	switch tag := tag.(type) {
   939  	case names.MachineTag:
   940  		coll = machinesC
   941  		id = st.docID(id)
   942  	case names.ApplicationTag:
   943  		coll = applicationsC
   944  		id = st.docID(id)
   945  	case names.UnitTag:
   946  		coll = unitsC
   947  		id = st.docID(id)
   948  	case names.UserTag:
   949  		coll = usersC
   950  		if !tag.IsLocal() {
   951  			return "", nil, fmt.Errorf("%q is not a local user", tag.Id())
   952  		}
   953  		id = tag.Name()
   954  	case names.RelationTag:
   955  		coll = relationsC
   956  		id = st.docID(id)
   957  	case names.ModelTag:
   958  		coll = modelsC
   959  	case names.ActionTag:
   960  		coll = actionsC
   961  		id = tag.Id()
   962  	case names.CharmTag:
   963  		coll = charmsC
   964  		id = tag.Id()
   965  	default:
   966  		return "", nil, errors.Errorf("%q is not a valid collection tag", tag)
   967  	}
   968  	return coll, id, nil
   969  }
   970  
   971  // removeStalePeerRelationsOps returns the operations necessary to remove any
   972  // stale peer relation docs that may have been left behind after switching to
   973  // a different charm.
   974  func (st *State) removeStalePeerRelationsOps(applicationName string, relations []*Relation, newCharmMeta *charm.Meta) ([]txn.Op, error) {
   975  	if len(relations) == 0 {
   976  		return nil, nil // nothing to do
   977  	}
   978  
   979  	// Construct set of keys for existing peer relations.
   980  	oldPeerRelKeySet := set.NewStrings()
   981  nextRel:
   982  	for _, rel := range relations {
   983  		for _, ep := range rel.Endpoints() {
   984  			if ep.Role == charm.RolePeer {
   985  				oldPeerRelKeySet.Add(ep.String())
   986  				continue nextRel
   987  			}
   988  		}
   989  	}
   990  
   991  	// Construct set of keys for any peer relations defined by the new charm.
   992  	newPeerRelKeySet := set.NewStrings()
   993  	for _, rel := range newCharmMeta.Peers {
   994  		newPeerRelKeySet.Add(
   995  			relationKey(
   996  				[]Endpoint{{
   997  					ApplicationName: applicationName,
   998  					Relation:        rel,
   999  				}},
  1000  			),
  1001  		)
  1002  	}
  1003  
  1004  	// Remove any stale peer relation docs
  1005  	var ops []txn.Op
  1006  	for peerRelKey := range oldPeerRelKeySet.Difference(newPeerRelKeySet) {
  1007  		ops = append(ops,
  1008  			txn.Op{
  1009  				C:      relationsC,
  1010  				Id:     st.docID(peerRelKey),
  1011  				Assert: txn.DocExists,
  1012  				Remove: true,
  1013  			},
  1014  		)
  1015  	}
  1016  
  1017  	// If any peer relation docs are to be removed, we need to adjust the
  1018  	// relationcount field for the application document accordingly.
  1019  	if removals := len(ops); removals > 0 {
  1020  		ops = append(ops,
  1021  			txn.Op{
  1022  				C:      applicationsC,
  1023  				Id:     st.docID(applicationName),
  1024  				Assert: txn.DocExists,
  1025  				Update: bson.M{
  1026  					"$inc": bson.M{
  1027  						"relationcount": -removals,
  1028  					},
  1029  				},
  1030  			},
  1031  		)
  1032  	}
  1033  
  1034  	return ops, nil
  1035  }
  1036  
  1037  // addPeerRelationsOps returns the operations necessary to add the
  1038  // specified application peer relations to the state.
  1039  func (st *State) addPeerRelationsOps(applicationName string, peers map[string]charm.Relation) ([]txn.Op, error) {
  1040  	now := st.clock().Now()
  1041  	var ops []txn.Op
  1042  	for _, rel := range peers {
  1043  		relId, err := sequence(st, "relation")
  1044  		if err != nil {
  1045  			return nil, errors.Trace(err)
  1046  		}
  1047  		eps := []Endpoint{{
  1048  			ApplicationName: applicationName,
  1049  			Relation:        rel,
  1050  		}}
  1051  		relKey := relationKey(eps)
  1052  		relDoc := &relationDoc{
  1053  			DocID:     st.docID(relKey),
  1054  			Key:       relKey,
  1055  			ModelUUID: st.ModelUUID(),
  1056  			Id:        relId,
  1057  			Endpoints: eps,
  1058  			Life:      Alive,
  1059  		}
  1060  		relationStatusDoc := statusDoc{
  1061  			Status:    status.Joining,
  1062  			ModelUUID: st.ModelUUID(),
  1063  			Updated:   now.UnixNano(),
  1064  		}
  1065  		ops = append(ops,
  1066  			txn.Op{
  1067  				C:      relationsC,
  1068  				Id:     relDoc.DocID,
  1069  				Assert: txn.DocMissing,
  1070  				Insert: relDoc,
  1071  			},
  1072  			createStatusOp(st, relationGlobalScope(relId), relationStatusDoc),
  1073  			createSettingsOp(
  1074  				settingsC,
  1075  				relationApplicationSettingsKey(relId, eps[0].ApplicationName),
  1076  				map[string]interface{}{},
  1077  			),
  1078  		)
  1079  	}
  1080  	return ops, nil
  1081  }
  1082  
  1083  var (
  1084  	errSameNameRemoteApplicationExists = errors.Errorf("saas application with same name already exists")
  1085  	errLocalApplicationExists          = errors.Errorf("application already exists")
  1086  )
  1087  
  1088  // SaveCloudServiceArgs defines the arguments for SaveCloudService method.
  1089  type SaveCloudServiceArgs struct {
  1090  	// Id will be the application Name if it's a part of application,
  1091  	// and will be controller UUID for k8s a controller(controller does not have an application),
  1092  	// then is wrapped with applicationGlobalKey.
  1093  	Id         string
  1094  	ProviderId string
  1095  	Addresses  corenetwork.SpaceAddresses
  1096  
  1097  	Generation            int64
  1098  	DesiredScaleProtected bool
  1099  }
  1100  
  1101  // SaveCloudService creates a cloud service.
  1102  func (st *State) SaveCloudService(args SaveCloudServiceArgs) (_ *CloudService, err error) {
  1103  	defer errors.DeferredAnnotatef(&err, "cannot add cloud service %q", args.ProviderId)
  1104  
  1105  	doc := cloudServiceDoc{
  1106  		DocID:                 applicationGlobalKey(args.Id),
  1107  		ProviderId:            args.ProviderId,
  1108  		Addresses:             fromNetworkAddresses(args.Addresses, corenetwork.OriginProvider),
  1109  		Generation:            args.Generation,
  1110  		DesiredScaleProtected: args.DesiredScaleProtected,
  1111  	}
  1112  	buildTxn := func(int) ([]txn.Op, error) {
  1113  		return buildCloudServiceOps(st, doc)
  1114  	}
  1115  
  1116  	if err := st.db().Run(buildTxn); err != nil {
  1117  		return nil, errors.Annotate(err, "failed to save cloud service")
  1118  	}
  1119  	// refresh then return updated CloudService.
  1120  	return newCloudService(st, &doc).CloudService()
  1121  }
  1122  
  1123  // CloudService returns a cloud service state by Id.
  1124  func (st *State) CloudService(id string) (*CloudService, error) {
  1125  	svc := newCloudService(st, &cloudServiceDoc{DocID: st.docID(applicationGlobalKey(id))})
  1126  	return svc.CloudService()
  1127  }
  1128  
  1129  type AddApplicationArgs struct {
  1130  	Name              string
  1131  	Charm             *Charm
  1132  	CharmOrigin       *CharmOrigin
  1133  	Storage           map[string]StorageConstraints
  1134  	Devices           map[string]DeviceConstraints
  1135  	AttachStorage     []names.StorageTag
  1136  	EndpointBindings  map[string]string
  1137  	ApplicationConfig *config.Config
  1138  	CharmConfig       charm.Settings
  1139  	NumUnits          int
  1140  	Placement         []*instance.Placement
  1141  	Constraints       constraints.Value
  1142  	Resources         map[string]string
  1143  }
  1144  
  1145  // AddApplication creates a new application, running the supplied charm, with the
  1146  // supplied name (which must be unique). If the charm defines peer relations,
  1147  // they will be created automatically.
  1148  func (st *State) AddApplication(args AddApplicationArgs) (_ *Application, err error) {
  1149  	defer errors.DeferredAnnotatef(&err, "cannot add application %q", args.Name)
  1150  
  1151  	// Sanity checks.
  1152  	if !names.IsValidApplication(args.Name) {
  1153  		return nil, errors.Errorf("invalid name")
  1154  	}
  1155  	if args.Charm == nil {
  1156  		return nil, errors.Errorf("charm is nil")
  1157  	}
  1158  	if args.CharmOrigin == nil {
  1159  		return nil, errors.Errorf("charm origin is nil")
  1160  	}
  1161  	if args.CharmOrigin.Platform == nil {
  1162  		return nil, errors.Errorf("charm origin platform is nil")
  1163  	}
  1164  
  1165  	// If either the charm origin ID or Hash is set before a charm is
  1166  	// downloaded, charm download will fail for charms with a forced series.
  1167  	// The logic (refreshConfig) in sending the correct request to charmhub
  1168  	// will break.
  1169  	if (args.CharmOrigin.ID != "" && args.CharmOrigin.Hash == "") ||
  1170  		(args.CharmOrigin.ID == "" && args.CharmOrigin.Hash != "") {
  1171  		return nil, errors.BadRequestf("programming error, AddApplication, neither CharmOrigin ID nor Hash can be set before a charm is downloaded. See CharmHubRepository GetDownloadURL.")
  1172  	}
  1173  
  1174  	model, err := st.Model()
  1175  	if err != nil {
  1176  		return nil, errors.Trace(err)
  1177  	}
  1178  
  1179  	// CAAS charms don't support volume/block storage yet.
  1180  	if model.Type() == ModelTypeCAAS {
  1181  		for name, charmStorage := range args.Charm.Meta().Storage {
  1182  			if storageKind(charmStorage.Type) != storage.StorageKindBlock {
  1183  				continue
  1184  			}
  1185  			var count uint64
  1186  			if arg, ok := args.Storage[name]; ok {
  1187  				count = arg.Count
  1188  			}
  1189  			if charmStorage.CountMin > 0 || count > 0 {
  1190  				return nil, errors.NotSupportedf("block storage on a container model")
  1191  			}
  1192  		}
  1193  	}
  1194  
  1195  	if len(args.AttachStorage) > 0 && args.NumUnits != 1 {
  1196  		return nil, errors.Errorf("AttachStorage is non-empty but NumUnits is %d, must be 1", args.NumUnits)
  1197  	}
  1198  
  1199  	if err := jujuversion.CheckJujuMinVersion(args.Charm.Meta().MinJujuVersion, jujuversion.Current); err != nil {
  1200  		return nil, errors.Trace(err)
  1201  	}
  1202  
  1203  	if exists, err := isNotDead(st, applicationsC, args.Name); err != nil {
  1204  		return nil, errors.Trace(err)
  1205  	} else if exists {
  1206  		return nil, errors.AlreadyExistsf("application")
  1207  	}
  1208  	if err := checkModelActive(st); err != nil {
  1209  		return nil, errors.Trace(err)
  1210  	}
  1211  
  1212  	// ensure storage
  1213  	if args.Storage == nil {
  1214  		args.Storage = make(map[string]StorageConstraints)
  1215  	}
  1216  	sb, err := NewStorageBackend(st)
  1217  	if err != nil {
  1218  		return nil, errors.Trace(err)
  1219  	}
  1220  	if err := addDefaultStorageConstraints(sb, args.Storage, args.Charm.Meta()); err != nil {
  1221  		return nil, errors.Trace(err)
  1222  	}
  1223  	if err := validateStorageConstraints(sb, args.Storage, args.Charm.Meta()); err != nil {
  1224  		return nil, errors.Trace(err)
  1225  	}
  1226  	storagePools := make(set.Strings)
  1227  	for _, storageParams := range args.Storage {
  1228  		storagePools.Add(storageParams.Pool)
  1229  	}
  1230  
  1231  	// ensure Devices
  1232  	if args.Devices == nil {
  1233  		args.Devices = make(map[string]DeviceConstraints)
  1234  	}
  1235  	deviceb, err := NewDeviceBackend(st)
  1236  	if err != nil {
  1237  		return nil, errors.Trace(err)
  1238  	}
  1239  
  1240  	if err := validateDeviceConstraints(deviceb, args.Devices, args.Charm.Meta()); err != nil {
  1241  		return nil, errors.Trace(err)
  1242  	}
  1243  
  1244  	// Always ensure that we snapshot the application architecture when adding
  1245  	// the application. If no architecture in the constraints, then look at
  1246  	// the model constraints. If no architecture is found in the model, use the
  1247  	// default architecture (amd64).
  1248  	var (
  1249  		cons        = args.Constraints
  1250  		subordinate = args.Charm.Meta().Subordinate
  1251  	)
  1252  	if !subordinate && !cons.HasArch() {
  1253  		modelConstraints, err := st.ModelConstraints()
  1254  		if err != nil {
  1255  			return nil, errors.Trace(err)
  1256  		}
  1257  		a := constraints.ArchOrDefault(cons, &modelConstraints)
  1258  		cons.Arch = &a
  1259  		args.Constraints = cons
  1260  	}
  1261  
  1262  	// Perform model specific arg processing.
  1263  	var (
  1264  		scale             int
  1265  		placement         string
  1266  		hasResources      bool
  1267  		operatorStatusDoc *statusDoc
  1268  	)
  1269  	nowNano := st.clock().Now().UnixNano()
  1270  	switch model.Type() {
  1271  	case ModelTypeIAAS:
  1272  		if err := st.processIAASModelApplicationArgs(&args); err != nil {
  1273  			return nil, errors.Trace(err)
  1274  		}
  1275  	case ModelTypeCAAS:
  1276  		hasResources = true // all k8s apps start with the assumption of resources
  1277  		if err := st.processCAASModelApplicationArgs(&args); err != nil {
  1278  			return nil, errors.Trace(err)
  1279  		}
  1280  		scale = args.NumUnits
  1281  		if len(args.Placement) == 1 {
  1282  			placement = args.Placement[0].Directive
  1283  		}
  1284  		operatorStatusDoc = &statusDoc{
  1285  			ModelUUID:  st.ModelUUID(),
  1286  			Status:     status.Waiting,
  1287  			StatusInfo: status.MessageWaitForContainer,
  1288  			Updated:    nowNano,
  1289  		}
  1290  	}
  1291  
  1292  	applicationID := st.docID(args.Name)
  1293  
  1294  	// Create the application addition operations.
  1295  	peers := args.Charm.Meta().Peers
  1296  
  1297  	// The doc defaults to CharmModifiedVersion = 0, which is correct, since it
  1298  	// has, by definition, at its initial state.
  1299  	cURL := args.Charm.URL()
  1300  	appDoc := &applicationDoc{
  1301  		DocID:         applicationID,
  1302  		Name:          args.Name,
  1303  		ModelUUID:     st.ModelUUID(),
  1304  		Subordinate:   subordinate,
  1305  		CharmURL:      &cURL,
  1306  		CharmOrigin:   *args.CharmOrigin,
  1307  		RelationCount: len(peers),
  1308  		Life:          Alive,
  1309  		UnitCount:     args.NumUnits,
  1310  
  1311  		// CAAS
  1312  		DesiredScale: scale,
  1313  		Placement:    placement,
  1314  		HasResources: hasResources,
  1315  	}
  1316  
  1317  	app := newApplication(st, appDoc)
  1318  
  1319  	// The app has no existing bindings yet.
  1320  	b, err := app.bindingsForOps(nil)
  1321  	if err != nil {
  1322  		return nil, errors.Trace(err)
  1323  	}
  1324  	endpointBindingsOp, err := b.createOp(
  1325  		args.EndpointBindings,
  1326  		args.Charm.Meta(),
  1327  	)
  1328  	if err != nil {
  1329  		return nil, errors.Trace(err)
  1330  	}
  1331  
  1332  	statusDoc := statusDoc{
  1333  		ModelUUID: st.ModelUUID(),
  1334  		Status:    status.Unset,
  1335  		Updated:   nowNano,
  1336  	}
  1337  
  1338  	if err := args.ApplicationConfig.Validate(); err != nil {
  1339  		return nil, errors.Trace(err)
  1340  	}
  1341  	appConfigAttrs := args.ApplicationConfig.Attributes()
  1342  
  1343  	// When creating the settings, we ignore nils.  In other circumstances, nil
  1344  	// means to delete the value (reset to default), so creating with nil should
  1345  	// mean to use the default, i.e. don't set the value.
  1346  	removeNils(args.CharmConfig)
  1347  	removeNils(appConfigAttrs)
  1348  
  1349  	buildTxn := func(attempt int) ([]txn.Op, error) {
  1350  		// If we've tried once already and failed, check that
  1351  		// model may have been destroyed.
  1352  		if attempt > 0 {
  1353  			if err := checkModelActive(st); err != nil {
  1354  				return nil, errors.Trace(err)
  1355  			}
  1356  			// Ensure a local application with the same name doesn't exist.
  1357  			if exists, err := isNotDead(st, applicationsC, args.Name); err != nil {
  1358  				return nil, errors.Trace(err)
  1359  			} else if exists {
  1360  				return nil, errLocalApplicationExists
  1361  			}
  1362  			// Ensure a remote application with the same name doesn't exist.
  1363  			if remoteExists, err := isNotDead(st, remoteApplicationsC, args.Name); err != nil {
  1364  				return nil, errors.Trace(err)
  1365  			} else if remoteExists {
  1366  				return nil, errSameNameRemoteApplicationExists
  1367  			}
  1368  		}
  1369  		// The addApplicationOps does not include the model alive assertion,
  1370  		// so we add it here.
  1371  		ops := []txn.Op{
  1372  			assertModelActiveOp(st.ModelUUID()),
  1373  			endpointBindingsOp,
  1374  		}
  1375  		addOps, err := addApplicationOps(st, app, addApplicationOpsArgs{
  1376  			applicationDoc:    appDoc,
  1377  			statusDoc:         statusDoc,
  1378  			operatorStatus:    operatorStatusDoc,
  1379  			constraints:       args.Constraints,
  1380  			storage:           args.Storage,
  1381  			devices:           args.Devices,
  1382  			applicationConfig: appConfigAttrs,
  1383  			charmConfig:       args.CharmConfig,
  1384  		})
  1385  		if err != nil {
  1386  			return nil, errors.Trace(err)
  1387  		}
  1388  		ops = append(ops, addOps...)
  1389  
  1390  		// Collect peer relation addition operations.
  1391  		//
  1392  		// TODO(dimitern): Ensure each st.Endpoint has a space name associated in a
  1393  		// follow-up.
  1394  		addPeerOps, err := st.addPeerRelationsOps(args.Name, peers)
  1395  		if err != nil {
  1396  			return nil, errors.Trace(err)
  1397  		}
  1398  		ops = append(ops, addPeerOps...)
  1399  
  1400  		if len(args.Resources) > 0 {
  1401  			// Collect pending resource resolution operations.
  1402  			resources := st.resources()
  1403  			resOps, err := resources.resolveApplicationPendingResourcesOps(args.Name, args.Resources)
  1404  			if err != nil {
  1405  				return nil, errors.Trace(err)
  1406  			}
  1407  			ops = append(ops, resOps...)
  1408  		}
  1409  
  1410  		isSidecar, err := app.IsSidecar()
  1411  		if err != nil {
  1412  			return nil, errors.Trace(err)
  1413  		}
  1414  		if isSidecar {
  1415  			if err := resetSequence(st, app.Tag().String()); err != nil {
  1416  				return nil, errors.Trace(err)
  1417  			}
  1418  		}
  1419  
  1420  		// Collect unit-adding operations.
  1421  		for x := 0; x < args.NumUnits; x++ {
  1422  			unitName, unitOps, err := app.addUnitOpsWithCons(applicationAddUnitOpsArgs{
  1423  				cons:          args.Constraints,
  1424  				storageCons:   args.Storage,
  1425  				attachStorage: args.AttachStorage,
  1426  			})
  1427  			if err != nil {
  1428  				return nil, errors.Trace(err)
  1429  			}
  1430  			ops = append(ops, unitOps...)
  1431  			if model.Type() != ModelTypeCAAS {
  1432  				placement := instance.Placement{}
  1433  				if x < len(args.Placement) {
  1434  					placement = *args.Placement[x]
  1435  				}
  1436  				ops = append(ops, assignUnitOps(unitName, placement)...)
  1437  			}
  1438  		}
  1439  		return ops, nil
  1440  	}
  1441  	// At the last moment before inserting the application, prime status history.
  1442  	_, _ = probablyUpdateStatusHistory(st.db(), app.globalKey(), statusDoc)
  1443  
  1444  	if err = st.db().Run(buildTxn); err == nil {
  1445  		// Refresh to pick the txn-revno.
  1446  		if err = app.Refresh(); err != nil {
  1447  			return nil, errors.Trace(err)
  1448  		}
  1449  		return app, nil
  1450  	}
  1451  	return nil, errors.Trace(err)
  1452  }
  1453  
  1454  func (st *State) processCommonModelApplicationArgs(args *AddApplicationArgs) (Base, error) {
  1455  	// User has specified base. Overriding supported bases is
  1456  	// handled by the client, so args.Release is not necessarily
  1457  	// one of the charm's supported bases. We require that the
  1458  	// specified base is of the same operating system as one of
  1459  	// the supported bases.
  1460  	appBase, err := corebase.ParseBase(args.CharmOrigin.Platform.OS, args.CharmOrigin.Platform.Channel)
  1461  	if err != nil {
  1462  		return Base{}, errors.Trace(err)
  1463  	}
  1464  
  1465  	err = corecharm.OSIsCompatibleWithCharm(appBase.OS, args.Charm)
  1466  	if err != nil {
  1467  		return Base{}, errors.Trace(err)
  1468  	}
  1469  
  1470  	// Ignore constraints that result from this call as
  1471  	// these would be accumulation of model and application constraints
  1472  	// but we only want application constraints to be persisted here.
  1473  	cons, err := st.ResolveConstraints(args.Constraints)
  1474  	if err != nil {
  1475  		return Base{}, errors.Trace(err)
  1476  	}
  1477  	unsupported, err := st.validateConstraints(cons)
  1478  	if len(unsupported) > 0 {
  1479  		logger.Warningf(
  1480  			"deploying %q: unsupported constraints: %v", args.Name, strings.Join(unsupported, ","))
  1481  	}
  1482  	return Base{appBase.OS, appBase.Channel.String()}, errors.Trace(err)
  1483  }
  1484  
  1485  func (st *State) processIAASModelApplicationArgs(args *AddApplicationArgs) error {
  1486  	appBase, err := st.processCommonModelApplicationArgs(args)
  1487  	if err != nil {
  1488  		return errors.Trace(err)
  1489  	}
  1490  
  1491  	storagePools := make(set.Strings)
  1492  	for _, storageParams := range args.Storage {
  1493  		storagePools.Add(storageParams.Pool)
  1494  	}
  1495  
  1496  	// Obtain volume attachment params corresponding to storage being
  1497  	// attached. We need to pass them along to precheckInstance, in
  1498  	// case the volumes cannot be attached to a machine with the given
  1499  	// placement directive.
  1500  	sb, err := NewStorageBackend(st)
  1501  	if err != nil {
  1502  		return errors.Trace(err)
  1503  	}
  1504  	volumeAttachments := make([]storage.VolumeAttachmentParams, 0, len(args.AttachStorage))
  1505  	for _, storageTag := range args.AttachStorage {
  1506  		v, err := sb.StorageInstanceVolume(storageTag)
  1507  		if errors.IsNotFound(err) {
  1508  			continue
  1509  		} else if err != nil {
  1510  			return errors.Trace(err)
  1511  		}
  1512  		volumeInfo, err := v.Info()
  1513  		if err != nil {
  1514  			// Volume has not been provisioned yet,
  1515  			// so it cannot be attached.
  1516  			continue
  1517  		}
  1518  		providerType, _, _, err := poolStorageProvider(sb, volumeInfo.Pool)
  1519  		if err != nil {
  1520  			return errors.Annotatef(err, "cannot attach %s", names.ReadableString(storageTag))
  1521  		}
  1522  		storageName, _ := names.StorageName(storageTag.Id())
  1523  		volumeAttachments = append(volumeAttachments, storage.VolumeAttachmentParams{
  1524  			AttachmentParams: storage.AttachmentParams{
  1525  				Provider: providerType,
  1526  				ReadOnly: args.Charm.Meta().Storage[storageName].ReadOnly,
  1527  			},
  1528  			Volume:   v.VolumeTag(),
  1529  			VolumeId: volumeInfo.VolumeId,
  1530  		})
  1531  	}
  1532  
  1533  	// Collect distinct placements that need to be checked.
  1534  	for _, placement := range args.Placement {
  1535  		data, err := st.parsePlacement(placement)
  1536  		if err != nil {
  1537  			return errors.Trace(err)
  1538  		}
  1539  		switch data.placementType() {
  1540  		case machinePlacement:
  1541  			// Ensure that the machine and charm series match.
  1542  			m, err := st.Machine(data.machineId)
  1543  			if err != nil {
  1544  				return errors.Trace(err)
  1545  			}
  1546  			subordinate := args.Charm.Meta().Subordinate
  1547  			if err := validateUnitMachineAssignment(
  1548  				m, appBase, subordinate, storagePools,
  1549  			); err != nil {
  1550  				return errors.Annotatef(
  1551  					err, "cannot deploy to machine %s", m,
  1552  				)
  1553  			}
  1554  			// This placement directive indicates that we're putting a
  1555  			// unit on a pre-existing machine. There's no need to
  1556  			// precheck the args since we're not starting an instance.
  1557  
  1558  		case directivePlacement:
  1559  			if err := st.precheckInstance(
  1560  				appBase,
  1561  				args.Constraints,
  1562  				data.directive,
  1563  				volumeAttachments,
  1564  			); err != nil {
  1565  				return errors.Trace(err)
  1566  			}
  1567  		}
  1568  	}
  1569  	// We want to check the constraints if there's no placement at all.
  1570  	if len(args.Placement) == 0 {
  1571  		if err := st.precheckInstance(
  1572  			appBase,
  1573  			args.Constraints,
  1574  			"",
  1575  			volumeAttachments,
  1576  		); err != nil {
  1577  			return errors.Trace(err)
  1578  		}
  1579  	}
  1580  
  1581  	return nil
  1582  }
  1583  
  1584  func (st *State) processCAASModelApplicationArgs(args *AddApplicationArgs) error {
  1585  	appSeries, err := st.processCommonModelApplicationArgs(args)
  1586  	if err != nil {
  1587  		return errors.Trace(err)
  1588  	}
  1589  	if len(args.Placement) > 0 {
  1590  		return errors.NotValidf("placement directives on k8s models")
  1591  	}
  1592  	return st.precheckInstance(
  1593  		appSeries,
  1594  		args.Constraints,
  1595  		"",
  1596  		nil,
  1597  	)
  1598  }
  1599  
  1600  // removeNils removes any keys with nil values from the given map.
  1601  func removeNils(m map[string]interface{}) {
  1602  	for k, v := range m {
  1603  		if v == nil {
  1604  			delete(m, k)
  1605  		}
  1606  	}
  1607  }
  1608  
  1609  // assignUnitOps returns the db ops to save unit assignment for use by the
  1610  // UnitAssigner worker.
  1611  func assignUnitOps(unitName string, placement instance.Placement) []txn.Op {
  1612  	udoc := assignUnitDoc{
  1613  		DocId:     unitName,
  1614  		Scope:     placement.Scope,
  1615  		Directive: placement.Directive,
  1616  	}
  1617  	return []txn.Op{{
  1618  		C:      assignUnitC,
  1619  		Id:     udoc.DocId,
  1620  		Assert: txn.DocMissing,
  1621  		Insert: udoc,
  1622  	}}
  1623  }
  1624  
  1625  // AssignStagedUnits gets called by the UnitAssigner worker, and runs the given
  1626  // assignments.
  1627  func (st *State) AssignStagedUnits(ids []string) ([]UnitAssignmentResult, error) {
  1628  	query := bson.D{{"_id", bson.D{{"$in", ids}}}}
  1629  	unitAssignments, err := st.unitAssignments(query)
  1630  	if err != nil {
  1631  		return nil, errors.Annotate(err, "getting staged unit assignments")
  1632  	}
  1633  	results := make([]UnitAssignmentResult, len(unitAssignments))
  1634  	for i, a := range unitAssignments {
  1635  		err := st.assignStagedUnit(a)
  1636  		results[i].Unit = a.Unit
  1637  		results[i].Error = err
  1638  	}
  1639  	return results, nil
  1640  }
  1641  
  1642  // AllUnitAssignments returns all staged unit assignments in the model.
  1643  func (st *State) AllUnitAssignments() ([]UnitAssignment, error) {
  1644  	return st.unitAssignments(nil)
  1645  }
  1646  
  1647  func (st *State) unitAssignments(query bson.D) ([]UnitAssignment, error) {
  1648  	col, closer := st.db().GetCollection(assignUnitC)
  1649  	defer closer()
  1650  
  1651  	var docs []assignUnitDoc
  1652  	if err := col.Find(query).All(&docs); err != nil {
  1653  		return nil, errors.Annotatef(err, "cannot get unit assignment docs")
  1654  	}
  1655  	results := make([]UnitAssignment, len(docs))
  1656  	for i, doc := range docs {
  1657  		results[i] = UnitAssignment{
  1658  			st.localID(doc.DocId),
  1659  			doc.Scope,
  1660  			doc.Directive,
  1661  		}
  1662  	}
  1663  	return results, nil
  1664  }
  1665  
  1666  func removeStagedAssignmentOp(id string) txn.Op {
  1667  	return txn.Op{
  1668  		C:      assignUnitC,
  1669  		Id:     id,
  1670  		Remove: true,
  1671  	}
  1672  }
  1673  
  1674  func (st *State) assignStagedUnit(a UnitAssignment) error {
  1675  	u, err := st.Unit(a.Unit)
  1676  	if err != nil {
  1677  		return errors.Trace(err)
  1678  	}
  1679  	if a.Scope == "" && a.Directive == "" {
  1680  		return errors.Trace(st.AssignUnit(u, AssignCleanEmpty))
  1681  	}
  1682  
  1683  	placement := &instance.Placement{Scope: a.Scope, Directive: a.Directive}
  1684  
  1685  	return errors.Trace(st.AssignUnitWithPlacement(u, placement))
  1686  }
  1687  
  1688  // AssignUnitWithPlacement chooses a machine using the given placement directive
  1689  // and then assigns the unit to it.
  1690  func (st *State) AssignUnitWithPlacement(unit *Unit, placement *instance.Placement) error {
  1691  	// TODO(natefinch) this should be done as a single transaction, not two.
  1692  	// Mark https://launchpad.net/bugs/1506994 fixed when done.
  1693  
  1694  	data, err := st.parsePlacement(placement)
  1695  	if err != nil {
  1696  		return errors.Trace(err)
  1697  	}
  1698  	if data.placementType() == directivePlacement {
  1699  		return unit.assignToNewMachine(data.directive)
  1700  	}
  1701  
  1702  	m, err := st.addMachineWithPlacement(unit, data)
  1703  	if err != nil {
  1704  		return errors.Trace(err)
  1705  	}
  1706  	return unit.AssignToMachine(m)
  1707  }
  1708  
  1709  // placementData is a helper type that encodes some of the logic behind how an
  1710  // instance.Placement gets translated into a placement directive the providers
  1711  // understand.
  1712  type placementData struct {
  1713  	machineId     string
  1714  	directive     string
  1715  	containerType instance.ContainerType
  1716  }
  1717  
  1718  type placementType int
  1719  
  1720  const (
  1721  	containerPlacement placementType = iota
  1722  	directivePlacement
  1723  	machinePlacement
  1724  )
  1725  
  1726  // placementType returns the type of placement that this data represents.
  1727  func (p placementData) placementType() placementType {
  1728  	if p.containerType != "" {
  1729  		return containerPlacement
  1730  	}
  1731  	if p.directive != "" {
  1732  		return directivePlacement
  1733  	}
  1734  	return machinePlacement
  1735  }
  1736  
  1737  func (st *State) parsePlacement(placement *instance.Placement) (*placementData, error) {
  1738  	// Extract container type and parent from container placement directives.
  1739  	if container, err := instance.ParseContainerType(placement.Scope); err == nil {
  1740  		return &placementData{
  1741  			containerType: container,
  1742  			machineId:     placement.Directive,
  1743  		}, nil
  1744  	}
  1745  	switch placement.Scope {
  1746  	case st.ModelUUID():
  1747  		return &placementData{directive: placement.Directive}, nil
  1748  	case instance.MachineScope:
  1749  		return &placementData{machineId: placement.Directive}, nil
  1750  	default:
  1751  		return nil, errors.Errorf("placement scope: invalid model UUID %q", placement.Scope)
  1752  	}
  1753  }
  1754  
  1755  // addMachineWithPlacement finds a machine that matches the given
  1756  // placement directive for the given unit.
  1757  func (st *State) addMachineWithPlacement(unit *Unit, data *placementData) (*Machine, error) {
  1758  	unitCons, err := unit.Constraints()
  1759  	if err != nil {
  1760  		return nil, errors.Trace(err)
  1761  	}
  1762  
  1763  	// Turn any endpoint bindings for the unit's application into machine
  1764  	// constraints. This prevents a possible race condition where the
  1765  	// provisioner can act on a newly created container before the unit is
  1766  	// assigned to it, missing the required spaces for bridging based on
  1767  	// endpoint bindings.
  1768  	// TODO (manadart 2019-10-08): This step is not necessary when a single
  1769  	// transaction is used based on the comment below.
  1770  	app, err := unit.Application()
  1771  	if err != nil {
  1772  		return nil, errors.Trace(err)
  1773  	}
  1774  	bindings, err := app.EndpointBindings()
  1775  	if err != nil {
  1776  		return nil, errors.Trace(err)
  1777  	}
  1778  
  1779  	lookup, err := st.AllSpaceInfos()
  1780  	if err != nil {
  1781  		return nil, errors.Trace(err)
  1782  	}
  1783  
  1784  	// Space constraints must be space name format as they are
  1785  	// used by the providers directly.
  1786  	bindingsNameMap, err := bindings.MapWithSpaceNames(lookup)
  1787  	if err != nil {
  1788  		return nil, errors.Trace(err)
  1789  	}
  1790  	spaces := set.NewStrings()
  1791  	for _, name := range bindingsNameMap {
  1792  		// TODO (manadart 2019-10-08): "alpha" is not guaranteed to have
  1793  		// subnets, which the provisioner expects, so can not be used as
  1794  		// a constraint.  This also preserves behavior from when the
  1795  		// AlphaSpaceName was "". This condition will be removed with
  1796  		// the institution of universal mutable spaces.
  1797  		if name != corenetwork.AlphaSpaceName {
  1798  			spaces.Add(name)
  1799  		}
  1800  	}
  1801  
  1802  	// Merging constraints returns an error if any spaces are already set,
  1803  	// so we "move" any existing constraints over to the bind spaces before
  1804  	// parsing and merging.
  1805  	if unitCons.Spaces != nil {
  1806  		for _, sp := range *unitCons.Spaces {
  1807  			spaces.Add(sp)
  1808  		}
  1809  		unitCons.Spaces = nil
  1810  	}
  1811  	spaceCons := constraints.MustParse("spaces=" + strings.Join(spaces.Values(), ","))
  1812  
  1813  	cons, err := constraints.Merge(*unitCons, spaceCons)
  1814  	if err != nil {
  1815  		return nil, errors.Trace(err)
  1816  	}
  1817  
  1818  	// Create any new machine marked as dirty so that
  1819  	// nothing else will grab it before we assign the unit to it.
  1820  	// TODO(natefinch) fix this when we put assignment in the same
  1821  	// transaction as adding a machine.  See bug
  1822  	// https://launchpad.net/bugs/1506994
  1823  
  1824  	mId := data.machineId
  1825  	var machine *Machine
  1826  	if data.machineId != "" {
  1827  		machine, err = st.Machine(mId)
  1828  		if err != nil {
  1829  			return nil, errors.Trace(err)
  1830  		}
  1831  
  1832  		// Check if an upgrade-series lock is present for the requested
  1833  		// machine or its parent.
  1834  		// If one exists, return an error to prevent deployment.
  1835  		locked, err := machine.IsLockedForSeriesUpgrade()
  1836  		if err != nil {
  1837  			return nil, errors.Trace(err)
  1838  		}
  1839  		if locked {
  1840  			return nil, errors.Errorf("machine %q is locked for series upgrade", mId)
  1841  		}
  1842  		locked, err = machine.IsParentLockedForSeriesUpgrade()
  1843  		if err != nil {
  1844  			return nil, errors.Trace(err)
  1845  		}
  1846  		if locked {
  1847  			return nil, errors.Errorf("machine hosting %q is locked for series upgrade", mId)
  1848  		}
  1849  	}
  1850  
  1851  	switch data.placementType() {
  1852  	case containerPlacement:
  1853  		// If a container is to be used, create it.
  1854  		template := MachineTemplate{
  1855  			Base:        unit.doc.Base,
  1856  			Jobs:        []MachineJob{JobHostUnits},
  1857  			Dirty:       true,
  1858  			Constraints: cons,
  1859  		}
  1860  		if mId != "" {
  1861  			return st.AddMachineInsideMachine(template, mId, data.containerType)
  1862  		}
  1863  		return st.AddMachineInsideNewMachine(template, template, data.containerType)
  1864  	case directivePlacement:
  1865  		return nil, errors.NotSupportedf(
  1866  			"programming error: directly adding a machine for %s with a non-machine placement directive", unit.Name())
  1867  	default:
  1868  		return machine, nil
  1869  	}
  1870  }
  1871  
  1872  // Application returns an application state by name.
  1873  func (st *State) Application(name string) (_ *Application, err error) {
  1874  	applications, closer := st.db().GetCollection(applicationsC)
  1875  	defer closer()
  1876  
  1877  	if !names.IsValidApplication(name) {
  1878  		return nil, errors.Errorf("%q is not a valid application name", name)
  1879  	}
  1880  	sdoc := &applicationDoc{}
  1881  	err = applications.FindId(name).One(sdoc)
  1882  	if err == mgo.ErrNotFound {
  1883  		return nil, errors.NotFoundf("application %q", name)
  1884  	}
  1885  	if err != nil {
  1886  		return nil, errors.Annotatef(err, "cannot get application %q", name)
  1887  	}
  1888  	return newApplication(st, sdoc), nil
  1889  }
  1890  
  1891  // AllApplications returns all deployed applications in the model.
  1892  func (st *State) AllApplications() (applications []*Application, err error) {
  1893  	applicationsCollection, closer := st.db().GetCollection(applicationsC)
  1894  	defer closer()
  1895  
  1896  	sdocs := []applicationDoc{}
  1897  	err = applicationsCollection.Find(bson.D{}).All(&sdocs)
  1898  	if err != nil {
  1899  		return nil, errors.Errorf("cannot get all applications")
  1900  	}
  1901  	for _, v := range sdocs {
  1902  		applications = append(applications, newApplication(st, &v))
  1903  	}
  1904  	return applications, nil
  1905  }
  1906  
  1907  // InferActiveRelation returns the relation corresponding to the supplied
  1908  // application or endpoint name(s), assuming such a relation exists and is unique.
  1909  // There must be 1 or 2 supplied names, of the form <application>[:<relation>].
  1910  func (st *State) InferActiveRelation(names ...string) (*Relation, error) {
  1911  	candidates, err := matchingRelations(st, names...)
  1912  	if err != nil {
  1913  		return nil, err
  1914  	}
  1915  
  1916  	relationQuery := strings.Join(names, " ")
  1917  	if len(candidates) == 0 {
  1918  		return nil, errors.NotFoundf("relation matching %q", relationQuery)
  1919  	}
  1920  	if len(candidates) == 1 {
  1921  		return candidates[0], nil
  1922  	}
  1923  
  1924  	keys := make([]string, len(candidates))
  1925  	for i, relation := range candidates {
  1926  		keys[i] = fmt.Sprintf("%q", relation.String())
  1927  	}
  1928  	return nil, errors.Errorf("ambiguous relation: %q could refer to %s",
  1929  		relationQuery, strings.Join(keys, "; "),
  1930  	)
  1931  }
  1932  
  1933  // InferEndpoints returns the endpoints corresponding to the supplied names.
  1934  // There must be 1 or 2 supplied names, of the form <application>[:<relation>].
  1935  // If the supplied names uniquely specify a possible relation, or if they
  1936  // uniquely specify a possible relation once all implicit relations have been
  1937  // filtered, the endpoints corresponding to that relation will be returned.
  1938  func (st *State) InferEndpoints(names ...string) ([]Endpoint, error) {
  1939  	// Collect all possible sane endpoint lists.
  1940  	var candidates [][]Endpoint
  1941  	switch len(names) {
  1942  	// Implicitly assume this is a peer relation, as they have only one endpoint
  1943  	case 1:
  1944  		eps, err := st.endpoints(names[0], isPeer)
  1945  		if err != nil {
  1946  			return nil, errors.Trace(err)
  1947  		}
  1948  		for _, ep := range eps {
  1949  			candidates = append(candidates, []Endpoint{ep})
  1950  		}
  1951  	// All other relations are between two endpoints
  1952  	case 2:
  1953  		eps1, err := st.endpoints(names[0], notPeer)
  1954  		if err != nil {
  1955  			return nil, errors.Trace(err)
  1956  		}
  1957  		eps2, err := st.endpoints(names[1], notPeer)
  1958  		if err != nil {
  1959  			return nil, errors.Trace(err)
  1960  		}
  1961  		for _, ep1 := range eps1 {
  1962  			for _, ep2 := range eps2 {
  1963  				scopeOk, err := containerScopeOk(st, ep1, ep2)
  1964  				if err != nil {
  1965  					return nil, errors.Trace(err)
  1966  				}
  1967  				if ep1.CanRelateTo(ep2) && scopeOk {
  1968  					candidates = append(candidates, []Endpoint{ep1, ep2})
  1969  				}
  1970  			}
  1971  		}
  1972  	default:
  1973  		return nil, errors.Errorf("cannot relate %d endpoints", len(names))
  1974  	}
  1975  	switch len(candidates) {
  1976  	case 0:
  1977  		return nil, errors.Errorf("no relations found")
  1978  	case 1:
  1979  		return candidates[0], nil
  1980  	}
  1981  	// If there's ambiguity, try discarding implicit relations.
  1982  	var filtered [][]Endpoint
  1983  outer:
  1984  	for _, cand := range candidates {
  1985  		for _, ep := range cand {
  1986  			if ep.IsImplicit() {
  1987  				continue outer
  1988  			}
  1989  		}
  1990  		filtered = append(filtered, cand)
  1991  	}
  1992  	if len(filtered) == 1 {
  1993  		return filtered[0], nil
  1994  	}
  1995  	keys := []string{}
  1996  	for _, cand := range candidates {
  1997  		keys = append(keys, fmt.Sprintf("%q", relationKey(cand)))
  1998  	}
  1999  	sort.Strings(keys)
  2000  	return nil, errors.Errorf("ambiguous relation: %q could refer to %s",
  2001  		strings.Join(names, " "), strings.Join(keys, "; "))
  2002  }
  2003  
  2004  func isPeer(ep Endpoint) bool {
  2005  	return ep.Role == charm.RolePeer
  2006  }
  2007  
  2008  func notPeer(ep Endpoint) bool {
  2009  	return ep.Role != charm.RolePeer
  2010  }
  2011  
  2012  func containerScopeOk(st *State, ep1, ep2 Endpoint) (bool, error) {
  2013  	if ep1.Scope != charm.ScopeContainer && ep2.Scope != charm.ScopeContainer {
  2014  		return true, nil
  2015  	}
  2016  	var subordinateCount int
  2017  	for _, ep := range []Endpoint{ep1, ep2} {
  2018  		app, err := applicationByName(st, ep.ApplicationName)
  2019  		if err != nil {
  2020  			return false, err
  2021  		}
  2022  		// Container scoped relations are not allowed for remote applications.
  2023  		if app.IsRemote() {
  2024  			return false, nil
  2025  		}
  2026  		if app.(*Application).doc.Subordinate {
  2027  			subordinateCount++
  2028  		}
  2029  	}
  2030  	return subordinateCount >= 1, nil
  2031  }
  2032  
  2033  func splitEndpointName(name string) (string, string, error) {
  2034  	if i := strings.Index(name, ":"); i == -1 {
  2035  		return name, "", nil
  2036  	} else if i != 0 && i != len(name)-1 {
  2037  		return name[:i], name[i+1:], nil
  2038  	} else {
  2039  		return "", "", errors.Errorf("invalid endpoint %q", name)
  2040  	}
  2041  }
  2042  
  2043  func applicationByName(st *State, name string) (ApplicationEntity, error) {
  2044  	app, err := st.Application(name)
  2045  	if err == nil {
  2046  		return app, nil
  2047  	} else if err != nil && !errors.IsNotFound(err) {
  2048  		return nil, err
  2049  	}
  2050  	remoteApp, remoteErr := st.RemoteApplication(name)
  2051  	if errors.IsNotFound(remoteErr) {
  2052  		// We can't find either an application or a remote application
  2053  		// by that name. Report the missing application, since that's
  2054  		// probably what was intended (and still indicates the problem
  2055  		// for remote applications).
  2056  		return nil, err
  2057  	}
  2058  	return remoteApp, remoteErr
  2059  }
  2060  
  2061  // endpoints returns all endpoints that could be intended by the
  2062  // supplied endpoint name, and which cause the filter param to
  2063  // return true.
  2064  func (st *State) endpoints(name string, filter func(ep Endpoint) bool) ([]Endpoint, error) {
  2065  	appName, relName, err := splitEndpointName(name)
  2066  	if err != nil {
  2067  		return nil, err
  2068  	}
  2069  	app, err := applicationByName(st, appName)
  2070  	if err != nil {
  2071  		return nil, errors.Trace(err)
  2072  	}
  2073  	eps := []Endpoint{}
  2074  	if relName != "" {
  2075  		ep, err := app.Endpoint(relName)
  2076  		if err != nil {
  2077  			return nil, errors.Trace(err)
  2078  		}
  2079  		eps = append(eps, ep)
  2080  	} else {
  2081  		eps, err = app.Endpoints()
  2082  		if err != nil {
  2083  			return nil, errors.Trace(err)
  2084  		}
  2085  	}
  2086  	final := []Endpoint{}
  2087  	for _, ep := range eps {
  2088  		if filter(ep) {
  2089  			final = append(final, ep)
  2090  		}
  2091  	}
  2092  	return final, nil
  2093  }
  2094  
  2095  // AddRelation creates a new relation with the given endpoints.
  2096  func (st *State) AddRelation(eps ...Endpoint) (r *Relation, err error) {
  2097  	key := relationKey(eps)
  2098  	defer errors.DeferredAnnotatef(&err, "cannot add relation %q", key)
  2099  
  2100  	// Enforce basic endpoint sanity. The epCount restrictions may be relaxed
  2101  	// in the future; if so, this method is likely to need significant rework.
  2102  	if len(eps) != 2 {
  2103  		return nil, errors.Errorf("relation must have two endpoints")
  2104  	}
  2105  	if !eps[0].CanRelateTo(eps[1]) {
  2106  		return nil, errors.Errorf("endpoints do not relate")
  2107  	}
  2108  
  2109  	// Check applications are alive and do checks if one is remote.
  2110  	app1, err := aliveApplication(st, eps[0].ApplicationName)
  2111  	if err != nil {
  2112  		return nil, err
  2113  	}
  2114  	app2, err := aliveApplication(st, eps[1].ApplicationName)
  2115  	if err != nil {
  2116  		return nil, err
  2117  	}
  2118  	if app1.IsRemote() && app2.IsRemote() {
  2119  		return nil, errors.Errorf("cannot add relation between saas applications %q and %q", eps[0].ApplicationName, eps[1].ApplicationName)
  2120  	}
  2121  	remoteRelation := app1.IsRemote() || app2.IsRemote()
  2122  	ep0ok := app1.IsRemote() || eps[0].Scope == charm.ScopeGlobal
  2123  	ep1ok := app2.IsRemote() || eps[1].Scope == charm.ScopeGlobal
  2124  	if remoteRelation && (!ep0ok || !ep1ok) {
  2125  		return nil, errors.Errorf("local endpoint must be globally scoped for remote relations")
  2126  	}
  2127  
  2128  	// If either endpoint has container scope, so must the other; and the
  2129  	// application's base must also match, because they'll be deployed to
  2130  	// the same machines.
  2131  	compatibleBases := true
  2132  	if eps[0].Scope == charm.ScopeContainer {
  2133  		eps[1].Scope = charm.ScopeContainer
  2134  	} else if eps[1].Scope == charm.ScopeContainer {
  2135  		eps[0].Scope = charm.ScopeContainer
  2136  	} else {
  2137  		compatibleBases = false
  2138  	}
  2139  
  2140  	// We only get a unique relation id once, to save on roundtrips. If it's
  2141  	// -1, we haven't got it yet (we don't get it at this stage, because we
  2142  	// still don't know whether it's sane to even attempt creation).
  2143  	id := -1
  2144  
  2145  	// If a application's charm is upgraded while we're trying to add a relation,
  2146  	// we'll need to re-validate application sanity.
  2147  	var doc *relationDoc
  2148  	now := st.clock().Now()
  2149  	buildTxn := func(attempt int) ([]txn.Op, error) {
  2150  		// Perform initial relation sanity check.
  2151  		if exists, err := isNotDead(st, relationsC, key); err != nil {
  2152  			return nil, errors.Trace(err)
  2153  		} else if exists {
  2154  			// Ignore the error here, if there is an error, we know that dying
  2155  			// will be false and can fall through to error message below.
  2156  			if dying, _ := isDying(st, relationsC, key); dying {
  2157  				return nil, errors.NewAlreadyExists(nil, fmt.Sprintf("relation %v is dying, but not yet removed", key))
  2158  			}
  2159  			return nil, errors.NewAlreadyExists(nil, fmt.Sprintf("relation %v", key))
  2160  		}
  2161  
  2162  		// Collect per-application operations, checking sanity as we go.
  2163  		var ops []txn.Op
  2164  		var subordinateCount int
  2165  		appBases := map[string][]corebase.Base{}
  2166  		for _, ep := range eps {
  2167  			app, err := aliveApplication(st, ep.ApplicationName)
  2168  			if err != nil {
  2169  				return nil, err
  2170  			}
  2171  			if app.IsRemote() {
  2172  				// If the remote application is known to be terminated, we don't
  2173  				// allow a relation to it.
  2174  				statusInfo, err := app.Status()
  2175  				if err != nil && !errors.IsNotFound(err) {
  2176  					return nil, errors.Trace(err)
  2177  				}
  2178  				if err == nil && statusInfo.Status == status.Terminated {
  2179  					return nil, errors.Errorf("remote offer %s is terminated", ep.ApplicationName)
  2180  				}
  2181  				ops = append(ops, txn.Op{
  2182  					C:      remoteApplicationsC,
  2183  					Id:     st.docID(ep.ApplicationName),
  2184  					Assert: bson.D{{"life", Alive}},
  2185  					Update: bson.D{{"$inc", bson.D{{"relationcount", 1}}}},
  2186  				})
  2187  			} else {
  2188  				localApp := app.(*Application)
  2189  				if localApp.doc.Subordinate {
  2190  					subordinateCount++
  2191  				}
  2192  				ch, _, err := localApp.Charm()
  2193  				if err != nil {
  2194  					return nil, errors.Trace(err)
  2195  				}
  2196  				if !ep.ImplementedBy(ch) {
  2197  					return nil, errors.Errorf("%q does not implement %q", ep.ApplicationName, ep)
  2198  				}
  2199  				charmBases, err := corecharm.ComputedBases(ch)
  2200  				if err != nil {
  2201  					return nil, errors.Trace(err)
  2202  				}
  2203  				if len(charmBases) == 0 {
  2204  					return nil, errors.NotValidf("charm %q does not support any bases", ch.Meta().Name)
  2205  				}
  2206  				appBases[localApp.doc.Name] = charmBases
  2207  				ops = append(ops, txn.Op{
  2208  					C:      applicationsC,
  2209  					Id:     st.docID(ep.ApplicationName),
  2210  					Assert: bson.D{{"life", Alive}, {"charmurl", ch.URL()}},
  2211  					Update: bson.D{{"$inc", bson.D{{"relationcount", 1}}}},
  2212  				})
  2213  			}
  2214  
  2215  			// Enforce max-relation limits for the app:ep combination
  2216  			if err := enforceMaxRelationLimit(app, ep); err != nil {
  2217  				return nil, errors.Trace(err)
  2218  			}
  2219  		}
  2220  		// We need to ensure that there's intersection between the supported
  2221  		// bases of both applications' charms.
  2222  		if compatibleBases && len(appBases) > 1 && !compatibleSupportedBases(appBases[eps[0].ApplicationName], appBases[eps[1].ApplicationName]) {
  2223  			return nil, errors.Errorf("principal and subordinate applications' bases must match")
  2224  		}
  2225  		if eps[0].Scope == charm.ScopeContainer && subordinateCount < 1 {
  2226  			return nil, errors.Errorf("container scoped relation requires at least one subordinate application")
  2227  		}
  2228  
  2229  		// Create a new unique id if that has not already been done, and add
  2230  		// an operation to create the relation document.
  2231  		if id == -1 {
  2232  			var err error
  2233  			if id, err = sequence(st, "relation"); err != nil {
  2234  				return nil, errors.Trace(err)
  2235  			}
  2236  		}
  2237  		docID := st.docID(key)
  2238  		doc = &relationDoc{
  2239  			DocID:     docID,
  2240  			Key:       key,
  2241  			ModelUUID: st.ModelUUID(),
  2242  			Id:        id,
  2243  			Endpoints: eps,
  2244  			Life:      Alive,
  2245  		}
  2246  		relationStatusDoc := statusDoc{
  2247  			Status:    status.Joining,
  2248  			ModelUUID: st.ModelUUID(),
  2249  			Updated:   now.UnixNano(),
  2250  		}
  2251  		ops = append(ops, txn.Op{
  2252  			C:      relationsC,
  2253  			Id:     docID,
  2254  			Assert: txn.DocMissing,
  2255  			Insert: doc,
  2256  		}, createStatusOp(st, relationGlobalScope(id), relationStatusDoc))
  2257  
  2258  		for _, ep := range eps {
  2259  			key := relationApplicationSettingsKey(id, ep.ApplicationName)
  2260  			settingsOp := createSettingsOp(settingsC, key, map[string]interface{}{})
  2261  			ops = append(ops, settingsOp)
  2262  		}
  2263  		return ops, nil
  2264  	}
  2265  	if err = st.db().Run(buildTxn); err == nil {
  2266  		return &Relation{st, *doc}, nil
  2267  	}
  2268  	return nil, errors.Trace(err)
  2269  }
  2270  
  2271  func compatibleSupportedBases(b1s, b2s []corebase.Base) bool {
  2272  	for _, b1 := range b1s {
  2273  		for _, b2 := range b2s {
  2274  			if b1.IsCompatible(b2) {
  2275  				return true
  2276  			}
  2277  		}
  2278  	}
  2279  	return false
  2280  }
  2281  
  2282  // enforceMaxRelationLimit returns an error if adding an additional relation
  2283  // from app:ep exceeds the maximum allowed relation limit as specified in the
  2284  // charm metadata.
  2285  func enforceMaxRelationLimit(app ApplicationEntity, ep Endpoint) error {
  2286  	// No limit defined
  2287  	if ep.Relation.Limit == 0 {
  2288  		return nil
  2289  	}
  2290  
  2291  	// Count the number of already established relations for this app:endpoint
  2292  	existingRels, err := app.Relations()
  2293  	if err != nil {
  2294  		return errors.Trace(err)
  2295  	}
  2296  
  2297  	// Adding a new relation would bump the already established limit by 1
  2298  	establishedCount := establishedRelationCount(existingRels, ep.ApplicationName, ep.Relation)
  2299  	if establishedCount+1 > ep.Relation.Limit {
  2300  		return errors.QuotaLimitExceededf("establishing a new relation for %s:%s would exceed its maximum relation limit of %d", ep.ApplicationName, ep.Relation.Name, ep.Relation.Limit)
  2301  	}
  2302  
  2303  	return nil
  2304  }
  2305  
  2306  func aliveApplication(st *State, name string) (ApplicationEntity, error) {
  2307  	app, err := applicationByName(st, name)
  2308  	if errors.IsNotFound(err) {
  2309  		return nil, errors.Errorf("application %q does not exist", name)
  2310  	} else if err != nil {
  2311  		return nil, errors.Trace(err)
  2312  	} else if app.Life() != Alive {
  2313  		return nil, errors.Errorf("application %q is not alive", name)
  2314  	}
  2315  	return app, err
  2316  }
  2317  
  2318  // EndpointsRelation returns the existing relation with the given endpoints.
  2319  func (st *State) EndpointsRelation(endpoints ...Endpoint) (*Relation, error) {
  2320  	return st.KeyRelation(relationKey(endpoints))
  2321  }
  2322  
  2323  // KeyRelation returns the existing relation with the given key (which can
  2324  // be derived unambiguously from the relation's endpoints).
  2325  func (st *State) KeyRelation(key string) (*Relation, error) {
  2326  	relations, closer := st.db().GetCollection(relationsC)
  2327  	defer closer()
  2328  
  2329  	doc := relationDoc{}
  2330  	err := relations.FindId(key).One(&doc)
  2331  	if err == mgo.ErrNotFound {
  2332  		return nil, errors.NotFoundf("relation %q", key)
  2333  	}
  2334  	if err != nil {
  2335  		return nil, errors.Annotatef(err, "cannot get relation %q", key)
  2336  	}
  2337  	return newRelation(st, &doc), nil
  2338  }
  2339  
  2340  // Relation returns the existing relation with the given id.
  2341  func (st *State) Relation(id int) (*Relation, error) {
  2342  	relations, closer := st.db().GetCollection(relationsC)
  2343  	defer closer()
  2344  
  2345  	doc := relationDoc{}
  2346  	err := relations.Find(bson.D{{"id", id}}).One(&doc)
  2347  	if err == mgo.ErrNotFound {
  2348  		return nil, errors.NotFoundf("relation %d", id)
  2349  	}
  2350  	if err != nil {
  2351  		return nil, errors.Annotatef(err, "cannot get relation %d", id)
  2352  	}
  2353  	return newRelation(st, &doc), nil
  2354  }
  2355  
  2356  // AllRelations returns all relations in the model ordered by id.
  2357  func (st *State) AllRelations() (relations []*Relation, err error) {
  2358  	relationsCollection, closer := st.db().GetCollection(relationsC)
  2359  	defer closer()
  2360  
  2361  	docs := relationDocSlice{}
  2362  	err = relationsCollection.Find(nil).All(&docs)
  2363  	if err != nil {
  2364  		return nil, errors.Annotate(err, "cannot get all relations")
  2365  	}
  2366  	sort.Sort(docs)
  2367  	for _, v := range docs {
  2368  		relations = append(relations, newRelation(st, &v))
  2369  	}
  2370  	return
  2371  }
  2372  
  2373  // AliveRelationKeys returns the relation keys of all live relations in
  2374  // the model.  Used in charmhub metrics collection.
  2375  func (st *State) AliveRelationKeys() []string {
  2376  	relationsCollection, closer := st.db().GetCollection(relationsC)
  2377  	defer closer()
  2378  	var doc struct {
  2379  		Key string `bson:"key"`
  2380  	}
  2381  
  2382  	var keys []string
  2383  	iter := relationsCollection.Find(isAliveDoc).Iter()
  2384  	defer func() { _ = iter.Close() }()
  2385  	for iter.Next(&doc) {
  2386  		key := doc.Key
  2387  		keys = append(keys, key)
  2388  	}
  2389  	return keys
  2390  }
  2391  
  2392  // Report conforms to the Dependency Engine Report() interface, giving an opportunity to introspect
  2393  // what is going on at runtime.
  2394  func (st *State) Report() map[string]interface{} {
  2395  	if st.workers == nil {
  2396  		return nil
  2397  	}
  2398  	return st.workers.Report()
  2399  }
  2400  
  2401  type relationDocSlice []relationDoc
  2402  
  2403  func (rdc relationDocSlice) Len() int      { return len(rdc) }
  2404  func (rdc relationDocSlice) Swap(i, j int) { rdc[i], rdc[j] = rdc[j], rdc[i] }
  2405  func (rdc relationDocSlice) Less(i, j int) bool {
  2406  	return rdc[i].Id < rdc[j].Id
  2407  }
  2408  
  2409  // Unit returns a unit by name.
  2410  func (st *State) Unit(name string) (*Unit, error) {
  2411  	if !names.IsValidUnit(name) {
  2412  		return nil, errors.Errorf("%q is not a valid unit name", name)
  2413  	}
  2414  	units, closer := st.db().GetCollection(unitsC)
  2415  	defer closer()
  2416  
  2417  	doc := unitDoc{}
  2418  	err := units.FindId(name).One(&doc)
  2419  	if err == mgo.ErrNotFound {
  2420  		return nil, errors.NotFoundf("unit %q", name)
  2421  	}
  2422  	if err != nil {
  2423  		return nil, errors.Annotatef(err, "cannot get unit %q", name)
  2424  	}
  2425  	model, err := st.Model()
  2426  	if err != nil {
  2427  		return nil, errors.Trace(err)
  2428  	}
  2429  	return newUnit(st, model.Type(), &doc), nil
  2430  }
  2431  
  2432  // UnitsFor returns the units placed in the given machine id.
  2433  func (st *State) UnitsFor(machineId string) ([]*Unit, error) {
  2434  	if !names.IsValidMachine(machineId) {
  2435  		return nil, errors.Errorf("%q is not a valid machine id", machineId)
  2436  	}
  2437  	m := &Machine{
  2438  		st: st,
  2439  		doc: machineDoc{
  2440  			Id: machineId,
  2441  		},
  2442  	}
  2443  	return m.Units()
  2444  }
  2445  
  2446  // UnitsInError returns the units which have an agent status of Error.
  2447  func (st *State) UnitsInError() ([]*Unit, error) {
  2448  	// First, find the agents in error state.
  2449  	agentGlobalKeys, err := getEntityKeysForStatus(st, "u", status.Error)
  2450  	if err != nil {
  2451  		return nil, errors.Trace(err)
  2452  	}
  2453  	// Extract the unit names.
  2454  	unitNames := make([]string, len(agentGlobalKeys))
  2455  	for i, key := range agentGlobalKeys {
  2456  		// agent key prefix is "u#"
  2457  		if !strings.HasPrefix(key, "u#") {
  2458  			return nil, errors.NotValidf("unit agent global key %q", key)
  2459  		}
  2460  		unitNames[i] = key[2:]
  2461  	}
  2462  
  2463  	// Query the units with the names of units in error.
  2464  	units, closer := st.db().GetCollection(unitsC)
  2465  	defer closer()
  2466  
  2467  	var docs []unitDoc
  2468  	err = units.Find(bson.D{{"name", bson.D{{"$in", unitNames}}}}).All(&docs)
  2469  	if err != nil {
  2470  		return nil, errors.Trace(err)
  2471  	}
  2472  	model, err := st.Model()
  2473  	if err != nil {
  2474  		return nil, errors.Trace(err)
  2475  	}
  2476  
  2477  	result := make([]*Unit, len(docs))
  2478  	for i, doc := range docs {
  2479  		result[i] = &Unit{st: st, doc: doc, modelType: model.Type()}
  2480  	}
  2481  	return result, nil
  2482  }
  2483  
  2484  // AssignUnit places the unit on a machine. Depending on the policy, and the
  2485  // state of the model, this may lead to new instances being launched
  2486  // within the model.
  2487  func (st *State) AssignUnit(u *Unit, policy AssignmentPolicy) (err error) {
  2488  	if !u.IsPrincipal() {
  2489  		return errors.Errorf("subordinate unit %q cannot be assigned directly to a machine", u)
  2490  	}
  2491  	defer errors.DeferredAnnotatef(&err, "cannot assign unit %q to machine", u)
  2492  	var m *Machine
  2493  	switch policy {
  2494  	case AssignLocal:
  2495  		m, err = st.Machine("0")
  2496  		if err != nil {
  2497  			return errors.Trace(err)
  2498  		}
  2499  		return u.AssignToMachine(m)
  2500  	case AssignClean:
  2501  		if _, err = u.AssignToCleanMachine(); errors.Cause(err) != noCleanMachines {
  2502  			return errors.Trace(err)
  2503  		}
  2504  		return u.AssignToNewMachineOrContainer()
  2505  	case AssignCleanEmpty:
  2506  		if _, err = u.AssignToCleanEmptyMachine(); errors.Cause(err) != noCleanMachines {
  2507  			return errors.Trace(err)
  2508  		}
  2509  		return u.AssignToNewMachineOrContainer()
  2510  	case AssignNew:
  2511  		return errors.Trace(u.AssignToNewMachine())
  2512  	}
  2513  	return errors.Errorf("unknown unit assignment policy: %q", policy)
  2514  }
  2515  
  2516  // SetAdminMongoPassword sets the administrative password
  2517  // to access the state. If the password is non-empty,
  2518  // all subsequent attempts to access the state must
  2519  // be authorized; otherwise no authorization is required.
  2520  func (st *State) SetAdminMongoPassword(password string) error {
  2521  	err := mongo.SetAdminMongoPassword(st.session, mongo.AdminUser, password)
  2522  	return errors.Trace(err)
  2523  }
  2524  
  2525  func (st *State) networkEntityGlobalKeyOp(globalKey string, providerId corenetwork.Id) txn.Op {
  2526  	key := st.networkEntityGlobalKey(globalKey, providerId)
  2527  	return txn.Op{
  2528  		C:      providerIDsC,
  2529  		Id:     key,
  2530  		Assert: txn.DocMissing,
  2531  		Insert: providerIdDoc{ID: key},
  2532  	}
  2533  }
  2534  
  2535  func (st *State) networkEntityGlobalKeyRemoveOp(globalKey string, providerId corenetwork.Id) txn.Op {
  2536  	key := st.networkEntityGlobalKey(globalKey, providerId)
  2537  	return txn.Op{
  2538  		C:      providerIDsC,
  2539  		Id:     key,
  2540  		Remove: true,
  2541  	}
  2542  }
  2543  
  2544  func (st *State) networkEntityGlobalKeyExists(globalKey string, providerId corenetwork.Id) (bool, error) {
  2545  	col, closer := st.db().GetCollection(providerIDsC)
  2546  	defer closer()
  2547  
  2548  	key := st.networkEntityGlobalKey(globalKey, providerId)
  2549  	var doc providerIdDoc
  2550  	err := col.FindId(key).One(&doc)
  2551  
  2552  	switch err {
  2553  	case nil:
  2554  		return true, nil
  2555  	case mgo.ErrNotFound:
  2556  		return false, nil
  2557  	default:
  2558  		return false, errors.Annotatef(err, "reading provider ID %q", key)
  2559  	}
  2560  }
  2561  
  2562  func (st *State) networkEntityGlobalKey(globalKey string, providerId corenetwork.Id) string {
  2563  	return st.docID(globalKey + ":" + string(providerId))
  2564  }
  2565  
  2566  // SetSLA sets the SLA on the current connected model.
  2567  func (st *State) SetSLA(level, owner string, credentials []byte) error {
  2568  	model, err := st.Model()
  2569  	if err != nil {
  2570  		return errors.Trace(err)
  2571  	}
  2572  	return model.SetSLA(level, owner, credentials)
  2573  }
  2574  
  2575  // SetModelMeterStatus sets the meter status for the current connected model.
  2576  func (st *State) SetModelMeterStatus(status, info string) error {
  2577  	model, err := st.Model()
  2578  	if err != nil {
  2579  		return errors.Trace(err)
  2580  	}
  2581  	return model.SetMeterStatus(status, info)
  2582  }
  2583  
  2584  // ModelMeterStatus returns the meter status for the current connected model.
  2585  func (st *State) ModelMeterStatus() (MeterStatus, error) {
  2586  	model, err := st.Model()
  2587  	if err != nil {
  2588  		return MeterStatus{MeterNotAvailable, ""}, errors.Trace(err)
  2589  	}
  2590  	return model.MeterStatus(), nil
  2591  }
  2592  
  2593  // SLALevel returns the SLA level of the current connected model.
  2594  func (st *State) SLALevel() (string, error) {
  2595  	model, err := st.Model()
  2596  	if err != nil {
  2597  		return "", errors.Trace(err)
  2598  	}
  2599  	return model.SLALevel(), nil
  2600  }
  2601  
  2602  // SLACredential returns the SLA credential of the current connected model.
  2603  func (st *State) SLACredential() ([]byte, error) {
  2604  	model, err := st.Model()
  2605  	if err != nil {
  2606  		return []byte{}, errors.Trace(err)
  2607  	}
  2608  	return model.SLACredential(), nil
  2609  }
  2610  
  2611  var tagPrefix = map[byte]string{
  2612  	'm': names.MachineTagKind + "-",
  2613  	'a': names.ApplicationTagKind + "-",
  2614  	'u': names.UnitTagKind + "-",
  2615  	'e': names.ModelTagKind + "-",
  2616  	'r': names.RelationTagKind + "-",
  2617  }
  2618  
  2619  func tagForGlobalKey(key string) (string, bool) {
  2620  	if len(key) < 3 || key[1] != '#' {
  2621  		return "", false
  2622  	}
  2623  	p, ok := tagPrefix[key[0]]
  2624  	if !ok {
  2625  		return "", false
  2626  	}
  2627  	return p + key[2:], true
  2628  }
  2629  
  2630  // TagFromDocID tries attempts to extract an entity-identifying tag from a
  2631  // Mongo document ID.
  2632  // For example "c9741ea1-0c2a-444d-82f5-787583a48557:a#mediawiki" would yield
  2633  // an application tag for "mediawiki"
  2634  func TagFromDocID(docID string) names.Tag {
  2635  	_, localID, _ := splitDocID(docID)
  2636  	switch {
  2637  	case strings.HasPrefix(localID, "a#"):
  2638  		return names.NewApplicationTag(localID[2:])
  2639  	case strings.HasPrefix(localID, "m#"):
  2640  		return names.NewMachineTag(localID[2:])
  2641  	case strings.HasPrefix(localID, "u#"):
  2642  		return names.NewUnitTag(localID[2:])
  2643  	case strings.HasPrefix(localID, "e"):
  2644  		return names.NewModelTag(docID)
  2645  	default:
  2646  		return nil
  2647  	}
  2648  }