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

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state
     5  
     6  import (
     7  	"fmt"
     8  	"os"
     9  	"path/filepath"
    10  	"strconv"
    11  	"time" // Only used for time types.
    12  
    13  	"github.com/juju/charm/v12"
    14  	"github.com/juju/clock"
    15  	"github.com/juju/clock/testclock"
    16  	"github.com/juju/description/v5"
    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  	jc "github.com/juju/testing/checkers"
    24  	jujutxn "github.com/juju/txn/v3"
    25  	txntesting "github.com/juju/txn/v3/testing"
    26  	jutils "github.com/juju/utils/v3"
    27  	"github.com/juju/worker/v3"
    28  	"github.com/kr/pretty"
    29  	gc "gopkg.in/check.v1"
    30  
    31  	corebase "github.com/juju/juju/core/base"
    32  	"github.com/juju/juju/core/network"
    33  	"github.com/juju/juju/core/permission"
    34  	"github.com/juju/juju/core/resources"
    35  	"github.com/juju/juju/core/secrets"
    36  	"github.com/juju/juju/core/status"
    37  	"github.com/juju/juju/mongo"
    38  	"github.com/juju/juju/mongo/utils"
    39  	"github.com/juju/juju/state/storage"
    40  	"github.com/juju/juju/state/watcher"
    41  	"github.com/juju/juju/testcharms"
    42  	"github.com/juju/juju/testcharms/repo"
    43  	"github.com/juju/juju/version"
    44  )
    45  
    46  const (
    47  	MachinesC         = machinesC
    48  	ModelEntityRefsC  = modelEntityRefsC
    49  	ApplicationsC     = applicationsC
    50  	OfferConnectionsC = offerConnectionsC
    51  	EndpointBindingsC = endpointBindingsC
    52  	ControllersC      = controllersC
    53  	UsersC            = usersC
    54  	BlockDevicesC     = blockDevicesC
    55  	StorageInstancesC = storageInstancesC
    56  	GlobalSettingsC   = globalSettingsC
    57  	SettingsC         = settingsC
    58  	UnitsC            = unitsC
    59  )
    60  
    61  var (
    62  	BinarystorageNew              = &binarystorageNew
    63  	MachineIdLessThan             = machineIdLessThan
    64  	CombineMeterStatus            = combineMeterStatus
    65  	ApplicationGlobalKey          = applicationGlobalKey
    66  	CloudGlobalKey                = cloudGlobalKey
    67  	RegionSettingsGlobalKey       = regionSettingsGlobalKey
    68  	ModelGlobalKey                = modelGlobalKey
    69  	DBCollectionSizeToInt         = dbCollectionSizeToInt
    70  	NewEntityWatcher              = newEntityWatcher
    71  	ApplicationHasConnectedOffers = applicationHasConnectedOffers
    72  	NewActionNotificationWatcher  = newActionNotificationWatcher
    73  )
    74  
    75  type (
    76  	CharmDoc       charmDoc
    77  	ApplicationDoc = applicationDoc
    78  	ConstraintsDoc = constraintsDoc
    79  
    80  	StorageBackend         = storageBackend
    81  	DeviceBackend          = deviceBackend
    82  	ControllerNodeInstance = controllerNode
    83  )
    84  
    85  var (
    86  	IsDying = isDying
    87  )
    88  
    89  func NewStateSettingsForCollection(backend modelBackend, collection string) *StateSettings {
    90  	return &StateSettings{backend, globalSettingsC}
    91  }
    92  
    93  // EnsureWorkersStarted ensures that all the automatically
    94  // started state workers are running, so that tests which
    95  // insert transaction hooks are less likely to have the hooks
    96  // run by some other worker, and any side effects of starting
    97  // the workers (for example, creating collections) will have
    98  // taken effect.
    99  func EnsureWorkersStarted(st *State) {
   100  	// Note: we don't start the all-watcher workers, as
   101  	// they're started on demand anyway.
   102  	st.workers.txnLogWatcher()
   103  }
   104  
   105  func SetTestHooks(c *gc.C, st *State, hooks ...jujutxn.TestHook) txntesting.TransactionChecker {
   106  	EnsureWorkersStarted(st)
   107  	return txntesting.SetTestHooks(c, newRunnerForHooks(st), hooks...)
   108  }
   109  
   110  func SetBeforeHooks(c *gc.C, st *State, fs ...func()) txntesting.TransactionChecker {
   111  	EnsureWorkersStarted(st)
   112  	return txntesting.SetBeforeHooks(c, newRunnerForHooks(st), fs...)
   113  }
   114  
   115  // SetFailIfTransaction will set a transaction hook that marks the test as an error
   116  // if there is a transaction run. This is used if you know a given set of operations
   117  // should *not* trigger database updates.
   118  func SetFailIfTransaction(c *gc.C, st *State) txntesting.TransactionChecker {
   119  	EnsureWorkersStarted(st)
   120  	return txntesting.SetFailIfTransaction(c, newRunnerForHooks(st))
   121  }
   122  
   123  func SetAfterHooks(c *gc.C, st *State, fs ...func()) txntesting.TransactionChecker {
   124  	EnsureWorkersStarted(st)
   125  	return txntesting.SetAfterHooks(c, newRunnerForHooks(st), fs...)
   126  }
   127  
   128  func SetRetryHooks(c *gc.C, st *State, block, check func()) txntesting.TransactionChecker {
   129  	EnsureWorkersStarted(st)
   130  	return txntesting.SetRetryHooks(c, newRunnerForHooks(st), block, check)
   131  }
   132  
   133  func SetMaxTxnAttempts(c *gc.C, st *State, n int) {
   134  	st.maxTxnAttempts = n
   135  	db := st.database.(*database)
   136  	db.maxTxnAttempts = n
   137  	runner := jujutxn.NewRunner(jujutxn.RunnerParams{
   138  		Database:                  db.raw,
   139  		Clock:                     st.stateClock,
   140  		TransactionCollectionName: "txns",
   141  		ChangeLogName:             "-",
   142  		ServerSideTransactions:    true,
   143  		MaxRetryAttempts:          db.maxTxnAttempts,
   144  	})
   145  	db.runner = runner
   146  	return
   147  }
   148  
   149  func newRunnerForHooks(st *State) jujutxn.Runner {
   150  	db := st.database.(*database)
   151  	runner := jujutxn.NewRunner(jujutxn.RunnerParams{
   152  		Database:                  db.raw,
   153  		Clock:                     st.stateClock,
   154  		TransactionCollectionName: "txns",
   155  		ChangeLogName:             "-",
   156  		ServerSideTransactions:    true,
   157  		RunTransactionObserver: func(t jujutxn.Transaction) {
   158  			txnLogger.Tracef("ran transaction in %.3fs (retries: %d) %# v\nerr: %v",
   159  				t.Duration.Seconds(), t.Attempt, pretty.Formatter(t.Ops), t.Error)
   160  		},
   161  		MaxRetryAttempts: db.maxTxnAttempts,
   162  	})
   163  	db.runner = runner
   164  	return runner
   165  }
   166  
   167  // SetPolicy updates the State's policy field to the
   168  // given Policy, and returns the old value.
   169  func SetPolicy(st *State, p Policy) Policy {
   170  	old := st.policy
   171  	st.policy = p
   172  	return old
   173  }
   174  
   175  func CloudModelRefCount(st *State, cloudName string) (int, error) {
   176  	refcounts, closer := st.db().GetCollection(globalRefcountsC)
   177  	defer closer()
   178  
   179  	key := cloudModelRefCountKey(cloudName)
   180  	return nsRefcounts.read(refcounts, key)
   181  }
   182  
   183  func ApplicationSettingsRefCount(st *State, appName string, curl *string) (int, error) {
   184  	refcounts, closer := st.db().GetCollection(refcountsC)
   185  	defer closer()
   186  
   187  	key := applicationCharmConfigKey(appName, curl)
   188  	return nsRefcounts.read(refcounts, key)
   189  }
   190  
   191  func ApplicationOffersRefCount(st *State, appName string) (int, error) {
   192  	refcounts, closer := st.db().GetCollection(refcountsC)
   193  	defer closer()
   194  
   195  	key := applicationOffersRefCountKey(appName)
   196  	return nsRefcounts.read(refcounts, key)
   197  }
   198  
   199  func ControllerRefCount(st *State, controllerUUID string) (int, error) {
   200  	refcounts, closer := st.db().GetCollection(globalRefcountsC)
   201  	defer closer()
   202  
   203  	key := externalControllerRefCountKey(controllerUUID)
   204  	return nsRefcounts.read(refcounts, key)
   205  }
   206  
   207  func IncSecretConsumerRefCount(st *State, uri *secrets.URI, inc int) error {
   208  	refCountCollection, ccloser := st.db().GetCollection(refcountsC)
   209  	defer ccloser()
   210  	incOp, err := nsRefcounts.CreateOrIncRefOp(refCountCollection, uri.ID, inc)
   211  	if err != nil {
   212  		return errors.Trace(err)
   213  	}
   214  	return st.db().RunTransaction([]txn.Op{incOp})
   215  }
   216  
   217  func SecretBackendRefCount(st *State, backendID string) (int, error) {
   218  	refcounts, closer := st.db().GetCollection(globalRefcountsC)
   219  	defer closer()
   220  
   221  	key := secretBackendRefCountKey(backendID)
   222  	return nsRefcounts.read(refcounts, key)
   223  }
   224  
   225  func AddTestingCharm(c *gc.C, st *State, name string) *Charm {
   226  	return addCharm(c, st, "quantal", testcharms.Repo.CharmDir(name))
   227  }
   228  
   229  func AddTestingCharmFromRepo(c *gc.C, st *State, name string, repo *repo.CharmRepo) *Charm {
   230  	return addCharm(c, st, "quantal", repo.CharmDir(name))
   231  }
   232  
   233  func AddTestingCharmWithSeries(c *gc.C, st *State, name string, series string) *Charm {
   234  	return addCharm(c, st, series, testcharms.Repo.CharmDir(name))
   235  }
   236  
   237  func getCharmRepo(series string) *repo.CharmRepo {
   238  	// All testing charms for state are under `quantal` except `kubernetes`.
   239  	if series == "kubernetes" {
   240  		return testcharms.RepoForSeries(series)
   241  	}
   242  	return testcharms.Repo
   243  }
   244  
   245  func AddTestingCharmForSeries(c *gc.C, st *State, series, name string) *Charm {
   246  	// Existing logic!
   247  	// Get charm from `quantal` dir or `kubernetes`.
   248  	return addCharm(c, st, series, getCharmRepo(series).CharmDir(name))
   249  }
   250  
   251  func AddTestingCharmhubCharmForSeries(c *gc.C, st *State, series, name string) *Charm {
   252  	ch := getCharmRepo(series).CharmDir(name)
   253  	ident := fmt.Sprintf("amd64/%s/%s-%d", series, name, ch.Revision())
   254  	curl := "ch:" + ident
   255  	info := CharmInfo{
   256  		Charm:       ch,
   257  		ID:          curl,
   258  		StoragePath: "dummy-path",
   259  		SHA256:      ident + "-sha256",
   260  	}
   261  	sch, err := st.AddCharm(info)
   262  	c.Assert(err, jc.ErrorIsNil)
   263  	return sch
   264  }
   265  
   266  func AddTestingCharmMultiSeries(c *gc.C, st *State, name string) *Charm {
   267  	ch := testcharms.Repo.CharmDir(name)
   268  	ident := fmt.Sprintf("%s-%d", ch.Meta().Name, ch.Revision())
   269  	curl := "ch:" + ident
   270  	info := CharmInfo{
   271  		Charm:       ch,
   272  		ID:          curl,
   273  		StoragePath: "dummy-path",
   274  		SHA256:      ident + "-sha256",
   275  	}
   276  	sch, err := st.AddCharm(info)
   277  	c.Assert(err, jc.ErrorIsNil)
   278  	return sch
   279  }
   280  
   281  func AddTestingApplication(c *gc.C, st *State, name string, ch *Charm) *Application {
   282  	return addTestingApplication(c, addTestingApplicationParams{
   283  		st:   st,
   284  		name: name,
   285  		ch:   ch,
   286  	})
   287  }
   288  
   289  func AddTestingApplicationForBase(c *gc.C, st *State, base Base, name string, ch *Charm) *Application {
   290  	return addTestingApplication(c, addTestingApplicationParams{
   291  		st: st,
   292  		origin: &CharmOrigin{Platform: &Platform{
   293  			OS:      base.OS,
   294  			Channel: base.Channel,
   295  		}},
   296  		name: name,
   297  		ch:   ch,
   298  	})
   299  }
   300  
   301  func AddTestingApplicationWithNumUnits(c *gc.C, st *State, numUnits int, name string, ch *Charm) *Application {
   302  	return addTestingApplication(c, addTestingApplicationParams{
   303  		st:       st,
   304  		numUnits: numUnits,
   305  		name:     name,
   306  		ch:       ch,
   307  	})
   308  }
   309  
   310  func AddTestingApplicationWithStorage(c *gc.C, st *State, name string, ch *Charm, storage map[string]StorageConstraints) *Application {
   311  	curl := charm.MustParseURL(ch.URL())
   312  	series := curl.Series
   313  	if series == "kubernetes" {
   314  		series = "focal"
   315  	}
   316  	base, err := corebase.GetBaseFromSeries(series)
   317  	c.Assert(err, jc.ErrorIsNil)
   318  	var source string
   319  	switch curl.Schema {
   320  	case "local":
   321  		source = "local"
   322  	case "ch":
   323  		source = "charm-hub"
   324  	case "cs":
   325  		source = "charm-store"
   326  	}
   327  	origin := &CharmOrigin{
   328  		Source: source,
   329  		Platform: &Platform{
   330  			OS:      base.OS,
   331  			Channel: base.Channel.String(),
   332  		},
   333  	}
   334  	return addTestingApplication(c, addTestingApplicationParams{
   335  		st:      st,
   336  		name:    name,
   337  		ch:      ch,
   338  		origin:  origin,
   339  		storage: storage,
   340  	})
   341  }
   342  
   343  func AddTestingApplicationWithDevices(c *gc.C, st *State, name string, ch *Charm, devices map[string]DeviceConstraints) *Application {
   344  	return addTestingApplication(c, addTestingApplicationParams{
   345  		st:      st,
   346  		name:    name,
   347  		ch:      ch,
   348  		devices: devices,
   349  	})
   350  }
   351  
   352  func AddTestingApplicationWithBindings(c *gc.C, st *State, name string, ch *Charm, bindings map[string]string) *Application {
   353  	return addTestingApplication(c, addTestingApplicationParams{
   354  		st:       st,
   355  		name:     name,
   356  		ch:       ch,
   357  		bindings: bindings,
   358  	})
   359  }
   360  
   361  type addTestingApplicationParams struct {
   362  	st       *State
   363  	name     string
   364  	ch       *Charm
   365  	origin   *CharmOrigin
   366  	bindings map[string]string
   367  	storage  map[string]StorageConstraints
   368  	devices  map[string]DeviceConstraints
   369  	numUnits int
   370  }
   371  
   372  func addTestingApplication(c *gc.C, params addTestingApplicationParams) *Application {
   373  	c.Assert(params.ch, gc.NotNil)
   374  	origin := params.origin
   375  	curl := charm.MustParseURL(params.ch.URL())
   376  	if origin == nil {
   377  		base, err := corebase.GetBaseFromSeries(curl.Series)
   378  		c.Assert(err, jc.ErrorIsNil)
   379  		var channel *Channel
   380  		// local charms cannot have a channel
   381  		if charm.CharmHub.Matches(curl.Schema) {
   382  			channel = &Channel{Risk: "stable"}
   383  		}
   384  		var source string
   385  		switch curl.Schema {
   386  		case "local":
   387  			source = "local"
   388  		case "ch":
   389  			source = "charm-hub"
   390  		case "cs":
   391  			source = "charm-store"
   392  		}
   393  		origin = &CharmOrigin{
   394  			Channel: channel,
   395  			Source:  source,
   396  			Platform: &Platform{
   397  				OS:      base.OS,
   398  				Channel: base.Channel.String(),
   399  			},
   400  		}
   401  	}
   402  	app, err := params.st.AddApplication(AddApplicationArgs{
   403  		Name:             params.name,
   404  		Charm:            params.ch,
   405  		CharmOrigin:      origin,
   406  		EndpointBindings: params.bindings,
   407  		Storage:          params.storage,
   408  		Devices:          params.devices,
   409  		NumUnits:         params.numUnits,
   410  	})
   411  	c.Assert(err, jc.ErrorIsNil)
   412  	return app
   413  }
   414  
   415  func addCustomCharmWithManifest(c *gc.C, st *State, repo *repo.CharmRepo, name, filename, content, series string, revision int, manifest bool) *Charm {
   416  	path := repo.ClonedDirPath(c.MkDir(), name)
   417  	if filename != "" {
   418  		if manifest {
   419  			manifestContent := `
   420  bases:
   421  - name: ubuntu
   422    channel: "18.04"
   423  `
   424  			manifestYAML := filepath.Join(path, "manifest.yaml")
   425  			err := os.WriteFile(manifestYAML, []byte(manifestContent), 0644)
   426  			c.Assert(err, jc.ErrorIsNil)
   427  		}
   428  		config := filepath.Join(path, filename)
   429  		err := os.WriteFile(config, []byte(content), 0644)
   430  		c.Assert(err, jc.ErrorIsNil)
   431  	}
   432  	ch, err := charm.ReadCharmDir(path)
   433  	c.Assert(err, jc.ErrorIsNil)
   434  	if revision != -1 {
   435  		ch.SetRevision(revision)
   436  	}
   437  	return addCharm(c, st, series, ch)
   438  }
   439  
   440  func addCustomCharm(c *gc.C, st *State, repo *repo.CharmRepo, name, filename, content, series string, revision int) *Charm {
   441  	return addCustomCharmWithManifest(c, st, repo, name, filename, content, series, revision, false)
   442  }
   443  
   444  func AddCustomCharmWithManifest(c *gc.C, st *State, name, filename, content, series string, revision int) *Charm {
   445  	return addCustomCharmWithManifest(c, st, testcharms.RepoForSeries(series), name, filename, content, series, revision, true)
   446  }
   447  
   448  func AddCustomCharmForSeries(c *gc.C, st *State, name, filename, content, series string, revision int) *Charm {
   449  	// Copy charm from `series` dir.
   450  	return addCustomCharm(c, st, testcharms.RepoForSeries(series), name, filename, content, series, revision)
   451  }
   452  
   453  func AddCustomCharm(c *gc.C, st *State, name, filename, content, series string, revision int) *Charm {
   454  	return addCustomCharm(c, st, getCharmRepo(series), name, filename, content, series, revision)
   455  }
   456  
   457  func addCharm(c *gc.C, st *State, series string, ch charm.Charm) *Charm {
   458  	ident := fmt.Sprintf("%s-%s-%d", series, ch.Meta().Name, ch.Revision())
   459  	curl := "local:" + series + "/" + ident
   460  	if series == "" {
   461  		ident = fmt.Sprintf("%s-%d", ch.Meta().Name, ch.Revision())
   462  		curl = "local:" + ident
   463  	}
   464  	info := CharmInfo{
   465  		Charm:       ch,
   466  		ID:          curl,
   467  		StoragePath: "dummy-path",
   468  		SHA256:      ident + "-sha256",
   469  	}
   470  	sch, err := st.AddCharm(info)
   471  	c.Assert(err, jc.ErrorIsNil)
   472  	return sch
   473  }
   474  
   475  // TxnRevno returns the txn-revno field of the document
   476  // associated with the given Id in the given collection.
   477  func TxnRevno(st *State, collName string, id interface{}) (int64, error) {
   478  	var doc struct {
   479  		TxnRevno int64 `bson:"txn-revno"`
   480  	}
   481  	coll, closer := st.db().GetCollection(collName)
   482  	defer closer()
   483  	err := coll.FindId(id).One(&doc)
   484  	if err != nil {
   485  		return 0, err
   486  	}
   487  	return doc.TxnRevno, nil
   488  }
   489  
   490  // MinUnitsRevno returns the Revno of the minUnits document
   491  // associated with the given application name.
   492  func MinUnitsRevno(st *State, applicationname string) (int, error) {
   493  	minUnitsCollection, closer := st.db().GetCollection(minUnitsC)
   494  	defer closer()
   495  	var doc minUnitsDoc
   496  	if err := minUnitsCollection.FindId(applicationname).One(&doc); err != nil {
   497  		return 0, err
   498  	}
   499  	return doc.Revno, nil
   500  }
   501  
   502  func ConvertTagToCollectionNameAndId(st *State, tag names.Tag) (string, interface{}, error) {
   503  	return st.tagToCollectionAndId(tag)
   504  }
   505  
   506  func NowToTheSecond(st *State) time.Time {
   507  	return st.nowToTheSecond()
   508  }
   509  
   510  // Return the PasswordSalt that goes along with the PasswordHash
   511  func GetUserPasswordSaltAndHash(u *User) (string, string) {
   512  	return u.doc.PasswordSalt, u.doc.PasswordHash
   513  }
   514  
   515  func CheckUserExists(st *State, name string) (bool, error) {
   516  	return st.checkUserExists(name)
   517  }
   518  
   519  func WatcherMergeIds(changeset *[]string, updates map[interface{}]bool, idconv func(string) (string, error)) error {
   520  	return mergeIds(changeset, updates, idconv)
   521  }
   522  
   523  func WatcherEnsureSuffixFn(marker string) func(string) string {
   524  	return ensureSuffixFn(marker)
   525  }
   526  
   527  func WatcherMakeIdFilter(st *State, marker string, receivers ...ActionReceiver) func(interface{}) bool {
   528  	return makeIdFilter(st, marker, receivers...)
   529  }
   530  
   531  func GetAllUpgradeInfos(st *State) ([]*UpgradeInfo, error) {
   532  	upgradeInfos, closer := st.db().GetCollection(upgradeInfoC)
   533  	defer closer()
   534  
   535  	var out []*UpgradeInfo
   536  	var doc upgradeInfoDoc
   537  	iter := upgradeInfos.Find(nil).Iter()
   538  	defer iter.Close()
   539  	for iter.Next(&doc) {
   540  		out = append(out, &UpgradeInfo{st: st, doc: doc})
   541  	}
   542  	if err := iter.Close(); err != nil {
   543  		return nil, err
   544  	}
   545  	return out, nil
   546  }
   547  
   548  func UserModelNameIndex(username, modelName string) string {
   549  	return userModelNameIndex(username, modelName)
   550  }
   551  
   552  func (m *Model) UniqueIndexExists() bool {
   553  	coll, closer := m.st.db().GetCollection(usermodelnameC)
   554  	defer closer()
   555  
   556  	var doc bson.M
   557  	err := coll.FindId(m.uniqueIndexID()).One(&doc)
   558  
   559  	return err == nil
   560  }
   561  
   562  func DocID(mb modelBackend, id string) string {
   563  	return mb.docID(id)
   564  }
   565  
   566  func LocalID(mb modelBackend, id string) string {
   567  	return mb.localID(id)
   568  }
   569  
   570  func StrictLocalID(mb modelBackend, id string) (string, error) {
   571  	return mb.strictLocalID(id)
   572  }
   573  
   574  func GetUnitModelUUID(unit *Unit) string {
   575  	return unit.doc.ModelUUID
   576  }
   577  
   578  func GetCollection(mb modelBackend, name string) (mongo.Collection, func()) {
   579  	return mb.db().GetCollection(name)
   580  }
   581  
   582  func GetRawCollection(mb modelBackend, name string) (*mgo.Collection, func()) {
   583  	return mb.db().GetRawCollection(name)
   584  }
   585  
   586  func HasRawAccess(collectionName string) bool {
   587  	return allCollections()[collectionName].rawAccess
   588  }
   589  
   590  func MultiModelCollections() []string {
   591  	var result []string
   592  	for name, info := range allCollections() {
   593  		if !info.global {
   594  			result = append(result, name)
   595  		}
   596  	}
   597  	return result
   598  }
   599  
   600  func Sequence(st *State, name string) (int, error) {
   601  	return sequence(st, name)
   602  }
   603  
   604  func ResetSequence(mb modelBackend, name string) error {
   605  	return resetSequence(mb, name)
   606  }
   607  
   608  func SequenceWithMin(st *State, name string, minVal int) (int, error) {
   609  	return sequenceWithMin(st, name, minVal)
   610  }
   611  
   612  func SequenceEnsure(st *State, name string, nextVal int) error {
   613  	sequences, closer := st.db().GetRawCollection(sequenceC)
   614  	defer closer()
   615  	updater := newDbSeqUpdater(sequences, st.ModelUUID(), name)
   616  	return updater.ensure(nextVal)
   617  }
   618  
   619  func (m *Model) SetDead() error {
   620  	ops := []txn.Op{{
   621  		C:      modelsC,
   622  		Id:     m.doc.UUID,
   623  		Update: bson.D{{"$set", bson.D{{"life", Dead}}}},
   624  	}, {
   625  		C:      usermodelnameC,
   626  		Id:     m.uniqueIndexID(),
   627  		Remove: true,
   628  	}}
   629  	return m.st.db().RunTransaction(ops)
   630  }
   631  
   632  func (st *State) SetDyingModelToDead() error {
   633  	return st.setDyingModelToDead()
   634  }
   635  
   636  func HostedModelCount(c *gc.C, st *State) int {
   637  	count, err := hostedModelCount(st)
   638  	c.Assert(err, jc.ErrorIsNil)
   639  	return count
   640  }
   641  
   642  type MockGlobalEntity struct {
   643  }
   644  
   645  func (m MockGlobalEntity) globalKey() string {
   646  	return "globalKey"
   647  }
   648  func (m MockGlobalEntity) Tag() names.Tag {
   649  	return names.NewMachineTag("42")
   650  }
   651  
   652  var (
   653  	_                    GlobalEntity = (*MockGlobalEntity)(nil)
   654  	TagToCollectionAndId              = (*State).tagToCollectionAndId
   655  )
   656  
   657  func AssertAddressConversion(c *gc.C, netAddr network.SpaceAddress) {
   658  	addr := fromNetworkAddress(netAddr, network.OriginUnknown)
   659  	newNetAddr := addr.networkAddress()
   660  	c.Assert(netAddr, gc.DeepEquals, newNetAddr)
   661  
   662  	size := 5
   663  	netAddrs := make(network.SpaceAddresses, size)
   664  	for i := 0; i < size; i++ {
   665  		netAddrs[i] = netAddr
   666  	}
   667  	addrs := fromNetworkAddresses(netAddrs, network.OriginUnknown)
   668  	newNetAddrs := networkAddresses(addrs)
   669  	c.Assert(netAddrs, gc.DeepEquals, newNetAddrs)
   670  }
   671  
   672  func AssertHostPortConversion(c *gc.C, netHostPort network.SpaceHostPort) {
   673  	hostPort := fromNetworkHostPort(netHostPort)
   674  	newNetHostPort := hostPort.networkHostPort()
   675  	c.Assert(netHostPort, gc.DeepEquals, newNetHostPort)
   676  
   677  	size := 5
   678  	netHostsPorts := make([]network.SpaceHostPorts, size)
   679  	for i := 0; i < size; i++ {
   680  		netHostsPorts[i] = make(network.SpaceHostPorts, size)
   681  		for j := 0; j < size; j++ {
   682  			netHostsPorts[i][j] = netHostPort
   683  		}
   684  	}
   685  	hostsPorts := fromNetworkHostsPorts(netHostsPorts)
   686  	newNetHostsPorts := networkHostsPorts(hostsPorts)
   687  	c.Assert(netHostsPorts, gc.DeepEquals, newNetHostsPorts)
   688  }
   689  
   690  // MakeLogDoc creates a database document for a single log message.
   691  func MakeLogDoc(
   692  	entity string,
   693  	t time.Time,
   694  	module string,
   695  	location string,
   696  	level loggo.Level,
   697  	msg string,
   698  	labels []string,
   699  ) *logDoc {
   700  	return &logDoc{
   701  		Id:       bson.NewObjectId(),
   702  		Time:     t.UnixNano(),
   703  		Entity:   entity,
   704  		Version:  version.Current.String(),
   705  		Module:   module,
   706  		Location: location,
   707  		Level:    int(level),
   708  		Message:  msg,
   709  		Labels:   labels,
   710  	}
   711  }
   712  
   713  func SpaceDoc(s *Space) spaceDoc {
   714  	return s.doc
   715  }
   716  
   717  func ForceDestroyMachineOps(m *Machine) ([]txn.Op, error) {
   718  	// For test we do not want to wait for the force.
   719  	return m.forceDestroyOps(time.Duration(0))
   720  }
   721  
   722  func MakeActionIdConverter(st *State) func(string) (string, error) {
   723  	return func(id string) (string, error) {
   724  		id, err := st.strictLocalID(id)
   725  		if err != nil {
   726  			return "", errors.Trace(err)
   727  		}
   728  		return actionNotificationIdToActionId(id), err
   729  	}
   730  }
   731  
   732  func UpdateModelUserLastConnection(st *State, e permission.UserAccess, when time.Time) error {
   733  	model, err := st.Model()
   734  	if err != nil {
   735  		return errors.Trace(err)
   736  	}
   737  
   738  	return model.updateLastModelConnection(e.UserTag, when)
   739  }
   740  
   741  func SetWantsVote(st *State, id string, wantsVote bool) error {
   742  	op := setControllerWantsVoteOp(st, id, wantsVote)
   743  	return st.runRawTransaction([]txn.Op{op})
   744  }
   745  
   746  func RemoveEndpointBindingsForApplication(c *gc.C, app *Application) {
   747  	globalKey := app.globalKey()
   748  	removeOp := removeEndpointBindingsOp(globalKey)
   749  
   750  	txnError := app.st.db().RunTransaction([]txn.Op{removeOp})
   751  	err := onAbort(txnError, nil) // ignore ErrAborted as it asserts DocExists
   752  	c.Assert(err, jc.ErrorIsNil)
   753  }
   754  
   755  func RemoveOfferConnectionsForRelation(c *gc.C, rel *Relation) {
   756  	removeOps := removeOfferConnectionsForRelationOps(rel.Id())
   757  	txnError := rel.st.db().RunTransaction(removeOps)
   758  	err := onAbort(txnError, nil) // ignore ErrAborted as it asserts DocExists
   759  	c.Assert(err, jc.ErrorIsNil)
   760  }
   761  
   762  func RelationCount(app *Application) int {
   763  	return app.doc.RelationCount
   764  }
   765  
   766  func AssertEndpointBindingsNotFoundForApplication(c *gc.C, app *Application) {
   767  	globalKey := app.globalKey()
   768  	storedBindings, _, err := readEndpointBindings(app.st, globalKey)
   769  	c.Assert(storedBindings, gc.IsNil)
   770  	c.Assert(err, gc.ErrorMatches, fmt.Sprintf("endpoint bindings for %q not found", globalKey))
   771  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   772  }
   773  
   774  func StorageAttachmentCount(instance StorageInstance) int {
   775  	internal, ok := instance.(*storageInstance)
   776  	if !ok {
   777  		return -1
   778  	}
   779  	return internal.doc.AttachmentCount
   780  }
   781  
   782  func ResetMigrationMode(c *gc.C, st *State) {
   783  	ops := []txn.Op{{
   784  		C:      modelsC,
   785  		Id:     st.ModelUUID(),
   786  		Assert: txn.DocExists,
   787  		Update: bson.M{
   788  			"$set": bson.M{"migration-mode": MigrationModeNone},
   789  		},
   790  	}}
   791  	err := st.db().RunTransaction(ops)
   792  	c.Assert(err, jc.ErrorIsNil)
   793  }
   794  
   795  func (a *RemoteApplication) SetDead() error {
   796  	ops := []txn.Op{{
   797  		C:      remoteApplicationsC,
   798  		Id:     a.doc.Name,
   799  		Update: bson.D{{"$set", bson.D{{"life", Dead}}}},
   800  	}}
   801  	return a.st.db().RunTransaction(ops)
   802  }
   803  
   804  func RemoveRelationStatus(c *gc.C, rel *Relation) {
   805  	st := rel.st
   806  	ops := []txn.Op{removeStatusOp(st, rel.globalScope())}
   807  	err := st.db().RunTransaction(ops)
   808  	c.Assert(err, jc.ErrorIsNil)
   809  }
   810  
   811  func RemoveUnitRelations(c *gc.C, rel *Relation) {
   812  	st := rel.st
   813  	scopes, closer := st.db().GetCollection(relationScopesC)
   814  	defer closer()
   815  	scopesW := scopes.Writeable()
   816  	_, err := scopesW.RemoveAll(nil)
   817  	c.Assert(err, jc.ErrorIsNil)
   818  }
   819  
   820  // PrimeUnitStatusHistory will add count history elements, advancing the test clock by
   821  // one second for each entry.
   822  func PrimeUnitStatusHistory(
   823  	c *gc.C, clock testclock.AdvanceableClock,
   824  	unit *Unit, statusVal status.Status,
   825  	count, batchSize int,
   826  	nextData func(int) map[string]interface{},
   827  ) {
   828  	globalKey := unit.globalKey()
   829  
   830  	history, closer := unit.st.db().GetCollection(statusesHistoryC)
   831  	defer closer()
   832  	historyW := history.Writeable()
   833  
   834  	var data map[string]interface{}
   835  	for i := 0; i < count; {
   836  		var docs []interface{}
   837  		for j := 0; j < batchSize && i < count; j++ {
   838  			clock.Advance(time.Second)
   839  			if nextData != nil {
   840  				data = utils.EscapeKeys(nextData(i))
   841  			}
   842  			docs = append(docs, &historicalStatusDoc{
   843  				Status:     statusVal,
   844  				StatusData: data,
   845  				Updated:    clock.Now().UnixNano(),
   846  				GlobalKey:  globalKey,
   847  			})
   848  			// Seems like you can't increment two values in one loop
   849  			i++
   850  		}
   851  		err := historyW.Insert(docs...)
   852  		c.Assert(err, jc.ErrorIsNil)
   853  	}
   854  	// Set the status for the unit itself.
   855  	doc := statusDoc{
   856  		Status:     statusVal,
   857  		StatusData: data,
   858  		Updated:    clock.Now().UnixNano(),
   859  	}
   860  
   861  	var buildTxn jujutxn.TransactionSource = func(int) ([]txn.Op, error) {
   862  		return statusSetOps(unit.st.db(), doc, globalKey)
   863  	}
   864  
   865  	err := unit.st.db().Run(buildTxn)
   866  	c.Assert(err, jc.ErrorIsNil)
   867  }
   868  
   869  // PrimeOperations generates operations and tasks to be pruned.
   870  // The method pads each entry with a 1MB string. This should allow us to infer the
   871  // approximate size of the entry and limit the number of entries that
   872  // must be generated for size related tests.
   873  func PrimeOperations(c *gc.C, age time.Time, unit *Unit, count, actionsPerOperation int) {
   874  	operationsCollection, closer := unit.st.db().GetCollection(operationsC)
   875  	defer closer()
   876  	actionCollection, closer := unit.st.db().GetCollection(actionsC)
   877  	defer closer()
   878  
   879  	operationsCollectionWriter := operationsCollection.Writeable()
   880  	actionCollectionWriter := actionCollection.Writeable()
   881  
   882  	const numBytes = 1 * 500 * 1000
   883  	var padding [numBytes]byte
   884  	var operationDocs []interface{}
   885  	var actionDocs []interface{}
   886  	for i := 0; i < count; i++ {
   887  		nextID, err := sequenceWithMin(unit.st, "task", 1)
   888  		c.Assert(err, jc.ErrorIsNil)
   889  		operationID := strconv.Itoa(nextID)
   890  		operationDocs = append(operationDocs, operationDoc{
   891  			DocId:     operationID,
   892  			ModelUUID: unit.st.ModelUUID(),
   893  			Summary:   "an operation",
   894  			Completed: age,
   895  			Status:    ActionCompleted,
   896  		})
   897  		for j := 0; j < actionsPerOperation; j++ {
   898  			id, err := jutils.NewUUID()
   899  			c.Assert(err, jc.ErrorIsNil)
   900  			actionDocs = append(actionDocs, actionDoc{
   901  				DocId:     id.String(),
   902  				ModelUUID: unit.st.ModelUUID(),
   903  				Receiver:  unit.Name(),
   904  				Completed: age,
   905  				Operation: operationID,
   906  				Status:    ActionCompleted,
   907  				Message:   string(padding[:numBytes]),
   908  			})
   909  		}
   910  	}
   911  
   912  	err := operationsCollectionWriter.Insert(operationDocs...)
   913  	c.Assert(err, jc.ErrorIsNil)
   914  	err = actionCollectionWriter.Insert(actionDocs...)
   915  	c.Assert(err, jc.ErrorIsNil)
   916  }
   917  
   918  // PrimeLegacyActions creates actions without a parent operation.
   919  func PrimeLegacyActions(c *gc.C, age time.Time, unit *Unit, count int) {
   920  	actionCollection, closer := unit.st.db().GetCollection(actionsC)
   921  	defer closer()
   922  
   923  	actionCollectionWriter := actionCollection.Writeable()
   924  
   925  	const numBytes = 1 * 500 * 1000
   926  	var padding [numBytes]byte
   927  	var actionDocs []interface{}
   928  	var ids []string
   929  	for i := 0; i < count; i++ {
   930  		nextID, err := sequenceWithMin(unit.st, "task", 1)
   931  		c.Assert(err, jc.ErrorIsNil)
   932  		ids = append(ids, fmt.Sprintf("%v:%d", unit.st.ModelUUID(), nextID))
   933  		actionDocs = append(actionDocs, actionDoc{
   934  			DocId:     strconv.Itoa(nextID),
   935  			ModelUUID: unit.st.ModelUUID(),
   936  			Receiver:  unit.Name(),
   937  			Completed: age,
   938  			Status:    ActionCompleted,
   939  			Message:   string(padding[:numBytes]),
   940  		})
   941  	}
   942  
   943  	err := actionCollectionWriter.Insert(actionDocs...)
   944  	c.Assert(err, jc.ErrorIsNil)
   945  	for _, id := range ids {
   946  		err = actionCollectionWriter.UpdateId(id, bson.D{{"$unset", bson.M{"operation": 1}}})
   947  		c.Assert(err, jc.ErrorIsNil)
   948  	}
   949  }
   950  
   951  // ActionOperationId returns the parent operation of an action.
   952  func ActionOperationId(a Action) string {
   953  	return a.(*action).doc.Operation
   954  }
   955  
   956  // GetInternalWorkers returns the internal workers managed by a State
   957  // to allow inspection in tests.
   958  func GetInternalWorkers(st *State) worker.Worker {
   959  	return st.workers
   960  }
   961  
   962  // ResourceStoragePath returns the path used to store resource content
   963  // in the managed blob store, given the resource ID.
   964  func ResourceStoragePath(c *gc.C, st *State, id string) string {
   965  	p := st.Resources().(*resourcePersistence)
   966  	_, storagePath, err := p.getResource(id)
   967  	c.Assert(err, jc.ErrorIsNil)
   968  	return storagePath
   969  }
   970  
   971  func StagedResourceForTest(c *gc.C, st *State, res resources.Resource) *StagedResource {
   972  	persist := st.Resources().(*resourcePersistence)
   973  	storagePath := storagePath(res.Name, res.ApplicationID, res.PendingID)
   974  	r, err := persist.stageResource(res, storagePath)
   975  	c.Assert(err, jc.ErrorIsNil)
   976  	return r
   977  }
   978  
   979  // IsBlobStored returns true if a given storage path is in used in the
   980  // managed blob store.
   981  func IsBlobStored(c *gc.C, st *State, storagePath string) bool {
   982  	stor := storage.NewStorage(st.ModelUUID(), st.MongoSession())
   983  	r, _, err := stor.Get(storagePath)
   984  	if err != nil {
   985  		if errors.IsNotFound(err) {
   986  			return false
   987  		}
   988  		c.Fatalf("Get failed: %v", err)
   989  		return false
   990  	}
   991  	r.Close()
   992  	return true
   993  }
   994  
   995  // AssertNoCleanupsWithKind checks that there are no cleanups
   996  // of a given kind scheduled.
   997  func AssertNoCleanupsWithKind(c *gc.C, st *State, kind cleanupKind) {
   998  	var docs []cleanupDoc
   999  	cleanups, closer := st.db().GetCollection(cleanupsC)
  1000  	defer closer()
  1001  	err := cleanups.Find(nil).All(&docs)
  1002  	c.Assert(err, jc.ErrorIsNil)
  1003  	for _, doc := range docs {
  1004  		if doc.Kind == kind {
  1005  			c.Fatalf("found cleanup of kind %q", kind)
  1006  		}
  1007  	}
  1008  }
  1009  
  1010  // AssertNoCleanupsWithKind checks that there is at least
  1011  // one cleanup of a given kind scheduled.
  1012  func AssertCleanupsWithKind(c *gc.C, st *State, kind cleanupKind) {
  1013  	var docs []cleanupDoc
  1014  	cleanups, closer := st.db().GetCollection(cleanupsC)
  1015  	defer closer()
  1016  	err := cleanups.Find(nil).All(&docs)
  1017  	c.Assert(err, jc.ErrorIsNil)
  1018  	for _, doc := range docs {
  1019  		if doc.Kind == kind {
  1020  			return
  1021  		}
  1022  	}
  1023  	c.Fatalf("found no cleanups of kind %q", kind)
  1024  }
  1025  
  1026  // AssertNoCleanups checks that there are no cleanups scheduled.
  1027  func AssertNoCleanups(c *gc.C, st *State) {
  1028  	var docs []cleanupDoc
  1029  	cleanups, closer := st.db().GetCollection(cleanupsC)
  1030  	defer closer()
  1031  	err := cleanups.Find(nil).All(&docs)
  1032  	c.Assert(err, jc.ErrorIsNil)
  1033  	if len(docs) > 0 {
  1034  		c.Fatalf("unexpected cleanups: %+v", docs)
  1035  	}
  1036  }
  1037  
  1038  // GetApplicationCharmConfig allows access to settings collection for a
  1039  // given application in order to get the charm config.
  1040  func GetApplicationCharmConfig(st *State, app *Application) *Settings {
  1041  	return newSettings(st.db(), settingsC, app.charmConfigKey())
  1042  }
  1043  
  1044  // GetApplicationConfig allows access to settings collection for a
  1045  // given application in order to get the application config.
  1046  func GetApplicationConfig(st *State, app *Application) *Settings {
  1047  	return newSettings(st.db(), settingsC, app.applicationConfigKey())
  1048  }
  1049  
  1050  // GetApplicationHasResources returns the app's HasResources value.
  1051  func GetApplicationHasResources(app *Application) bool {
  1052  	return app.doc.HasResources
  1053  }
  1054  
  1055  // GetControllerSettings allows access to settings collection for
  1056  // the controller.
  1057  func GetControllerSettings(st *State) *Settings {
  1058  	return newSettings(st.db(), controllersC, ControllerSettingsGlobalKey)
  1059  }
  1060  
  1061  // GetPopulatedSettings returns a reference to settings with the input values
  1062  // populated. Attempting to read/write will cause nil-reference panics.
  1063  func GetPopulatedSettings(cfg map[string]interface{}) *Settings {
  1064  	return &Settings{
  1065  		disk: copyMap(cfg, nil),
  1066  		core: copyMap(cfg, nil),
  1067  	}
  1068  }
  1069  
  1070  // NewSLALevel returns a new SLA level.
  1071  func NewSLALevel(level string) (slaLevel, error) {
  1072  	return newSLALevel(level)
  1073  }
  1074  
  1075  func AppStorageConstraints(app *Application) (map[string]StorageConstraints, error) {
  1076  	return readStorageConstraints(app.st, app.storageConstraintsKey())
  1077  }
  1078  
  1079  func RemoveRelation(c *gc.C, rel *Relation, force bool) {
  1080  	op := &ForcedOperation{Force: force}
  1081  	ops, err := rel.removeOps("", "", op)
  1082  	c.Assert(err, jc.ErrorIsNil)
  1083  	c.Logf("operational errors %v", op.Errors)
  1084  	c.Assert(op.Errors, gc.HasLen, 0)
  1085  	err = rel.st.db().RunTransaction(ops)
  1086  	c.Assert(err, jc.ErrorIsNil)
  1087  }
  1088  
  1089  func AddVolumeOps(st *State, params VolumeParams, machineId string) ([]txn.Op, names.VolumeTag, error) {
  1090  	sb, err := NewStorageBackend(st)
  1091  	if err != nil {
  1092  		return nil, names.VolumeTag{}, err
  1093  	}
  1094  	return sb.addVolumeOps(params, machineId)
  1095  }
  1096  
  1097  func ModelBackendFromStorageBackend(sb *StorageBackend) modelBackend {
  1098  	return sb.mb
  1099  }
  1100  
  1101  func (st *State) ModelQueryForUser(user names.UserTag, isSuperuser bool) (mongo.Query, SessionCloser, error) {
  1102  	return st.modelQueryForUser(user, isSuperuser)
  1103  }
  1104  
  1105  func UnitsHaveChanged(m *Machine, unitNames []string) (bool, error) {
  1106  	return m.unitsHaveChanged(unitNames)
  1107  }
  1108  
  1109  func GetCloudContainerStatus(st *State, name string) (status.StatusInfo, error) {
  1110  	return getStatus(st.db(), globalCloudContainerKey(name), "unit")
  1111  }
  1112  
  1113  func GetCloudContainerStatusHistory(st *State, name string, filter status.StatusHistoryFilter) ([]status.StatusInfo, error) {
  1114  	args := &statusHistoryArgs{
  1115  		db:        st.db(),
  1116  		globalKey: globalCloudContainerKey(name),
  1117  		filter:    filter,
  1118  		clock:     st.clock(),
  1119  	}
  1120  	return statusHistory(args)
  1121  }
  1122  
  1123  func ApplicationOperatorStatus(st *State, appName string) (status.StatusInfo, error) {
  1124  	return getStatus(st.db(), applicationGlobalOperatorKey(appName), "operator")
  1125  }
  1126  
  1127  func NewInstanceCharmProfileDataCompatibilityWatcher(backend ModelBackendShim, memberId string) StringsWatcher {
  1128  	return watchInstanceCharmProfileCompatibilityData(backend, memberId)
  1129  }
  1130  
  1131  func UnitBranch(m *Model, unitName string) (*Generation, error) {
  1132  	return m.unitBranch(unitName)
  1133  }
  1134  
  1135  func ApplicationBranches(m *Model, appName string) ([]*Generation, error) {
  1136  	return m.applicationBranches(appName)
  1137  }
  1138  
  1139  func MachinePortOps(st *State, m description.Machine) ([]txn.Op, error) {
  1140  	resolver := &importer{st: st}
  1141  	return []txn.Op{resolver.machinePortsOp(m)}, nil
  1142  }
  1143  
  1144  func ApplicationPortOps(st *State, a description.Application) ([]txn.Op, error) {
  1145  	resolver := &importer{st: st}
  1146  	return []txn.Op{resolver.applicationPortsOp(a)}, nil
  1147  }
  1148  
  1149  func GetSecretNextRotateTime(c *gc.C, st *State, id string) time.Time {
  1150  	secretRotateCollection, closer := st.db().GetCollection(secretRotateC)
  1151  	defer closer()
  1152  
  1153  	var doc secretRotationDoc
  1154  	err := secretRotateCollection.FindId(id).One(&doc)
  1155  	c.Assert(err, jc.ErrorIsNil)
  1156  	return doc.NextRotateTime.UTC()
  1157  }
  1158  
  1159  func GetSecretBackendNextRotateInfo(c *gc.C, st *State, id string) (string, time.Time) {
  1160  	secretBackendRotateCollection, closer := st.db().GetCollection(secretBackendsRotateC)
  1161  	defer closer()
  1162  
  1163  	var doc secretBackendRotationDoc
  1164  	err := secretBackendRotateCollection.FindId(id).One(&doc)
  1165  	c.Assert(err, jc.ErrorIsNil)
  1166  	return doc.Name, doc.NextRotateTime.UTC()
  1167  }
  1168  
  1169  // ModelBackendShim is required to live here in the export_test.go file because
  1170  // there is issues placing this in the test files themselves. The strangeness
  1171  // exhibits itself from the fact that `clock() clock.Clock` doesn't type
  1172  // check correctly and the go compiler thinks it should be
  1173  // `state.clock() clock.Clock`, which makes no sense.
  1174  type ModelBackendShim struct {
  1175  	Clock    clock.Clock
  1176  	Database Database
  1177  	Watcher  watcher.BaseWatcher
  1178  }
  1179  
  1180  func (s ModelBackendShim) docID(id string) string {
  1181  	return ""
  1182  }
  1183  
  1184  func (s ModelBackendShim) localID(id string) string {
  1185  	return ""
  1186  }
  1187  
  1188  func (s ModelBackendShim) strictLocalID(id string) (string, error) {
  1189  	return "", nil
  1190  }
  1191  
  1192  func (s ModelBackendShim) nowToTheSecond() time.Time {
  1193  	return s.Clock.Now().Round(time.Second).UTC()
  1194  }
  1195  
  1196  func (s ModelBackendShim) clock() clock.Clock {
  1197  	return s.Clock
  1198  }
  1199  
  1200  func (s ModelBackendShim) db() Database {
  1201  	return s.Database
  1202  }
  1203  
  1204  func (s ModelBackendShim) ModelUUID() string {
  1205  	return ""
  1206  }
  1207  
  1208  func (s ModelBackendShim) modelName() (string, error) {
  1209  	return "", nil
  1210  }
  1211  
  1212  func (s ModelBackendShim) IsController() bool {
  1213  	return false
  1214  }
  1215  
  1216  func (s ModelBackendShim) txnLogWatcher() watcher.BaseWatcher {
  1217  	return s.Watcher
  1218  }
  1219  
  1220  // SetClockForTesting is an exported function to allow tests
  1221  // to set the internal clock for the State instance. It is named such
  1222  // that it should be obvious if it is ever called from a non-test package.
  1223  // TODO (thumper): This is a terrible method and we should remove it.
  1224  // NOTE: this should almost never be needed.
  1225  func (st *State) SetClockForTesting(clock clock.Clock) error {
  1226  	// Need to restart the lease workers so they get the new clock.
  1227  	// Stop them first so they don't try to use it when we're setting it.
  1228  	hub := st.workers.hub
  1229  	st.workers.Kill()
  1230  	err := st.workers.Wait()
  1231  	if err != nil {
  1232  		return errors.Trace(err)
  1233  	}
  1234  	st.stateClock = clock
  1235  	if db, ok := st.database.(*database); ok {
  1236  		db.clock = clock
  1237  	}
  1238  	err = st.startWorkers(hub)
  1239  	if err != nil {
  1240  		return errors.Trace(err)
  1241  	}
  1242  	return nil
  1243  }
  1244  
  1245  var (
  1246  	CleanupForceDestroyedUnit = cleanupForceDestroyedUnit
  1247  	CleanupForceRemoveUnit    = cleanupForceRemoveUnit
  1248  	CleanupForceApplication   = cleanupForceApplication
  1249  )
  1250  
  1251  func (st *State) ScheduleForceCleanup(kind cleanupKind, name string, maxWait time.Duration) {
  1252  	st.scheduleForceCleanup(kind, name, maxWait)
  1253  }
  1254  
  1255  func GetCollectionCappedInfo(coll *mgo.Collection) (bool, int, error) {
  1256  	return getCollectionCappedInfo(coll)
  1257  }
  1258  
  1259  func (m *Model) AllActionIDsHasActionNotifications() ([]string, error) {
  1260  	actionNotifications, closer := m.st.db().GetCollection(actionNotificationsC)
  1261  	defer closer()
  1262  
  1263  	docs := []actionNotificationDoc{}
  1264  	err := actionNotifications.Find(nil).All(&docs)
  1265  	if err != nil {
  1266  		return nil, errors.Annotatef(err, "cannot get all actions")
  1267  	}
  1268  	actionIDs := make([]string, len(docs))
  1269  	for i, doc := range docs {
  1270  		actionIDs[i] = doc.ActionID
  1271  	}
  1272  	return actionIDs, nil
  1273  }