github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/state/application.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  	stderrors "errors"
     8  	"fmt"
     9  	"sort"
    10  	"strconv"
    11  	"strings"
    12  
    13  	"github.com/juju/errors"
    14  	jujutxn "github.com/juju/txn"
    15  	"github.com/juju/utils/series"
    16  	"gopkg.in/juju/charm.v6-unstable"
    17  	csparams "gopkg.in/juju/charmrepo.v2-unstable/csclient/params"
    18  	"gopkg.in/juju/names.v2"
    19  	"gopkg.in/mgo.v2"
    20  	"gopkg.in/mgo.v2/bson"
    21  	"gopkg.in/mgo.v2/txn"
    22  
    23  	"github.com/juju/juju/constraints"
    24  	"github.com/juju/juju/core/leadership"
    25  	"github.com/juju/juju/status"
    26  )
    27  
    28  // Application represents the state of an application.
    29  type Application struct {
    30  	st  *State
    31  	doc applicationDoc
    32  }
    33  
    34  // serviceDoc represents the internal state of an application in MongoDB.
    35  // Note the correspondence with ApplicationInfo in apiserver.
    36  type applicationDoc struct {
    37  	DocID                string     `bson:"_id"`
    38  	Name                 string     `bson:"name"`
    39  	ModelUUID            string     `bson:"model-uuid"`
    40  	Series               string     `bson:"series"`
    41  	Subordinate          bool       `bson:"subordinate"`
    42  	CharmURL             *charm.URL `bson:"charmurl"`
    43  	Channel              string     `bson:"cs-channel"`
    44  	CharmModifiedVersion int        `bson:"charmmodifiedversion"`
    45  	ForceCharm           bool       `bson:"forcecharm"`
    46  	Life                 Life       `bson:"life"`
    47  	UnitCount            int        `bson:"unitcount"`
    48  	RelationCount        int        `bson:"relationcount"`
    49  	Exposed              bool       `bson:"exposed"`
    50  	MinUnits             int        `bson:"minunits"`
    51  	TxnRevno             int64      `bson:"txn-revno"`
    52  	MetricCredentials    []byte     `bson:"metric-credentials"`
    53  }
    54  
    55  func newApplication(st *State, doc *applicationDoc) *Application {
    56  	svc := &Application{
    57  		st:  st,
    58  		doc: *doc,
    59  	}
    60  	return svc
    61  }
    62  
    63  // Name returns the application name.
    64  func (a *Application) Name() string {
    65  	return a.doc.Name
    66  }
    67  
    68  // Tag returns a name identifying the service.
    69  // The returned name will be different from other Tag values returned by any
    70  // other entities from the same state.
    71  func (a *Application) Tag() names.Tag {
    72  	return a.ApplicationTag()
    73  }
    74  
    75  // ApplicationTag returns the more specific ApplicationTag rather than the generic
    76  // Tag.
    77  func (a *Application) ApplicationTag() names.ApplicationTag {
    78  	return names.NewApplicationTag(a.Name())
    79  }
    80  
    81  // applicationGlobalKey returns the global database key for the application
    82  // with the given name.
    83  func applicationGlobalKey(svcName string) string {
    84  	return "a#" + svcName
    85  }
    86  
    87  // globalKey returns the global database key for the application.
    88  func (a *Application) globalKey() string {
    89  	return applicationGlobalKey(a.doc.Name)
    90  }
    91  
    92  func applicationSettingsKey(appName string, curl *charm.URL) string {
    93  	return fmt.Sprintf("a#%s#%s", appName, curl)
    94  }
    95  
    96  // settingsKey returns the charm-version-specific settings collection
    97  // key for the application.
    98  func (a *Application) settingsKey() string {
    99  	return applicationSettingsKey(a.doc.Name, a.doc.CharmURL)
   100  }
   101  
   102  func applicationStorageConstraintsKey(appName string, curl *charm.URL) string {
   103  	return fmt.Sprintf("asc#%s#%s", appName, curl)
   104  }
   105  
   106  // storageConstraintsKey returns the charm-version-specific storage
   107  // constraints collection key for the application.
   108  func (a *Application) storageConstraintsKey() string {
   109  	return applicationStorageConstraintsKey(a.doc.Name, a.doc.CharmURL)
   110  }
   111  
   112  // Series returns the specified series for this charm.
   113  func (a *Application) Series() string {
   114  	return a.doc.Series
   115  }
   116  
   117  // Life returns whether the application is Alive, Dying or Dead.
   118  func (a *Application) Life() Life {
   119  	return a.doc.Life
   120  }
   121  
   122  var errRefresh = stderrors.New("state seems inconsistent, refresh and try again")
   123  
   124  // Destroy ensures that the application and all its relations will be removed at
   125  // some point; if the application has no units, and no relation involving the
   126  // application has any units in scope, they are all removed immediately.
   127  func (a *Application) Destroy() (err error) {
   128  	defer errors.DeferredAnnotatef(&err, "cannot destroy application %q", a)
   129  	defer func() {
   130  		if err == nil {
   131  			// This is a white lie; the document might actually be removed.
   132  			a.doc.Life = Dying
   133  		}
   134  	}()
   135  	svc := &Application{st: a.st, doc: a.doc}
   136  	buildTxn := func(attempt int) ([]txn.Op, error) {
   137  		if attempt > 0 {
   138  			if err := svc.Refresh(); errors.IsNotFound(err) {
   139  				return nil, jujutxn.ErrNoOperations
   140  			} else if err != nil {
   141  				return nil, err
   142  			}
   143  		}
   144  		switch ops, err := svc.destroyOps(); err {
   145  		case errRefresh:
   146  		case errAlreadyDying:
   147  			return nil, jujutxn.ErrNoOperations
   148  		case nil:
   149  			return ops, nil
   150  		default:
   151  			return nil, err
   152  		}
   153  		return nil, jujutxn.ErrTransientFailure
   154  	}
   155  	return a.st.run(buildTxn)
   156  }
   157  
   158  // destroyOps returns the operations required to destroy the service. If it
   159  // returns errRefresh, the application should be refreshed and the destruction
   160  // operations recalculated.
   161  func (a *Application) destroyOps() ([]txn.Op, error) {
   162  	if a.doc.Life == Dying {
   163  		return nil, errAlreadyDying
   164  	}
   165  	rels, err := a.Relations()
   166  	if err != nil {
   167  		return nil, err
   168  	}
   169  	if len(rels) != a.doc.RelationCount {
   170  		// This is just an early bail out. The relations obtained may still
   171  		// be wrong, but that situation will be caught by a combination of
   172  		// asserts on relationcount and on each known relation, below.
   173  		return nil, errRefresh
   174  	}
   175  	ops := []txn.Op{minUnitsRemoveOp(a.st, a.doc.Name)}
   176  	removeCount := 0
   177  	for _, rel := range rels {
   178  		relOps, isRemove, err := rel.destroyOps(a.doc.Name)
   179  		if err == errAlreadyDying {
   180  			relOps = []txn.Op{{
   181  				C:      relationsC,
   182  				Id:     rel.doc.DocID,
   183  				Assert: bson.D{{"life", Dying}},
   184  			}}
   185  		} else if err != nil {
   186  			return nil, err
   187  		}
   188  		if isRemove {
   189  			removeCount++
   190  		}
   191  		ops = append(ops, relOps...)
   192  	}
   193  	// TODO(ericsnow) Use a generic registry instead.
   194  	resOps, err := removeResourcesOps(a.st, a.doc.Name)
   195  	if err != nil {
   196  		return nil, errors.Trace(err)
   197  	}
   198  	ops = append(ops, resOps...)
   199  	// If the application has no units, and all its known relations will be
   200  	// removed, the application can also be removed.
   201  	if a.doc.UnitCount == 0 && a.doc.RelationCount == removeCount {
   202  		hasLastRefs := bson.D{{"life", Alive}, {"unitcount", 0}, {"relationcount", removeCount}}
   203  		removeOps, err := a.removeOps(hasLastRefs)
   204  		if err != nil {
   205  			return nil, errors.Trace(err)
   206  		}
   207  		return append(ops, removeOps...), nil
   208  	}
   209  	// In all other cases, application removal will be handled as a consequence
   210  	// of the removal of the last unit or relation referencing it. If any
   211  	// relations have been removed, they'll be caught by the operations
   212  	// collected above; but if any has been added, we need to abort and add
   213  	// a destroy op for that relation too. In combination, it's enough to
   214  	// check for count equality: an add/remove will not touch the count, but
   215  	// will be caught by virtue of being a remove.
   216  	notLastRefs := bson.D{
   217  		{"life", Alive},
   218  		{"relationcount", a.doc.RelationCount},
   219  	}
   220  	// With respect to unit count, a changing value doesn't matter, so long
   221  	// as the count's equality with zero does not change, because all we care
   222  	// about is that *some* unit is, or is not, keeping the application from
   223  	// being removed: the difference between 1 unit and 1000 is irrelevant.
   224  	if a.doc.UnitCount > 0 {
   225  		ops = append(ops, newCleanupOp(cleanupUnitsForDyingService, a.doc.Name))
   226  		notLastRefs = append(notLastRefs, bson.D{{"unitcount", bson.D{{"$gt", 0}}}}...)
   227  	} else {
   228  		notLastRefs = append(notLastRefs, bson.D{{"unitcount", 0}}...)
   229  	}
   230  	update := bson.D{{"$set", bson.D{{"life", Dying}}}}
   231  	if removeCount != 0 {
   232  		decref := bson.D{{"$inc", bson.D{{"relationcount", -removeCount}}}}
   233  		update = append(update, decref...)
   234  	}
   235  	return append(ops, txn.Op{
   236  		C:      applicationsC,
   237  		Id:     a.doc.DocID,
   238  		Assert: notLastRefs,
   239  		Update: update,
   240  	}), nil
   241  }
   242  
   243  func removeResourcesOps(st *State, serviceID string) ([]txn.Op, error) {
   244  	persist, err := st.ResourcesPersistence()
   245  	if errors.IsNotSupported(err) {
   246  		// Nothing to see here, move along.
   247  		return nil, nil
   248  	}
   249  	if err != nil {
   250  		return nil, errors.Trace(err)
   251  	}
   252  	ops, err := persist.NewRemoveResourcesOps(serviceID)
   253  	if err != nil {
   254  		return nil, errors.Trace(err)
   255  	}
   256  	return ops, nil
   257  }
   258  
   259  // removeOps returns the operations required to remove the service. Supplied
   260  // asserts will be included in the operation on the application document.
   261  func (a *Application) removeOps(asserts bson.D) ([]txn.Op, error) {
   262  	ops := []txn.Op{
   263  		{
   264  			C:      applicationsC,
   265  			Id:     a.doc.DocID,
   266  			Assert: asserts,
   267  			Remove: true,
   268  		}, {
   269  			C:      settingsC,
   270  			Id:     a.settingsKey(),
   271  			Remove: true,
   272  		},
   273  	}
   274  	// Note that appCharmDecRefOps might not catch the final decref
   275  	// when run in a transaction that decrefs more than once. In
   276  	// this case, luckily, we can be sure that we unconditionally
   277  	// need finalAppCharmRemoveOps; and we trust that it's written
   278  	// such that it's safe to run multiple times.
   279  	name := a.doc.Name
   280  	curl := a.doc.CharmURL
   281  	charmOps, err := appCharmDecRefOps(a.st, name, curl)
   282  	if err != nil {
   283  		return nil, errors.Trace(err)
   284  	}
   285  	ops = append(ops, charmOps...)
   286  	ops = append(ops, finalAppCharmRemoveOps(name, curl)...)
   287  
   288  	globalKey := a.globalKey()
   289  	ops = append(ops,
   290  		removeEndpointBindingsOp(globalKey),
   291  		removeConstraintsOp(a.st, globalKey),
   292  		annotationRemoveOp(a.st, globalKey),
   293  		removeLeadershipSettingsOp(name),
   294  		removeStatusOp(a.st, globalKey),
   295  		removeModelServiceRefOp(a.st, name),
   296  	)
   297  	return ops, nil
   298  }
   299  
   300  // IsExposed returns whether this application is exposed. The explicitly open
   301  // ports (with open-port) for exposed services may be accessed from machines
   302  // outside of the local deployment network. See SetExposed and ClearExposed.
   303  func (a *Application) IsExposed() bool {
   304  	return a.doc.Exposed
   305  }
   306  
   307  // SetExposed marks the application as exposed.
   308  // See ClearExposed and IsExposed.
   309  func (a *Application) SetExposed() error {
   310  	return a.setExposed(true)
   311  }
   312  
   313  // ClearExposed removes the exposed flag from the service.
   314  // See SetExposed and IsExposed.
   315  func (a *Application) ClearExposed() error {
   316  	return a.setExposed(false)
   317  }
   318  
   319  func (a *Application) setExposed(exposed bool) (err error) {
   320  	ops := []txn.Op{{
   321  		C:      applicationsC,
   322  		Id:     a.doc.DocID,
   323  		Assert: isAliveDoc,
   324  		Update: bson.D{{"$set", bson.D{{"exposed", exposed}}}},
   325  	}}
   326  	if err := a.st.runTransaction(ops); err != nil {
   327  		return errors.Errorf("cannot set exposed flag for application %q to %v: %v", a, exposed, onAbort(err, errNotAlive))
   328  	}
   329  	a.doc.Exposed = exposed
   330  	return nil
   331  }
   332  
   333  // Charm returns the service's charm and whether units should upgrade to that
   334  // charm even if they are in an error state.
   335  func (a *Application) Charm() (ch *Charm, force bool, err error) {
   336  	// We don't worry about the channel since we aren't interacting
   337  	// with the charm store here.
   338  	ch, err = a.st.Charm(a.doc.CharmURL)
   339  	if err != nil {
   340  		return nil, false, err
   341  	}
   342  	return ch, a.doc.ForceCharm, nil
   343  }
   344  
   345  // IsPrincipal returns whether units of the application can
   346  // have subordinate units.
   347  func (a *Application) IsPrincipal() bool {
   348  	return !a.doc.Subordinate
   349  }
   350  
   351  // CharmModifiedVersion increases whenever the service's charm is changed in any
   352  // way.
   353  func (a *Application) CharmModifiedVersion() int {
   354  	return a.doc.CharmModifiedVersion
   355  }
   356  
   357  // CharmURL returns the service's charm URL, and whether units should upgrade
   358  // to the charm with that URL even if they are in an error state.
   359  func (a *Application) CharmURL() (curl *charm.URL, force bool) {
   360  	return a.doc.CharmURL, a.doc.ForceCharm
   361  }
   362  
   363  // Channel identifies the charm store channel from which the service's
   364  // charm was deployed. It is only needed when interacting with the charm
   365  // store.
   366  func (a *Application) Channel() csparams.Channel {
   367  	return csparams.Channel(a.doc.Channel)
   368  }
   369  
   370  // Endpoints returns the service's currently available relation endpoints.
   371  func (a *Application) Endpoints() (eps []Endpoint, err error) {
   372  	ch, _, err := a.Charm()
   373  	if err != nil {
   374  		return nil, err
   375  	}
   376  	collect := func(role charm.RelationRole, rels map[string]charm.Relation) {
   377  		for _, rel := range rels {
   378  			eps = append(eps, Endpoint{
   379  				ApplicationName: a.doc.Name,
   380  				Relation:        rel,
   381  			})
   382  		}
   383  	}
   384  	meta := ch.Meta()
   385  	collect(charm.RolePeer, meta.Peers)
   386  	collect(charm.RoleProvider, meta.Provides)
   387  	collect(charm.RoleRequirer, meta.Requires)
   388  	collect(charm.RoleProvider, map[string]charm.Relation{
   389  		"juju-info": {
   390  			Name:      "juju-info",
   391  			Role:      charm.RoleProvider,
   392  			Interface: "juju-info",
   393  			Scope:     charm.ScopeGlobal,
   394  		},
   395  	})
   396  	sort.Sort(epSlice(eps))
   397  	return eps, nil
   398  }
   399  
   400  // Endpoint returns the relation endpoint with the supplied name, if it exists.
   401  func (a *Application) Endpoint(relationName string) (Endpoint, error) {
   402  	eps, err := a.Endpoints()
   403  	if err != nil {
   404  		return Endpoint{}, err
   405  	}
   406  	for _, ep := range eps {
   407  		if ep.Name == relationName {
   408  			return ep, nil
   409  		}
   410  	}
   411  	return Endpoint{}, errors.Errorf("application %q has no %q relation", a, relationName)
   412  }
   413  
   414  // extraPeerRelations returns only the peer relations in newMeta not
   415  // present in the service's current charm meta data.
   416  func (a *Application) extraPeerRelations(newMeta *charm.Meta) map[string]charm.Relation {
   417  	if newMeta == nil {
   418  		// This should never happen, since we're checking the charm in SetCharm already.
   419  		panic("newMeta is nil")
   420  	}
   421  	ch, _, err := a.Charm()
   422  	if err != nil {
   423  		return nil
   424  	}
   425  	newPeers := newMeta.Peers
   426  	oldPeers := ch.Meta().Peers
   427  	extraPeers := make(map[string]charm.Relation)
   428  	for relName, rel := range newPeers {
   429  		if _, ok := oldPeers[relName]; !ok {
   430  			extraPeers[relName] = rel
   431  		}
   432  	}
   433  	return extraPeers
   434  }
   435  
   436  func (a *Application) checkRelationsOps(ch *Charm, relations []*Relation) ([]txn.Op, error) {
   437  	asserts := make([]txn.Op, 0, len(relations))
   438  	// All relations must still exist and their endpoints are implemented by the charm.
   439  	for _, rel := range relations {
   440  		if ep, err := rel.Endpoint(a.doc.Name); err != nil {
   441  			return nil, err
   442  		} else if !ep.ImplementedBy(ch) {
   443  			return nil, errors.Errorf("would break relation %q", rel)
   444  		}
   445  		asserts = append(asserts, txn.Op{
   446  			C:      relationsC,
   447  			Id:     rel.doc.DocID,
   448  			Assert: txn.DocExists,
   449  		})
   450  	}
   451  	return asserts, nil
   452  }
   453  
   454  func (a *Application) checkStorageUpgrade(newMeta, oldMeta *charm.Meta, units []*Unit) (_ []txn.Op, err error) {
   455  	// Make sure no storage instances are added or removed.
   456  	var ops []txn.Op
   457  	for name, oldStorageMeta := range oldMeta.Storage {
   458  		if _, ok := newMeta.Storage[name]; ok {
   459  			continue
   460  		}
   461  		if oldStorageMeta.CountMin > 0 {
   462  			return nil, errors.Errorf("required storage %q removed", name)
   463  		}
   464  		// Optional storage has been removed. So long as there
   465  		// are no instances of the store, it can safely be
   466  		// removed.
   467  		if oldStorageMeta.Shared {
   468  			op, n, err := a.st.countEntityStorageInstances(a.Tag(), name)
   469  			if err != nil {
   470  				return nil, errors.Trace(err)
   471  			}
   472  			if n > 0 {
   473  				return nil, errors.Errorf("in-use storage %q removed", name)
   474  			}
   475  			ops = append(ops, op)
   476  		} else {
   477  			for _, u := range units {
   478  				op, n, err := a.st.countEntityStorageInstances(u.Tag(), name)
   479  				if err != nil {
   480  					return nil, errors.Trace(err)
   481  				}
   482  				if n > 0 {
   483  					return nil, errors.Errorf("in-use storage %q removed", name)
   484  				}
   485  				ops = append(ops, op)
   486  			}
   487  		}
   488  	}
   489  	less := func(a, b int) bool {
   490  		return a != -1 && (b == -1 || a < b)
   491  	}
   492  	for name, newStorageMeta := range newMeta.Storage {
   493  		oldStorageMeta, ok := oldMeta.Storage[name]
   494  		if !ok {
   495  			continue
   496  		}
   497  		if newStorageMeta.Type != oldStorageMeta.Type {
   498  			return nil, errors.Errorf(
   499  				"existing storage %q type changed from %q to %q",
   500  				name, oldStorageMeta.Type, newStorageMeta.Type,
   501  			)
   502  		}
   503  		if newStorageMeta.Shared != oldStorageMeta.Shared {
   504  			return nil, errors.Errorf(
   505  				"existing storage %q shared changed from %v to %v",
   506  				name, oldStorageMeta.Shared, newStorageMeta.Shared,
   507  			)
   508  		}
   509  		if newStorageMeta.ReadOnly != oldStorageMeta.ReadOnly {
   510  			return nil, errors.Errorf(
   511  				"existing storage %q read-only changed from %v to %v",
   512  				name, oldStorageMeta.ReadOnly, newStorageMeta.ReadOnly,
   513  			)
   514  		}
   515  		if newStorageMeta.Location != oldStorageMeta.Location {
   516  			return nil, errors.Errorf(
   517  				"existing storage %q location changed from %q to %q",
   518  				name, oldStorageMeta.Location, newStorageMeta.Location,
   519  			)
   520  		}
   521  		if less(newStorageMeta.CountMax, oldStorageMeta.CountMax) {
   522  			var oldCountMax interface{} = oldStorageMeta.CountMax
   523  			if oldStorageMeta.CountMax == -1 {
   524  				oldCountMax = "<unbounded>"
   525  			}
   526  			return nil, errors.Errorf(
   527  				"existing storage %q range contracted: max decreased from %v to %d",
   528  				name, oldCountMax, newStorageMeta.CountMax,
   529  			)
   530  		}
   531  		if oldStorageMeta.Location != "" && oldStorageMeta.CountMax == 1 && newStorageMeta.CountMax != 1 {
   532  			// If a location is specified, the store may not go
   533  			// from being a singleton to multiple, since then the
   534  			// location has a different meaning.
   535  			return nil, errors.Errorf(
   536  				"existing storage %q with location changed from single to multiple",
   537  				name,
   538  			)
   539  		}
   540  	}
   541  	return ops, nil
   542  }
   543  
   544  // changeCharmOps returns the operations necessary to set a service's
   545  // charm URL to a new value.
   546  func (a *Application) changeCharmOps(
   547  	ch *Charm,
   548  	channel string,
   549  	updatedSettings charm.Settings,
   550  	forceUnits bool,
   551  	resourceIDs map[string]string,
   552  	updatedStorageConstraints map[string]StorageConstraints,
   553  ) ([]txn.Op, error) {
   554  	// Build the new application config from what can be used of the old one.
   555  	var newSettings charm.Settings
   556  	oldSettings, err := readSettings(a.st, settingsC, a.settingsKey())
   557  	if err == nil {
   558  		// Filter the old settings through to get the new settings.
   559  		newSettings = ch.Config().FilterSettings(oldSettings.Map())
   560  		for k, v := range updatedSettings {
   561  			newSettings[k] = v
   562  		}
   563  	} else if errors.IsNotFound(err) {
   564  		// No old settings, start with the updated settings.
   565  		newSettings = updatedSettings
   566  	} else {
   567  		return nil, errors.Trace(err)
   568  	}
   569  
   570  	// Create or replace application settings.
   571  	var settingsOp txn.Op
   572  	newSettingsKey := applicationSettingsKey(a.doc.Name, ch.URL())
   573  	if _, err := readSettings(a.st, settingsC, newSettingsKey); errors.IsNotFound(err) {
   574  		// No settings for this key yet, create it.
   575  		settingsOp = createSettingsOp(settingsC, newSettingsKey, newSettings)
   576  	} else if err != nil {
   577  		return nil, errors.Trace(err)
   578  	} else {
   579  		// Settings exist, just replace them with the new ones.
   580  		settingsOp, _, err = replaceSettingsOp(a.st, settingsC, newSettingsKey, newSettings)
   581  		if err != nil {
   582  			return nil, errors.Trace(err)
   583  		}
   584  	}
   585  
   586  	// Make sure no units are added or removed while the upgrade
   587  	// transaction is being executed. This allows us to make
   588  	// changes to units during the upgrade, e.g. add storage
   589  	// to existing units, or remove optional storage so long as
   590  	// it is unreferenced.
   591  	units, err := a.AllUnits()
   592  	if err != nil {
   593  		return nil, errors.Trace(err)
   594  	}
   595  	unitOps := make([]txn.Op, len(units))
   596  	for i, u := range units {
   597  		unitOps[i] = txn.Op{
   598  			C:      unitsC,
   599  			Id:     u.doc.DocID,
   600  			Assert: txn.DocExists,
   601  		}
   602  	}
   603  	unitOps = append(unitOps, txn.Op{
   604  		C:      applicationsC,
   605  		Id:     a.doc.DocID,
   606  		Assert: bson.D{{"unitcount", len(units)}},
   607  	})
   608  
   609  	// Check storage to ensure no referenced storage is removed, or changed
   610  	// in an incompatible way. We do this before computing the new storage
   611  	// constraints, as incompatible charm changes will otherwise yield
   612  	// confusing error messages that would suggest the user has supplied
   613  	// invalid constraints.
   614  	oldCharm, _, err := a.Charm()
   615  	if err != nil {
   616  		return nil, errors.Trace(err)
   617  	}
   618  	oldMeta := oldCharm.Meta()
   619  	checkStorageOps, err := a.checkStorageUpgrade(ch.Meta(), oldMeta, units)
   620  	if err != nil {
   621  		return nil, errors.Trace(err)
   622  	}
   623  
   624  	// Create or replace storage constraints. We take the existing storage
   625  	// constraints, remove any keys that are no longer referenced by the
   626  	// charm, and update the constraints that the user has specified.
   627  	var storageConstraintsOp txn.Op
   628  	oldStorageConstraints, err := a.StorageConstraints()
   629  	if err != nil {
   630  		return nil, errors.Trace(err)
   631  	}
   632  	newStorageConstraints := oldStorageConstraints
   633  	for name, cons := range updatedStorageConstraints {
   634  		newStorageConstraints[name] = cons
   635  	}
   636  	for name := range newStorageConstraints {
   637  		if _, ok := ch.Meta().Storage[name]; !ok {
   638  			delete(newStorageConstraints, name)
   639  		}
   640  	}
   641  	if err := addDefaultStorageConstraints(a.st, newStorageConstraints, ch.Meta()); err != nil {
   642  		return nil, errors.Annotate(err, "adding default storage constraints")
   643  	}
   644  	if err := validateStorageConstraints(a.st, newStorageConstraints, ch.Meta()); err != nil {
   645  		return nil, errors.Annotate(err, "validating storage constraints")
   646  	}
   647  	newStorageConstraintsKey := applicationStorageConstraintsKey(a.doc.Name, ch.URL())
   648  	if _, err := readStorageConstraints(a.st, newStorageConstraintsKey); errors.IsNotFound(err) {
   649  		storageConstraintsOp = createStorageConstraintsOp(
   650  			newStorageConstraintsKey, newStorageConstraints,
   651  		)
   652  	} else if err != nil {
   653  		return nil, errors.Trace(err)
   654  	} else {
   655  		storageConstraintsOp = replaceStorageConstraintsOp(
   656  			newStorageConstraintsKey, newStorageConstraints,
   657  		)
   658  	}
   659  
   660  	// Upgrade charm storage.
   661  	upgradeStorageOps, err := a.upgradeStorageOps(ch.Meta(), oldMeta, units, newStorageConstraints)
   662  	if err != nil {
   663  		return nil, errors.Trace(err)
   664  	}
   665  
   666  	// Add or create a reference to the new charm, settings,
   667  	// and storage constraints docs.
   668  	incOps, err := appCharmIncRefOps(a.st, a.doc.Name, ch.URL(), true)
   669  	if err != nil {
   670  		return nil, errors.Trace(err)
   671  	}
   672  	var decOps []txn.Op
   673  	// Drop the references to the old settings, storage constraints,
   674  	// and charm docs (if the refs actually exist yet).
   675  	if oldSettings != nil {
   676  		decOps, err = appCharmDecRefOps(a.st, a.doc.Name, a.doc.CharmURL) // current charm
   677  		if err != nil {
   678  			return nil, errors.Trace(err)
   679  		}
   680  	}
   681  
   682  	// Build the transaction.
   683  	var ops []txn.Op
   684  	if oldSettings != nil {
   685  		// Old settings shouldn't change (when they exist).
   686  		ops = append(ops, oldSettings.assertUnchangedOp())
   687  	}
   688  	ops = append(ops, unitOps...)
   689  	ops = append(ops, incOps...)
   690  	ops = append(ops, []txn.Op{
   691  		// Create or replace new settings.
   692  		settingsOp,
   693  		// Create storage constraints.
   694  		storageConstraintsOp,
   695  		// Update the charm URL and force flag (if relevant).
   696  		{
   697  			C:  applicationsC,
   698  			Id: a.doc.DocID,
   699  			Update: bson.D{{"$set", bson.D{
   700  				{"charmurl", ch.URL()},
   701  				{"cs-channel", channel},
   702  				{"forcecharm", forceUnits},
   703  			}}},
   704  		},
   705  	}...)
   706  	ops = append(ops, checkStorageOps...)
   707  	ops = append(ops, upgradeStorageOps...)
   708  
   709  	ops = append(ops, incCharmModifiedVersionOps(a.doc.DocID)...)
   710  
   711  	// Add any extra peer relations that need creation.
   712  	newPeers := a.extraPeerRelations(ch.Meta())
   713  	peerOps, err := a.st.addPeerRelationsOps(a.doc.Name, newPeers)
   714  	if err != nil {
   715  		return nil, errors.Trace(err)
   716  	}
   717  
   718  	if len(resourceIDs) > 0 {
   719  		// Collect pending resource resolution operations.
   720  		resOps, err := a.resolveResourceOps(resourceIDs)
   721  		if err != nil {
   722  			return nil, errors.Trace(err)
   723  		}
   724  		ops = append(ops, resOps...)
   725  	}
   726  
   727  	// Get all relations - we need to check them later.
   728  	relations, err := a.Relations()
   729  	if err != nil {
   730  		return nil, errors.Trace(err)
   731  	}
   732  	// Make sure the relation count does not change.
   733  	sameRelCount := bson.D{{"relationcount", len(relations)}}
   734  
   735  	ops = append(ops, peerOps...)
   736  	// Update the relation count as well.
   737  	ops = append(ops, txn.Op{
   738  		C:      applicationsC,
   739  		Id:     a.doc.DocID,
   740  		Assert: append(notDeadDoc, sameRelCount...),
   741  		Update: bson.D{{"$inc", bson.D{{"relationcount", len(newPeers)}}}},
   742  	})
   743  	// Check relations to ensure no active relations are removed.
   744  	relOps, err := a.checkRelationsOps(ch, relations)
   745  	if err != nil {
   746  		return nil, errors.Trace(err)
   747  	}
   748  	ops = append(ops, relOps...)
   749  
   750  	// Update any existing endpoint bindings, using defaults for new endpoints.
   751  	//
   752  	// TODO(dimitern): Once upgrade-charm accepts --bind like deploy, pass the
   753  	// given bindings below, instead of nil.
   754  	endpointBindingsOp, err := updateEndpointBindingsOp(a.st, a.globalKey(), nil, ch.Meta())
   755  	if err == nil {
   756  		ops = append(ops, endpointBindingsOp)
   757  	} else if !errors.IsNotFound(err) && err != jujutxn.ErrNoOperations {
   758  		// If endpoint bindings do not exist this most likely means the service
   759  		// itself no longer exists, which will be caught soon enough anyway.
   760  		// ErrNoOperations on the other hand means there's nothing to update.
   761  		return nil, errors.Trace(err)
   762  	}
   763  
   764  	// And finally, decrement the old charm and settings.
   765  	return append(ops, decOps...), nil
   766  }
   767  
   768  func (a *Application) upgradeStorageOps(
   769  	meta, oldMeta *charm.Meta,
   770  	units []*Unit,
   771  	allStorageCons map[string]StorageConstraints,
   772  ) (_ []txn.Op, err error) {
   773  	// For each store, ensure that every unit has the minimum requirements.
   774  	// If a unit has an existing store, but its minimum count has been
   775  	// increased, we only add the shortfall; we do not necessarily add as
   776  	// many instances as are specified in the storage constraints.
   777  	var ops []txn.Op
   778  	for name, cons := range allStorageCons {
   779  		for _, u := range units {
   780  			countMin := meta.Storage[name].CountMin
   781  			if _, ok := oldMeta.Storage[name]; !ok {
   782  				// The store did not exist previously, so we
   783  				// create the full amount specified in the
   784  				// cosntraints.
   785  				countMin = int(cons.Count)
   786  			}
   787  			unitOps, err := a.st.addUnitStorageOps(
   788  				meta, u, name, cons, countMin,
   789  			)
   790  			if err != nil {
   791  				return nil, errors.Trace(err)
   792  			}
   793  			ops = append(ops, unitOps...)
   794  		}
   795  	}
   796  	return ops, nil
   797  }
   798  
   799  // incCharmModifiedVersionOps returns the operations necessary to increment
   800  // the CharmModifiedVersion field for the given service.
   801  func incCharmModifiedVersionOps(serviceID string) []txn.Op {
   802  	return []txn.Op{{
   803  		C:      applicationsC,
   804  		Id:     serviceID,
   805  		Assert: txn.DocExists,
   806  		Update: bson.D{{"$inc", bson.D{{"charmmodifiedversion", 1}}}},
   807  	}}
   808  }
   809  
   810  func (a *Application) resolveResourceOps(resourceIDs map[string]string) ([]txn.Op, error) {
   811  	// Collect pending resource resolution operations.
   812  	resources, err := a.st.Resources()
   813  	if err != nil {
   814  		return nil, errors.Trace(err)
   815  	}
   816  	return resources.NewResolvePendingResourcesOps(a.doc.Name, resourceIDs)
   817  }
   818  
   819  // SetCharmConfig contains the parameters for Application.SetCharm.
   820  type SetCharmConfig struct {
   821  	// Charm is the new charm to use for the application. New units
   822  	// will be started with this charm, and existing units will be
   823  	// upgraded to use it.
   824  	Charm *Charm
   825  
   826  	// Channel is the charm store channel from which charm was pulled.
   827  	Channel csparams.Channel
   828  
   829  	// ConfigSettings is the charm config settings to apply when upgrading
   830  	// the charm.
   831  	ConfigSettings charm.Settings
   832  
   833  	// ForceUnits forces the upgrade on units in an error state.
   834  	ForceUnits bool
   835  
   836  	// ForceSeries forces the use of the charm even if it is not one of
   837  	// the charm's supported series.
   838  	ForceSeries bool
   839  
   840  	// ResourceIDs is a map of resource names to resource IDs to activate during
   841  	// the upgrade.
   842  	ResourceIDs map[string]string
   843  
   844  	// StorageConstraints contains the constraints to add or update when
   845  	// upgrading the charm.
   846  	//
   847  	// Any existing storage instances for the named stores will be
   848  	// unaffected; the storage constraints will only be used for
   849  	// provisioning new storage instances.
   850  	StorageConstraints map[string]StorageConstraints
   851  }
   852  
   853  // SetCharm changes the charm for the application.
   854  func (a *Application) SetCharm(cfg SetCharmConfig) (err error) {
   855  	defer errors.DeferredAnnotatef(
   856  		&err, "cannot upgrade application %q to charm %q", a, cfg.Charm,
   857  	)
   858  	if cfg.Charm.Meta().Subordinate != a.doc.Subordinate {
   859  		return errors.Errorf("cannot change an application's subordinacy")
   860  	}
   861  	// For old style charms written for only one series, we still retain
   862  	// this check. Newer charms written for multi-series have a URL
   863  	// with series = "".
   864  	if cfg.Charm.URL().Series != "" {
   865  		if cfg.Charm.URL().Series != a.doc.Series {
   866  			return errors.Errorf("cannot change an application's series")
   867  		}
   868  	} else if !cfg.ForceSeries {
   869  		supported := false
   870  		for _, series := range cfg.Charm.Meta().Series {
   871  			if series == a.doc.Series {
   872  				supported = true
   873  				break
   874  			}
   875  		}
   876  		if !supported {
   877  			supportedSeries := "no series"
   878  			if len(cfg.Charm.Meta().Series) > 0 {
   879  				supportedSeries = strings.Join(cfg.Charm.Meta().Series, ", ")
   880  			}
   881  			return errors.Errorf("only these series are supported: %v", supportedSeries)
   882  		}
   883  	} else {
   884  		// Even with forceSeries=true, we do not allow a charm to be used which is for
   885  		// a different OS. This assumes the charm declares it has supported series which
   886  		// we can check for OS compatibility. Otherwise, we just accept the series supplied.
   887  		currentOS, err := series.GetOSFromSeries(a.doc.Series)
   888  		if err != nil {
   889  			// We don't expect an error here but there's not much we can
   890  			// do to recover.
   891  			return err
   892  		}
   893  		supportedOS := false
   894  		supportedSeries := cfg.Charm.Meta().Series
   895  		for _, chSeries := range supportedSeries {
   896  			charmSeriesOS, err := series.GetOSFromSeries(chSeries)
   897  			if err != nil {
   898  				return nil
   899  			}
   900  			if currentOS == charmSeriesOS {
   901  				supportedOS = true
   902  				break
   903  			}
   904  		}
   905  		if !supportedOS && len(supportedSeries) > 0 {
   906  			return errors.Errorf("OS %q not supported by charm", currentOS)
   907  		}
   908  	}
   909  
   910  	updatedSettings, err := cfg.Charm.Config().ValidateSettings(cfg.ConfigSettings)
   911  	if err != nil {
   912  		return errors.Annotate(err, "validating config settings")
   913  	}
   914  
   915  	var newCharmModifiedVersion int
   916  	channel := string(cfg.Channel)
   917  	acopy := &Application{a.st, a.doc}
   918  	buildTxn := func(attempt int) ([]txn.Op, error) {
   919  		a := acopy
   920  		if attempt > 0 {
   921  			if err := a.Refresh(); err != nil {
   922  				return nil, errors.Trace(err)
   923  			}
   924  		}
   925  
   926  		// NOTE: We're explicitly allowing SetCharm to succeed
   927  		// when the application is Dying, because service/charm
   928  		// upgrades should still be allowed to apply to dying
   929  		// services and units, so that bugs in departed/broken
   930  		// hooks can be addressed at runtime.
   931  		if a.Life() == Dead {
   932  			return nil, ErrDead
   933  		}
   934  
   935  		// Record the current value of charmModifiedVersion, so we can
   936  		// set the value on the method receiver's in-memory document
   937  		// structure. We increment the version only when we change the
   938  		// charm URL.
   939  		newCharmModifiedVersion = a.doc.CharmModifiedVersion
   940  
   941  		ops := []txn.Op{{
   942  			C:  applicationsC,
   943  			Id: a.doc.DocID,
   944  			Assert: append(notDeadDoc, bson.DocElem{
   945  				"charmmodifiedversion", a.doc.CharmModifiedVersion,
   946  			}),
   947  		}}
   948  
   949  		if a.doc.CharmURL.String() == cfg.Charm.URL().String() {
   950  			// Charm URL already set; just update the force flag and channel.
   951  			ops = append(ops, txn.Op{
   952  				C:  applicationsC,
   953  				Id: a.doc.DocID,
   954  				Update: bson.D{{"$set", bson.D{
   955  					{"cs-channel", channel},
   956  					{"forcecharm", cfg.ForceUnits},
   957  				}}},
   958  			})
   959  		} else {
   960  			chng, err := a.changeCharmOps(
   961  				cfg.Charm,
   962  				channel,
   963  				updatedSettings,
   964  				cfg.ForceUnits,
   965  				cfg.ResourceIDs,
   966  				cfg.StorageConstraints,
   967  			)
   968  			if err != nil {
   969  				return nil, errors.Trace(err)
   970  			}
   971  			ops = append(ops, chng...)
   972  			newCharmModifiedVersion++
   973  		}
   974  
   975  		return ops, nil
   976  	}
   977  	if err := a.st.run(buildTxn); err != nil {
   978  		return err
   979  	}
   980  	a.doc.CharmURL = cfg.Charm.URL()
   981  	a.doc.Channel = channel
   982  	a.doc.ForceCharm = cfg.ForceUnits
   983  	a.doc.CharmModifiedVersion = newCharmModifiedVersion
   984  	return nil
   985  }
   986  
   987  // String returns the application name.
   988  func (a *Application) String() string {
   989  	return a.doc.Name
   990  }
   991  
   992  // Refresh refreshes the contents of the Service from the underlying
   993  // state. It returns an error that satisfies errors.IsNotFound if the
   994  // application has been removed.
   995  func (a *Application) Refresh() error {
   996  	services, closer := a.st.getCollection(applicationsC)
   997  	defer closer()
   998  
   999  	err := services.FindId(a.doc.DocID).One(&a.doc)
  1000  	if err == mgo.ErrNotFound {
  1001  		return errors.NotFoundf("application %q", a)
  1002  	}
  1003  	if err != nil {
  1004  		return errors.Errorf("cannot refresh application %q: %v", a, err)
  1005  	}
  1006  	return nil
  1007  }
  1008  
  1009  // newUnitName returns the next unit name.
  1010  func (a *Application) newUnitName() (string, error) {
  1011  	unitSeq, err := a.st.sequence(a.Tag().String())
  1012  	if err != nil {
  1013  		return "", errors.Trace(err)
  1014  	}
  1015  	name := a.doc.Name + "/" + strconv.Itoa(unitSeq)
  1016  	return name, nil
  1017  }
  1018  
  1019  // addUnitOps returns a unique name for a new unit, and a list of txn operations
  1020  // necessary to create that unit. The principalName param must be non-empty if
  1021  // and only if s is a subordinate service. Only one subordinate of a given
  1022  // application will be assigned to a given principal. The asserts param can be used
  1023  // to include additional assertions for the application document.  This method
  1024  // assumes that the application already exists in the db.
  1025  func (a *Application) addUnitOps(principalName string, asserts bson.D) (string, []txn.Op, error) {
  1026  	var cons constraints.Value
  1027  	if !a.doc.Subordinate {
  1028  		scons, err := a.Constraints()
  1029  		if errors.IsNotFound(err) {
  1030  			return "", nil, errors.NotFoundf("application %q", a.Name())
  1031  		}
  1032  		if err != nil {
  1033  			return "", nil, err
  1034  		}
  1035  		cons, err = a.st.resolveConstraints(scons)
  1036  		if err != nil {
  1037  			return "", nil, err
  1038  		}
  1039  	}
  1040  	storageCons, err := a.StorageConstraints()
  1041  	if err != nil {
  1042  		return "", nil, err
  1043  	}
  1044  	args := applicationAddUnitOpsArgs{
  1045  		cons:          cons,
  1046  		principalName: principalName,
  1047  		storageCons:   storageCons,
  1048  	}
  1049  	names, ops, err := a.addUnitOpsWithCons(args)
  1050  	if err != nil {
  1051  		return names, ops, err
  1052  	}
  1053  	// we verify the application is alive
  1054  	asserts = append(isAliveDoc, asserts...)
  1055  	ops = append(ops, a.incUnitCountOp(asserts))
  1056  	return names, ops, err
  1057  }
  1058  
  1059  type applicationAddUnitOpsArgs struct {
  1060  	principalName string
  1061  	cons          constraints.Value
  1062  	storageCons   map[string]StorageConstraints
  1063  }
  1064  
  1065  // addServiceUnitOps is just like addUnitOps but explicitly takes a
  1066  // constraints value (this is used at application creation time).
  1067  func (a *Application) addServiceUnitOps(args applicationAddUnitOpsArgs) (string, []txn.Op, error) {
  1068  	names, ops, err := a.addUnitOpsWithCons(args)
  1069  	if err == nil {
  1070  		ops = append(ops, a.incUnitCountOp(nil))
  1071  	}
  1072  	return names, ops, err
  1073  }
  1074  
  1075  // addUnitOpsWithCons is a helper method for returning addUnitOps.
  1076  func (a *Application) addUnitOpsWithCons(args applicationAddUnitOpsArgs) (string, []txn.Op, error) {
  1077  	if a.doc.Subordinate && args.principalName == "" {
  1078  		return "", nil, errors.New("application is a subordinate")
  1079  	} else if !a.doc.Subordinate && args.principalName != "" {
  1080  		return "", nil, errors.New("application is not a subordinate")
  1081  	}
  1082  	name, err := a.newUnitName()
  1083  	if err != nil {
  1084  		return "", nil, err
  1085  	}
  1086  	unitTag := names.NewUnitTag(name)
  1087  
  1088  	charm, _, err := a.Charm()
  1089  	if err != nil {
  1090  		return "", nil, err
  1091  	}
  1092  
  1093  	// Add storage instances/attachments for the unit. If the
  1094  	// application is subordinate, we'll add the machine storage
  1095  	// if the principal is assigned to a machine. Otherwise, we
  1096  	// will add the subordinate's storage along with the principal's
  1097  	// when the principal is assigned to a machine.
  1098  	var machineAssignable machineAssignable
  1099  	if a.doc.Subordinate {
  1100  		pu, err := a.st.Unit(args.principalName)
  1101  		if err != nil {
  1102  			return "", nil, errors.Trace(err)
  1103  		}
  1104  		machineAssignable = pu
  1105  	}
  1106  	storageOps, numStorageAttachments, err := createStorageOps(
  1107  		a.st,
  1108  		unitTag,
  1109  		charm.Meta(),
  1110  		args.storageCons,
  1111  		a.doc.Series,
  1112  		machineAssignable,
  1113  	)
  1114  	if err != nil {
  1115  		return "", nil, errors.Trace(err)
  1116  	}
  1117  
  1118  	docID := a.st.docID(name)
  1119  	globalKey := unitGlobalKey(name)
  1120  	agentGlobalKey := unitAgentGlobalKey(name)
  1121  	udoc := &unitDoc{
  1122  		DocID:                  docID,
  1123  		Name:                   name,
  1124  		Application:            a.doc.Name,
  1125  		Series:                 a.doc.Series,
  1126  		Life:                   Alive,
  1127  		Principal:              args.principalName,
  1128  		StorageAttachmentCount: numStorageAttachments,
  1129  	}
  1130  	now := a.st.clock.Now()
  1131  	agentStatusDoc := statusDoc{
  1132  		Status:  status.Allocating,
  1133  		Updated: now.UnixNano(),
  1134  	}
  1135  	unitStatusDoc := statusDoc{
  1136  		Status:     status.Waiting,
  1137  		StatusInfo: status.MessageWaitForMachine,
  1138  		Updated:    now.UnixNano(),
  1139  	}
  1140  	workloadVersionDoc := statusDoc{
  1141  		Status:  status.Unknown,
  1142  		Updated: now.UnixNano(),
  1143  	}
  1144  
  1145  	ops, err := addUnitOps(a.st, addUnitOpsArgs{
  1146  		unitDoc:            udoc,
  1147  		agentStatusDoc:     agentStatusDoc,
  1148  		workloadStatusDoc:  unitStatusDoc,
  1149  		workloadVersionDoc: workloadVersionDoc,
  1150  		meterStatusDoc:     &meterStatusDoc{Code: MeterNotSet.String()},
  1151  	})
  1152  	if err != nil {
  1153  		return "", nil, errors.Trace(err)
  1154  	}
  1155  
  1156  	ops = append(ops, storageOps...)
  1157  
  1158  	if a.doc.Subordinate {
  1159  		ops = append(ops, txn.Op{
  1160  			C:  unitsC,
  1161  			Id: a.st.docID(args.principalName),
  1162  			Assert: append(isAliveDoc, bson.DocElem{
  1163  				"subordinates", bson.D{{"$not", bson.RegEx{Pattern: "^" + a.doc.Name + "/"}}},
  1164  			}),
  1165  			Update: bson.D{{"$addToSet", bson.D{{"subordinates", name}}}},
  1166  		})
  1167  	} else {
  1168  		ops = append(ops, createConstraintsOp(a.st, agentGlobalKey, args.cons))
  1169  	}
  1170  
  1171  	// At the last moment we still have the statusDocs in scope, set the initial
  1172  	// history entries. This is risky, and may lead to extra entries, but that's
  1173  	// an intrinsic problem with mixing txn and non-txn ops -- we can't sync
  1174  	// them cleanly.
  1175  	probablyUpdateStatusHistory(a.st, globalKey, unitStatusDoc)
  1176  	probablyUpdateStatusHistory(a.st, agentGlobalKey, agentStatusDoc)
  1177  	probablyUpdateStatusHistory(a.st, globalWorkloadVersionKey(name), workloadVersionDoc)
  1178  	return name, ops, nil
  1179  }
  1180  
  1181  // incUnitCountOp returns the operation to increment the service's unit count.
  1182  func (a *Application) incUnitCountOp(asserts bson.D) txn.Op {
  1183  	op := txn.Op{
  1184  		C:      applicationsC,
  1185  		Id:     a.doc.DocID,
  1186  		Update: bson.D{{"$inc", bson.D{{"unitcount", 1}}}},
  1187  	}
  1188  	if len(asserts) > 0 {
  1189  		op.Assert = asserts
  1190  	}
  1191  	return op
  1192  }
  1193  
  1194  // AddUnit adds a new principal unit to the service.
  1195  func (a *Application) AddUnit() (unit *Unit, err error) {
  1196  	defer errors.DeferredAnnotatef(&err, "cannot add unit to application %q", a)
  1197  	name, ops, err := a.addUnitOps("", nil)
  1198  	if err != nil {
  1199  		return nil, err
  1200  	}
  1201  
  1202  	if err := a.st.runTransaction(ops); err == txn.ErrAborted {
  1203  		if alive, err := isAlive(a.st, applicationsC, a.doc.DocID); err != nil {
  1204  			return nil, err
  1205  		} else if !alive {
  1206  			return nil, errors.New("application is not alive")
  1207  		}
  1208  		return nil, errors.New("inconsistent state")
  1209  	} else if err != nil {
  1210  		return nil, err
  1211  	}
  1212  	return a.st.Unit(name)
  1213  }
  1214  
  1215  // removeUnitOps returns the operations necessary to remove the supplied unit,
  1216  // assuming the supplied asserts apply to the unit document.
  1217  func (a *Application) removeUnitOps(u *Unit, asserts bson.D) ([]txn.Op, error) {
  1218  	ops, err := u.destroyHostOps(a)
  1219  	if err != nil {
  1220  		return nil, err
  1221  	}
  1222  	portsOps, err := removePortsForUnitOps(a.st, u)
  1223  	if err != nil {
  1224  		return nil, err
  1225  	}
  1226  	storageInstanceOps, err := removeStorageInstancesOps(a.st, u.Tag())
  1227  	if err != nil {
  1228  		return nil, err
  1229  	}
  1230  	resOps, err := removeUnitResourcesOps(a.st, u.doc.Application, u.doc.Name)
  1231  	if err != nil {
  1232  		return nil, errors.Trace(err)
  1233  	}
  1234  	ops = append(ops, resOps...)
  1235  
  1236  	observedFieldsMatch := bson.D{
  1237  		{"charmurl", u.doc.CharmURL},
  1238  		{"machineid", u.doc.MachineId},
  1239  	}
  1240  	ops = append(ops,
  1241  		txn.Op{
  1242  			C:      unitsC,
  1243  			Id:     u.doc.DocID,
  1244  			Assert: append(observedFieldsMatch, asserts...),
  1245  			Remove: true,
  1246  		},
  1247  		removeMeterStatusOp(a.st, u.globalMeterStatusKey()),
  1248  		removeStatusOp(a.st, u.globalAgentKey()),
  1249  		removeStatusOp(a.st, u.globalKey()),
  1250  		removeConstraintsOp(a.st, u.globalAgentKey()),
  1251  		annotationRemoveOp(a.st, u.globalKey()),
  1252  		newCleanupOp(cleanupRemovedUnit, u.doc.Name),
  1253  	)
  1254  	ops = append(ops, portsOps...)
  1255  	ops = append(ops, storageInstanceOps...)
  1256  	if u.doc.CharmURL != nil {
  1257  		decOps, err := appCharmDecRefOps(a.st, a.doc.Name, u.doc.CharmURL)
  1258  		if errors.IsNotFound(err) {
  1259  			return nil, errRefresh
  1260  		} else if err != nil {
  1261  			return nil, err
  1262  		}
  1263  		ops = append(ops, decOps...)
  1264  	}
  1265  	if a.doc.Life == Dying && a.doc.RelationCount == 0 && a.doc.UnitCount == 1 {
  1266  		hasLastRef := bson.D{{"life", Dying}, {"relationcount", 0}, {"unitcount", 1}}
  1267  		removeOps, err := a.removeOps(hasLastRef)
  1268  		if err != nil {
  1269  			return nil, errors.Trace(err)
  1270  		}
  1271  		return append(ops, removeOps...), nil
  1272  	}
  1273  	svcOp := txn.Op{
  1274  		C:      applicationsC,
  1275  		Id:     a.doc.DocID,
  1276  		Update: bson.D{{"$inc", bson.D{{"unitcount", -1}}}},
  1277  	}
  1278  	if a.doc.Life == Alive {
  1279  		svcOp.Assert = bson.D{{"life", Alive}, {"unitcount", bson.D{{"$gt", 0}}}}
  1280  	} else {
  1281  		svcOp.Assert = bson.D{
  1282  			{"life", Dying},
  1283  			{"$or", []bson.D{
  1284  				{{"unitcount", bson.D{{"$gt", 1}}}},
  1285  				{{"relationcount", bson.D{{"$gt", 0}}}},
  1286  			}},
  1287  		}
  1288  	}
  1289  	ops = append(ops, svcOp)
  1290  
  1291  	return ops, nil
  1292  }
  1293  
  1294  func removeUnitResourcesOps(st *State, serviceID, unitID string) ([]txn.Op, error) {
  1295  	persist, err := st.ResourcesPersistence()
  1296  	if errors.IsNotSupported(err) {
  1297  		// Nothing to see here, move along.
  1298  		return nil, nil
  1299  	}
  1300  	if err != nil {
  1301  		return nil, errors.Trace(err)
  1302  	}
  1303  	ops, err := persist.NewRemoveUnitResourcesOps(unitID)
  1304  	if err != nil {
  1305  		return nil, errors.Trace(err)
  1306  	}
  1307  	return ops, nil
  1308  }
  1309  
  1310  // AllUnits returns all units of the service.
  1311  func (a *Application) AllUnits() (units []*Unit, err error) {
  1312  	return allUnits(a.st, a.doc.Name)
  1313  }
  1314  
  1315  func allUnits(st *State, application string) (units []*Unit, err error) {
  1316  	unitsCollection, closer := st.getCollection(unitsC)
  1317  	defer closer()
  1318  
  1319  	docs := []unitDoc{}
  1320  	err = unitsCollection.Find(bson.D{{"application", application}}).All(&docs)
  1321  	if err != nil {
  1322  		return nil, errors.Errorf("cannot get all units from application %q: %v", application, err)
  1323  	}
  1324  	for i := range docs {
  1325  		units = append(units, newUnit(st, &docs[i]))
  1326  	}
  1327  	return units, nil
  1328  }
  1329  
  1330  // Relations returns a Relation for every relation the application is in.
  1331  func (a *Application) Relations() (relations []*Relation, err error) {
  1332  	return applicationRelations(a.st, a.doc.Name)
  1333  }
  1334  
  1335  func applicationRelations(st *State, name string) (relations []*Relation, err error) {
  1336  	defer errors.DeferredAnnotatef(&err, "can't get relations for application %q", name)
  1337  	relationsCollection, closer := st.getCollection(relationsC)
  1338  	defer closer()
  1339  
  1340  	docs := []relationDoc{}
  1341  	err = relationsCollection.Find(bson.D{{"endpoints.applicationname", name}}).All(&docs)
  1342  	if err != nil {
  1343  		return nil, err
  1344  	}
  1345  	for _, v := range docs {
  1346  		relations = append(relations, newRelation(st, &v))
  1347  	}
  1348  	return relations, nil
  1349  }
  1350  
  1351  // ConfigSettings returns the raw user configuration for the application's charm.
  1352  // Unset values are omitted.
  1353  func (a *Application) ConfigSettings() (charm.Settings, error) {
  1354  	settings, err := readSettings(a.st, settingsC, a.settingsKey())
  1355  	if err != nil {
  1356  		return nil, err
  1357  	}
  1358  	return settings.Map(), nil
  1359  }
  1360  
  1361  // UpdateConfigSettings changes a service's charm config settings. Values set
  1362  // to nil will be deleted; unknown and invalid values will return an error.
  1363  func (a *Application) UpdateConfigSettings(changes charm.Settings) error {
  1364  	charm, _, err := a.Charm()
  1365  	if err != nil {
  1366  		return err
  1367  	}
  1368  	changes, err = charm.Config().ValidateSettings(changes)
  1369  	if err != nil {
  1370  		return err
  1371  	}
  1372  	// TODO(fwereade) state.Settings is itself really problematic in just
  1373  	// about every use case. This needs to be resolved some time; but at
  1374  	// least the settings docs are keyed by charm url as well as service
  1375  	// name, so the actual impact of a race is non-threatening.
  1376  	node, err := readSettings(a.st, settingsC, a.settingsKey())
  1377  	if err != nil {
  1378  		return err
  1379  	}
  1380  	for name, value := range changes {
  1381  		if value == nil {
  1382  			node.Delete(name)
  1383  		} else {
  1384  			node.Set(name, value)
  1385  		}
  1386  	}
  1387  	_, err = node.Write()
  1388  	return err
  1389  }
  1390  
  1391  // LeaderSettings returns a service's leader settings. If nothing has been set
  1392  // yet, it will return an empty map; this is not an error.
  1393  func (a *Application) LeaderSettings() (map[string]string, error) {
  1394  	// There's no compelling reason to have these methods on Service -- and
  1395  	// thus require an extra db read to access them -- but it stops the State
  1396  	// type getting even more cluttered.
  1397  
  1398  	doc, err := readSettingsDoc(a.st, settingsC, leadershipSettingsKey(a.doc.Name))
  1399  	if errors.IsNotFound(err) {
  1400  		return nil, errors.NotFoundf("application")
  1401  	} else if err != nil {
  1402  		return nil, errors.Trace(err)
  1403  	}
  1404  	result := make(map[string]string)
  1405  	for escapedKey, interfaceValue := range doc.Settings {
  1406  		key := unescapeReplacer.Replace(escapedKey)
  1407  		if value, _ := interfaceValue.(string); value != "" {
  1408  			// Empty strings are technically bad data -- when set, they clear.
  1409  			result[key] = value
  1410  		} else {
  1411  			// Some bad data isn't reason enough to obscure the good data.
  1412  			logger.Warningf("unexpected leader settings value for %s: %#v", key, interfaceValue)
  1413  		}
  1414  	}
  1415  	return result, nil
  1416  }
  1417  
  1418  // UpdateLeaderSettings updates the service's leader settings with the supplied
  1419  // values, but will fail (with a suitable error) if the supplied Token loses
  1420  // validity. Empty values in the supplied map will be cleared in the database.
  1421  func (a *Application) UpdateLeaderSettings(token leadership.Token, updates map[string]string) error {
  1422  	// There's no compelling reason to have these methods on Service -- and
  1423  	// thus require an extra db read to access them -- but it stops the State
  1424  	// type getting even more cluttered.
  1425  
  1426  	// We can calculate the actual update ahead of time; it's not dependent
  1427  	// upon the current state of the document. (*Writing* it should depend
  1428  	// on document state, but that's handled below.)
  1429  	key := leadershipSettingsKey(a.doc.Name)
  1430  	sets := bson.M{}
  1431  	unsets := bson.M{}
  1432  	for unescapedKey, value := range updates {
  1433  		key := escapeReplacer.Replace(unescapedKey)
  1434  		if value == "" {
  1435  			unsets[key] = 1
  1436  		} else {
  1437  			sets[key] = value
  1438  		}
  1439  	}
  1440  	update := setUnsetUpdateSettings(sets, unsets)
  1441  
  1442  	isNullChange := func(rawMap map[string]interface{}) bool {
  1443  		for key := range unsets {
  1444  			if _, found := rawMap[key]; found {
  1445  				return false
  1446  			}
  1447  		}
  1448  		for key, value := range sets {
  1449  			if current := rawMap[key]; current != value {
  1450  				return false
  1451  			}
  1452  		}
  1453  		return true
  1454  	}
  1455  
  1456  	buildTxn := func(_ int) ([]txn.Op, error) {
  1457  		// Read the current document state so we can abort if there's
  1458  		// no actual change; and the version number so we can assert
  1459  		// on it and prevent these settings from landing late.
  1460  		doc, err := readSettingsDoc(a.st, settingsC, key)
  1461  		if errors.IsNotFound(err) {
  1462  			return nil, errors.NotFoundf("application")
  1463  		} else if err != nil {
  1464  			return nil, errors.Trace(err)
  1465  		}
  1466  		if isNullChange(doc.Settings) {
  1467  			return nil, jujutxn.ErrNoOperations
  1468  		}
  1469  		return []txn.Op{{
  1470  			C:      settingsC,
  1471  			Id:     key,
  1472  			Assert: bson.D{{"version", doc.Version}},
  1473  			Update: update,
  1474  		}}, nil
  1475  	}
  1476  	return a.st.run(buildTxnWithLeadership(buildTxn, token))
  1477  }
  1478  
  1479  var ErrSubordinateConstraints = stderrors.New("constraints do not apply to subordinate services")
  1480  
  1481  // Constraints returns the current application constraints.
  1482  func (a *Application) Constraints() (constraints.Value, error) {
  1483  	if a.doc.Subordinate {
  1484  		return constraints.Value{}, ErrSubordinateConstraints
  1485  	}
  1486  	return readConstraints(a.st, a.globalKey())
  1487  }
  1488  
  1489  // SetConstraints replaces the current application constraints.
  1490  func (a *Application) SetConstraints(cons constraints.Value) (err error) {
  1491  	unsupported, err := a.st.validateConstraints(cons)
  1492  	if len(unsupported) > 0 {
  1493  		logger.Warningf(
  1494  			"setting constraints on application %q: unsupported constraints: %v", a.Name(), strings.Join(unsupported, ","))
  1495  	} else if err != nil {
  1496  		return err
  1497  	}
  1498  	if a.doc.Subordinate {
  1499  		return ErrSubordinateConstraints
  1500  	}
  1501  	defer errors.DeferredAnnotatef(&err, "cannot set constraints")
  1502  	if a.doc.Life != Alive {
  1503  		return errNotAlive
  1504  	}
  1505  	ops := []txn.Op{{
  1506  		C:      applicationsC,
  1507  		Id:     a.doc.DocID,
  1508  		Assert: isAliveDoc,
  1509  	}}
  1510  	ops = append(ops, setConstraintsOp(a.st, a.globalKey(), cons))
  1511  	return onAbort(a.st.runTransaction(ops), errNotAlive)
  1512  }
  1513  
  1514  // EndpointBindings returns the mapping for each endpoint name and the space
  1515  // name it is bound to (or empty if unspecified). When no bindings are stored
  1516  // for the application, defaults are returned.
  1517  func (a *Application) EndpointBindings() (map[string]string, error) {
  1518  	// We don't need the TxnRevno below.
  1519  	bindings, _, err := readEndpointBindings(a.st, a.globalKey())
  1520  	if err != nil && !errors.IsNotFound(err) {
  1521  		return nil, errors.Trace(err)
  1522  	}
  1523  	if bindings == nil {
  1524  		bindings, err = a.defaultEndpointBindings()
  1525  		if err != nil {
  1526  			return nil, errors.Trace(err)
  1527  		}
  1528  	}
  1529  	return bindings, nil
  1530  }
  1531  
  1532  // defaultEndpointBindings returns a map with each endpoint from the current
  1533  // charm metadata bound to an empty space. If no charm URL is set yet, it
  1534  // returns an empty map.
  1535  func (a *Application) defaultEndpointBindings() (map[string]string, error) {
  1536  	if a.doc.CharmURL == nil {
  1537  		return map[string]string{}, nil
  1538  	}
  1539  
  1540  	charm, _, err := a.Charm()
  1541  	if err != nil {
  1542  		return nil, errors.Trace(err)
  1543  	}
  1544  
  1545  	return DefaultEndpointBindingsForCharm(charm.Meta()), nil
  1546  }
  1547  
  1548  // MetricCredentials returns any metric credentials associated with this service.
  1549  func (a *Application) MetricCredentials() []byte {
  1550  	return a.doc.MetricCredentials
  1551  }
  1552  
  1553  // SetMetricCredentials updates the metric credentials associated with this service.
  1554  func (a *Application) SetMetricCredentials(b []byte) error {
  1555  	buildTxn := func(attempt int) ([]txn.Op, error) {
  1556  		if attempt > 0 {
  1557  			alive, err := isAlive(a.st, applicationsC, a.doc.DocID)
  1558  			if err != nil {
  1559  				return nil, errors.Trace(err)
  1560  			} else if !alive {
  1561  				return nil, errNotAlive
  1562  			}
  1563  		}
  1564  		ops := []txn.Op{
  1565  			{
  1566  				C:      applicationsC,
  1567  				Id:     a.doc.DocID,
  1568  				Assert: isAliveDoc,
  1569  				Update: bson.M{"$set": bson.M{"metric-credentials": b}},
  1570  			},
  1571  		}
  1572  		return ops, nil
  1573  	}
  1574  	if err := a.st.run(buildTxn); err != nil {
  1575  		if err == errNotAlive {
  1576  			return errors.New("cannot update metric credentials: application " + err.Error())
  1577  		}
  1578  		return errors.Annotatef(err, "cannot update metric credentials")
  1579  	}
  1580  	a.doc.MetricCredentials = b
  1581  	return nil
  1582  }
  1583  
  1584  // StorageConstraints returns the storage constraints for the application.
  1585  func (a *Application) StorageConstraints() (map[string]StorageConstraints, error) {
  1586  	cons, err := readStorageConstraints(a.st, a.storageConstraintsKey())
  1587  	if errors.IsNotFound(err) {
  1588  		return nil, nil
  1589  	} else if err != nil {
  1590  		return nil, errors.Trace(err)
  1591  	}
  1592  	return cons, nil
  1593  }
  1594  
  1595  // Status returns the status of the service.
  1596  // Only unit leaders are allowed to set the status of the service.
  1597  // If no status is recorded, then there are no unit leaders and the
  1598  // status is derived from the unit status values.
  1599  func (a *Application) Status() (status.StatusInfo, error) {
  1600  	statuses, closer := a.st.getCollection(statusesC)
  1601  	defer closer()
  1602  	query := statuses.Find(bson.D{{"_id", a.globalKey()}, {"neverset", true}})
  1603  	if count, err := query.Count(); err != nil {
  1604  		return status.StatusInfo{}, errors.Trace(err)
  1605  	} else if count != 0 {
  1606  		// This indicates that SetStatus has never been called on this service.
  1607  		// This in turn implies the application status document is likely to be
  1608  		// inaccurate, so we return aggregated unit statuses instead.
  1609  		//
  1610  		// TODO(fwereade): this is completely wrong and will produce bad results
  1611  		// in not-very-challenging scenarios. The leader unit remains responsible
  1612  		// for setting the application status in a timely way, *whether or not the
  1613  		// charm's hooks exists or sets an application status*. This logic should be
  1614  		// removed as soon as possible, and the responsibilities implemented in
  1615  		// the right places rather than being applied at seeming random.
  1616  		units, err := a.AllUnits()
  1617  		if err != nil {
  1618  			return status.StatusInfo{}, err
  1619  		}
  1620  		logger.Tracef("service %q has %d units", a.Name(), len(units))
  1621  		if len(units) > 0 {
  1622  			return a.deriveStatus(units)
  1623  		}
  1624  	}
  1625  	return getStatus(a.st, a.globalKey(), "application")
  1626  }
  1627  
  1628  // SetStatus sets the status for the application.
  1629  func (a *Application) SetStatus(statusInfo status.StatusInfo) error {
  1630  	if !status.ValidWorkloadStatus(statusInfo.Status) {
  1631  		return errors.Errorf("cannot set invalid status %q", statusInfo.Status)
  1632  	}
  1633  	return setStatus(a.st, setStatusParams{
  1634  		badge:     "application",
  1635  		globalKey: a.globalKey(),
  1636  		status:    statusInfo.Status,
  1637  		message:   statusInfo.Message,
  1638  		rawData:   statusInfo.Data,
  1639  		updated:   statusInfo.Since,
  1640  	})
  1641  }
  1642  
  1643  // StatusHistory returns a slice of at most filter.Size StatusInfo items
  1644  // or items as old as filter.Date or items newer than now - filter.Delta time
  1645  // representing past statuses for this service.
  1646  func (a *Application) StatusHistory(filter status.StatusHistoryFilter) ([]status.StatusInfo, error) {
  1647  	args := &statusHistoryArgs{
  1648  		st:        a.st,
  1649  		globalKey: a.globalKey(),
  1650  		filter:    filter,
  1651  	}
  1652  	return statusHistory(args)
  1653  }
  1654  
  1655  // ServiceAndUnitsStatus returns the status for this application and all its units.
  1656  func (a *Application) ServiceAndUnitsStatus() (status.StatusInfo, map[string]status.StatusInfo, error) {
  1657  	serviceStatus, err := a.Status()
  1658  	if err != nil {
  1659  		return status.StatusInfo{}, nil, errors.Trace(err)
  1660  	}
  1661  	units, err := a.AllUnits()
  1662  	if err != nil {
  1663  		return status.StatusInfo{}, nil, err
  1664  	}
  1665  	results := make(map[string]status.StatusInfo, len(units))
  1666  	for _, unit := range units {
  1667  		unitStatus, err := unit.Status()
  1668  		if err != nil {
  1669  			return status.StatusInfo{}, nil, err
  1670  		}
  1671  		results[unit.Name()] = unitStatus
  1672  	}
  1673  	return serviceStatus, results, nil
  1674  
  1675  }
  1676  
  1677  func (a *Application) deriveStatus(units []*Unit) (status.StatusInfo, error) {
  1678  	var result status.StatusInfo
  1679  	for _, unit := range units {
  1680  		currentSeverity := statusServerities[result.Status]
  1681  		unitStatus, err := unit.Status()
  1682  		if err != nil {
  1683  			return status.StatusInfo{}, errors.Annotatef(err, "deriving application status from %q", unit.Name())
  1684  		}
  1685  		unitSeverity := statusServerities[unitStatus.Status]
  1686  		if unitSeverity > currentSeverity {
  1687  			result.Status = unitStatus.Status
  1688  			result.Message = unitStatus.Message
  1689  			result.Data = unitStatus.Data
  1690  			result.Since = unitStatus.Since
  1691  		}
  1692  	}
  1693  	return result, nil
  1694  }
  1695  
  1696  // statusSeverities holds status values with a severity measure.
  1697  // Status values with higher severity are used in preference to others.
  1698  var statusServerities = map[status.Status]int{
  1699  	status.Error:       100,
  1700  	status.Blocked:     90,
  1701  	status.Waiting:     80,
  1702  	status.Maintenance: 70,
  1703  	status.Terminated:  60,
  1704  	status.Active:      50,
  1705  	status.Unknown:     40,
  1706  }
  1707  
  1708  type addApplicationOpsArgs struct {
  1709  	applicationDoc *applicationDoc
  1710  	statusDoc      statusDoc
  1711  	constraints    constraints.Value
  1712  	storage        map[string]StorageConstraints
  1713  	settings       map[string]interface{}
  1714  	// These are nil when adding a new service, and most likely
  1715  	// non-nil when migrating.
  1716  	leadershipSettings map[string]interface{}
  1717  }
  1718  
  1719  // addApplicationOps returns the operations required to add an application to the
  1720  // services collection, along with all the associated expected other service
  1721  // entries. This method is used by both the *State.AddService method and the
  1722  // migration import code.
  1723  func addApplicationOps(st *State, args addApplicationOpsArgs) ([]txn.Op, error) {
  1724  	svc := newApplication(st, args.applicationDoc)
  1725  
  1726  	charmRefOps, err := appCharmIncRefOps(st, args.applicationDoc.Name, args.applicationDoc.CharmURL, true)
  1727  	if err != nil {
  1728  		return nil, errors.Trace(err)
  1729  	}
  1730  
  1731  	globalKey := svc.globalKey()
  1732  	settingsKey := svc.settingsKey()
  1733  	storageConstraintsKey := svc.storageConstraintsKey()
  1734  	leadershipKey := leadershipSettingsKey(svc.Name())
  1735  
  1736  	ops := []txn.Op{
  1737  		createConstraintsOp(st, globalKey, args.constraints),
  1738  		createStorageConstraintsOp(storageConstraintsKey, args.storage),
  1739  		createSettingsOp(settingsC, settingsKey, args.settings),
  1740  		createSettingsOp(settingsC, leadershipKey, args.leadershipSettings),
  1741  		createStatusOp(st, globalKey, args.statusDoc),
  1742  		addModelServiceRefOp(st, svc.Name()),
  1743  	}
  1744  	ops = append(ops, charmRefOps...)
  1745  	ops = append(ops, txn.Op{
  1746  		C:      applicationsC,
  1747  		Id:     svc.Name(),
  1748  		Assert: txn.DocMissing,
  1749  		Insert: args.applicationDoc,
  1750  	})
  1751  	return ops, nil
  1752  }