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