github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/state/unit.go (about)

     1  // Copyright 2012-2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state
     5  
     6  import (
     7  	"fmt"
     8  	"time"
     9  
    10  	"github.com/juju/errors"
    11  	"github.com/juju/loggo"
    12  	"github.com/juju/names"
    13  	jujutxn "github.com/juju/txn"
    14  	"github.com/juju/utils"
    15  	"github.com/juju/utils/set"
    16  	"github.com/juju/version"
    17  	"gopkg.in/juju/charm.v6-unstable"
    18  	"gopkg.in/mgo.v2"
    19  	"gopkg.in/mgo.v2/bson"
    20  	"gopkg.in/mgo.v2/txn"
    21  
    22  	"github.com/juju/juju/constraints"
    23  	"github.com/juju/juju/core/actions"
    24  	"github.com/juju/juju/instance"
    25  	"github.com/juju/juju/network"
    26  	"github.com/juju/juju/state/presence"
    27  	"github.com/juju/juju/status"
    28  	"github.com/juju/juju/tools"
    29  )
    30  
    31  var unitLogger = loggo.GetLogger("juju.state.unit")
    32  
    33  // AssignmentPolicy controls what machine a unit will be assigned to.
    34  type AssignmentPolicy string
    35  
    36  const (
    37  	// AssignLocal indicates that all service units should be assigned
    38  	// to machine 0.
    39  	AssignLocal AssignmentPolicy = "local"
    40  
    41  	// AssignClean indicates that every service unit should be assigned
    42  	// to a machine which never previously has hosted any units, and that
    43  	// new machines should be launched if required.
    44  	AssignClean AssignmentPolicy = "clean"
    45  
    46  	// AssignCleanEmpty indicates that every service unit should be assigned
    47  	// to a machine which never previously has hosted any units, and which is not
    48  	// currently hosting any containers, and that new machines should be launched if required.
    49  	AssignCleanEmpty AssignmentPolicy = "clean-empty"
    50  
    51  	// AssignNew indicates that every service unit should be assigned to a new
    52  	// dedicated machine.  A new machine will be launched for each new unit.
    53  	AssignNew AssignmentPolicy = "new"
    54  )
    55  
    56  // ResolvedMode describes the way state transition errors
    57  // are resolved.
    58  type ResolvedMode string
    59  
    60  // These are available ResolvedMode values.
    61  const (
    62  	ResolvedNone       ResolvedMode = ""
    63  	ResolvedRetryHooks ResolvedMode = "retry-hooks"
    64  	ResolvedNoHooks    ResolvedMode = "no-hooks"
    65  )
    66  
    67  // port identifies a network port number for a particular protocol.
    68  // TODO(mue) Not really used anymore, se bellow. Can be removed when
    69  // cleaning unitDoc.
    70  type port struct {
    71  	Protocol string `bson:"protocol"`
    72  	Number   int    `bson:"number"`
    73  }
    74  
    75  // unitDoc represents the internal state of a unit in MongoDB.
    76  // Note the correspondence with UnitInfo in apiserver/params.
    77  type unitDoc struct {
    78  	DocID                  string `bson:"_id"`
    79  	Name                   string `bson:"name"`
    80  	ModelUUID              string `bson:"model-uuid"`
    81  	Service                string
    82  	Series                 string
    83  	CharmURL               *charm.URL
    84  	Principal              string
    85  	Subordinates           []string
    86  	StorageAttachmentCount int `bson:"storageattachmentcount"`
    87  	MachineId              string
    88  	Resolved               ResolvedMode
    89  	Tools                  *tools.Tools `bson:",omitempty"`
    90  	Life                   Life
    91  	TxnRevno               int64 `bson:"txn-revno"`
    92  	PasswordHash           string
    93  
    94  	// TODO(mue) No longer actively used, only in upgrades.go.
    95  	// To be removed later.
    96  	Ports          []port `bson:"ports"`
    97  	PublicAddress  string `bson:"publicaddress"`
    98  	PrivateAddress string `bson:"privateaddress"`
    99  }
   100  
   101  // Unit represents the state of a service unit.
   102  type Unit struct {
   103  	st  *State
   104  	doc unitDoc
   105  }
   106  
   107  func newUnit(st *State, udoc *unitDoc) *Unit {
   108  	unit := &Unit{
   109  		st:  st,
   110  		doc: *udoc,
   111  	}
   112  	return unit
   113  }
   114  
   115  // Service returns the service.
   116  func (u *Unit) Service() (*Service, error) {
   117  	return u.st.Service(u.doc.Service)
   118  }
   119  
   120  // ConfigSettings returns the complete set of service charm config settings
   121  // available to the unit. Unset values will be replaced with the default
   122  // value for the associated option, and may thus be nil when no default is
   123  // specified.
   124  func (u *Unit) ConfigSettings() (charm.Settings, error) {
   125  	if u.doc.CharmURL == nil {
   126  		return nil, fmt.Errorf("unit charm not set")
   127  	}
   128  	settings, err := readSettings(u.st, serviceSettingsKey(u.doc.Service, u.doc.CharmURL))
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  	chrm, err := u.st.Charm(u.doc.CharmURL)
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  	result := chrm.Config().DefaultSettings()
   137  	for name, value := range settings.Map() {
   138  		result[name] = value
   139  	}
   140  	return result, nil
   141  }
   142  
   143  // ServiceName returns the service name.
   144  func (u *Unit) ServiceName() string {
   145  	return u.doc.Service
   146  }
   147  
   148  // Series returns the deployed charm's series.
   149  func (u *Unit) Series() string {
   150  	return u.doc.Series
   151  }
   152  
   153  // String returns the unit as string.
   154  func (u *Unit) String() string {
   155  	return u.doc.Name
   156  }
   157  
   158  // Name returns the unit name.
   159  func (u *Unit) Name() string {
   160  	return u.doc.Name
   161  }
   162  
   163  // unitGlobalKey returns the global database key for the named unit.
   164  func unitGlobalKey(name string) string {
   165  	return "u#" + name + "#charm"
   166  }
   167  
   168  // globalAgentKey returns the global database key for the unit.
   169  func (u *Unit) globalAgentKey() string {
   170  	return unitAgentGlobalKey(u.doc.Name)
   171  }
   172  
   173  // globalMeterStatusKey returns the global database key for the meter status of the unit.
   174  func (u *Unit) globalMeterStatusKey() string {
   175  	return unitAgentGlobalKey(u.doc.Name)
   176  }
   177  
   178  // globalKey returns the global database key for the unit.
   179  func (u *Unit) globalKey() string {
   180  	return unitGlobalKey(u.doc.Name)
   181  }
   182  
   183  // Life returns whether the unit is Alive, Dying or Dead.
   184  func (u *Unit) Life() Life {
   185  	return u.doc.Life
   186  }
   187  
   188  // AgentTools returns the tools that the agent is currently running.
   189  // It an error that satisfies errors.IsNotFound if the tools have not
   190  // yet been set.
   191  func (u *Unit) AgentTools() (*tools.Tools, error) {
   192  	if u.doc.Tools == nil {
   193  		return nil, errors.NotFoundf("agent tools for unit %q", u)
   194  	}
   195  	tools := *u.doc.Tools
   196  	return &tools, nil
   197  }
   198  
   199  // SetAgentVersion sets the version of juju that the agent is
   200  // currently running.
   201  func (u *Unit) SetAgentVersion(v version.Binary) (err error) {
   202  	defer errors.DeferredAnnotatef(&err, "cannot set agent version for unit %q", u)
   203  	if err = checkVersionValidity(v); err != nil {
   204  		return err
   205  	}
   206  	tools := &tools.Tools{Version: v}
   207  	ops := []txn.Op{{
   208  		C:      unitsC,
   209  		Id:     u.doc.DocID,
   210  		Assert: notDeadDoc,
   211  		Update: bson.D{{"$set", bson.D{{"tools", tools}}}},
   212  	}}
   213  	if err := u.st.runTransaction(ops); err != nil {
   214  		return onAbort(err, ErrDead)
   215  	}
   216  	u.doc.Tools = tools
   217  	return nil
   218  }
   219  
   220  // SetPassword sets the password for the machine's agent.
   221  func (u *Unit) SetPassword(password string) error {
   222  	if len(password) < utils.MinAgentPasswordLength {
   223  		return fmt.Errorf("password is only %d bytes long, and is not a valid Agent password", len(password))
   224  	}
   225  	return u.setPasswordHash(utils.AgentPasswordHash(password))
   226  }
   227  
   228  // setPasswordHash sets the underlying password hash in the database directly
   229  // to the value supplied. This is split out from SetPassword to allow direct
   230  // manipulation in tests (to check for backwards compatibility).
   231  func (u *Unit) setPasswordHash(passwordHash string) error {
   232  	ops := []txn.Op{{
   233  		C:      unitsC,
   234  		Id:     u.doc.DocID,
   235  		Assert: notDeadDoc,
   236  		Update: bson.D{{"$set", bson.D{{"passwordhash", passwordHash}}}},
   237  	}}
   238  	err := u.st.runTransaction(ops)
   239  	if err != nil {
   240  		return fmt.Errorf("cannot set password of unit %q: %v", u, onAbort(err, ErrDead))
   241  	}
   242  	u.doc.PasswordHash = passwordHash
   243  	return nil
   244  }
   245  
   246  // Return the underlying PasswordHash stored in the database. Used by the test
   247  // suite to check that the PasswordHash gets properly updated to new values
   248  // when compatibility mode is detected.
   249  func (u *Unit) getPasswordHash() string {
   250  	return u.doc.PasswordHash
   251  }
   252  
   253  // PasswordValid returns whether the given password is valid
   254  // for the given unit.
   255  func (u *Unit) PasswordValid(password string) bool {
   256  	agentHash := utils.AgentPasswordHash(password)
   257  	if agentHash == u.doc.PasswordHash {
   258  		return true
   259  	}
   260  	return false
   261  }
   262  
   263  // Destroy, when called on a Alive unit, advances its lifecycle as far as
   264  // possible; it otherwise has no effect. In most situations, the unit's
   265  // life is just set to Dying; but if a principal unit that is not assigned
   266  // to a provisioned machine is Destroyed, it will be removed from state
   267  // directly.
   268  func (u *Unit) Destroy() (err error) {
   269  	defer func() {
   270  		if err == nil {
   271  			// This is a white lie; the document might actually be removed.
   272  			u.doc.Life = Dying
   273  		}
   274  	}()
   275  	unit := &Unit{st: u.st, doc: u.doc}
   276  	buildTxn := func(attempt int) ([]txn.Op, error) {
   277  		if attempt > 0 {
   278  			if err := unit.Refresh(); errors.IsNotFound(err) {
   279  				return nil, jujutxn.ErrNoOperations
   280  			} else if err != nil {
   281  				return nil, err
   282  			}
   283  		}
   284  		switch ops, err := unit.destroyOps(); err {
   285  		case errRefresh:
   286  		case errAlreadyDying:
   287  			return nil, jujutxn.ErrNoOperations
   288  		case nil:
   289  			return ops, nil
   290  		default:
   291  			return nil, err
   292  		}
   293  		return nil, jujutxn.ErrNoOperations
   294  	}
   295  	if err = unit.st.run(buildTxn); err == nil {
   296  		if historyErr := unit.eraseHistory(); historyErr != nil {
   297  			logger.Errorf("cannot delete history for unit %q: %v", unit.globalKey(), err)
   298  		}
   299  		if err = unit.Refresh(); errors.IsNotFound(err) {
   300  			return nil
   301  		}
   302  	}
   303  	return err
   304  }
   305  
   306  func (u *Unit) eraseHistory() error {
   307  	history, closer := u.st.getCollection(statusesHistoryC)
   308  	defer closer()
   309  	// XXX(fwereade): 2015-06-19 this is anything but safe: we must not mix
   310  	// txn and non-txn operations in the same collection without clear and
   311  	// detailed reasoning for so doing.
   312  	historyW := history.Writeable()
   313  
   314  	if _, err := historyW.RemoveAll(bson.D{{"statusid", u.globalKey()}}); err != nil {
   315  		return err
   316  	}
   317  	if _, err := historyW.RemoveAll(bson.D{{"statusid", u.globalAgentKey()}}); err != nil {
   318  		return err
   319  	}
   320  	return nil
   321  }
   322  
   323  // destroyOps returns the operations required to destroy the unit. If it
   324  // returns errRefresh, the unit should be refreshed and the destruction
   325  // operations recalculated.
   326  func (u *Unit) destroyOps() ([]txn.Op, error) {
   327  	if u.doc.Life != Alive {
   328  		return nil, errAlreadyDying
   329  	}
   330  
   331  	// Where possible, we'd like to be able to short-circuit unit destruction
   332  	// such that units can be removed directly rather than waiting for their
   333  	// agents to start, observe Dying, set Dead, and shut down; this takes a
   334  	// long time and is vexing to users. This turns out to be possible if and
   335  	// only if the unit agent has not yet set its status; this implies that the
   336  	// most the unit could possibly have done is to run its install hook.
   337  	//
   338  	// There's no harm in removing a unit that's run its install hook only --
   339  	// or, at least, there is no more harm than there is in removing a unit
   340  	// that's run its stop hook, and that's the usual condition.
   341  	//
   342  	// Principals with subordinates are never eligible for this shortcut,
   343  	// because the unit agent must inevitably have set a status before getting
   344  	// to the point where it can actually create its subordinate.
   345  	//
   346  	// Subordinates should be eligible for the shortcut but are not currently
   347  	// considered, on the basis that (1) they were created by active principals
   348  	// and can be expected to be deployed pretty soon afterwards, so we don't
   349  	// lose much time and (2) by maintaining this restriction, I can reduce
   350  	// the number of tests that have to change and defer that improvement to
   351  	// its own CL.
   352  	minUnitsOp := minUnitsTriggerOp(u.st, u.ServiceName())
   353  	cleanupOp := u.st.newCleanupOp(cleanupDyingUnit, u.doc.Name)
   354  	setDyingOp := txn.Op{
   355  		C:      unitsC,
   356  		Id:     u.doc.DocID,
   357  		Assert: isAliveDoc,
   358  		Update: bson.D{{"$set", bson.D{{"life", Dying}}}},
   359  	}
   360  	setDyingOps := []txn.Op{setDyingOp, cleanupOp, minUnitsOp}
   361  	if u.doc.Principal != "" {
   362  		return setDyingOps, nil
   363  	} else if len(u.doc.Subordinates)+u.doc.StorageAttachmentCount != 0 {
   364  		return setDyingOps, nil
   365  	}
   366  
   367  	// See if the unit agent has started running.
   368  	// If so then we can't set directly to dead.
   369  	agentStatusDocId := u.globalAgentKey()
   370  	agentStatusInfo, agentErr := getStatus(u.st, agentStatusDocId, "agent")
   371  	if errors.IsNotFound(agentErr) {
   372  		return nil, errAlreadyDying
   373  	} else if agentErr != nil {
   374  		return nil, errors.Trace(agentErr)
   375  	}
   376  	if agentStatusInfo.Status != status.StatusAllocating {
   377  		return setDyingOps, nil
   378  	}
   379  
   380  	ops := []txn.Op{{
   381  		C:      statusesC,
   382  		Id:     u.st.docID(agentStatusDocId),
   383  		Assert: bson.D{{"status", status.StatusAllocating}},
   384  	}, minUnitsOp}
   385  	removeAsserts := append(isAliveDoc, bson.DocElem{
   386  		"$and", []bson.D{
   387  			unitHasNoSubordinates,
   388  			unitHasNoStorageAttachments,
   389  		},
   390  	})
   391  	removeOps, err := u.removeOps(removeAsserts)
   392  	if err == errAlreadyRemoved {
   393  		return nil, errAlreadyDying
   394  	} else if err != nil {
   395  		return nil, err
   396  	}
   397  	return append(ops, removeOps...), nil
   398  }
   399  
   400  // destroyHostOps returns all necessary operations to destroy the service unit's host machine,
   401  // or ensure that the conditions preventing its destruction remain stable through the transaction.
   402  func (u *Unit) destroyHostOps(s *Service) (ops []txn.Op, err error) {
   403  	if s.doc.Subordinate {
   404  		return []txn.Op{{
   405  			C:      unitsC,
   406  			Id:     u.st.docID(u.doc.Principal),
   407  			Assert: txn.DocExists,
   408  			Update: bson.D{{"$pull", bson.D{{"subordinates", u.doc.Name}}}},
   409  		}}, nil
   410  	} else if u.doc.MachineId == "" {
   411  		unitLogger.Errorf("unit %v unassigned", u)
   412  		return nil, nil
   413  	}
   414  
   415  	machineUpdate := bson.D{{"$pull", bson.D{{"principals", u.doc.Name}}}}
   416  
   417  	m, err := u.st.Machine(u.doc.MachineId)
   418  	if err != nil {
   419  		if errors.IsNotFound(err) {
   420  			return nil, nil
   421  		}
   422  		return nil, err
   423  	}
   424  
   425  	containerCheck := true // whether container conditions allow destroying the host machine
   426  	containers, err := m.Containers()
   427  	if err != nil {
   428  		return nil, err
   429  	}
   430  	if len(containers) > 0 {
   431  		ops = append(ops, txn.Op{
   432  			C:      containerRefsC,
   433  			Id:     m.doc.DocID,
   434  			Assert: bson.D{{"children.0", bson.D{{"$exists", 1}}}},
   435  		})
   436  		containerCheck = false
   437  	} else {
   438  		ops = append(ops, txn.Op{
   439  			C:  containerRefsC,
   440  			Id: m.doc.DocID,
   441  			Assert: bson.D{{"$or", []bson.D{
   442  				{{"children", bson.D{{"$size", 0}}}},
   443  				{{"children", bson.D{{"$exists", false}}}},
   444  			}}},
   445  		})
   446  	}
   447  
   448  	machineCheck := true // whether host machine conditions allow destroy
   449  	if len(m.doc.Principals) != 1 || m.doc.Principals[0] != u.doc.Name {
   450  		machineCheck = false
   451  	} else if hasJob(m.doc.Jobs, JobManageModel) {
   452  		// Check that the machine does not have any responsibilities that
   453  		// prevent a lifecycle change.
   454  		machineCheck = false
   455  	} else if m.doc.HasVote {
   456  		machineCheck = false
   457  	}
   458  
   459  	// assert that the machine conditions pertaining to host removal conditions
   460  	// remain the same throughout the transaction.
   461  	var machineAssert bson.D
   462  	if machineCheck {
   463  		machineAssert = bson.D{{"$and", []bson.D{
   464  			{{"principals", []string{u.doc.Name}}},
   465  			{{"jobs", bson.D{{"$nin", []MachineJob{JobManageModel}}}}},
   466  			{{"hasvote", bson.D{{"$ne", true}}}},
   467  		}}}
   468  	} else {
   469  		machineAssert = bson.D{{"$or", []bson.D{
   470  			{{"principals", bson.D{{"$ne", []string{u.doc.Name}}}}},
   471  			{{"jobs", bson.D{{"$in", []MachineJob{JobManageModel}}}}},
   472  			{{"hasvote", true}},
   473  		}}}
   474  	}
   475  
   476  	// If removal conditions satisfied by machine & container docs, we can
   477  	// destroy it, in addition to removing the unit principal.
   478  	if machineCheck && containerCheck {
   479  		machineUpdate = append(machineUpdate, bson.D{{"$set", bson.D{{"life", Dying}}}}...)
   480  	}
   481  
   482  	ops = append(ops, txn.Op{
   483  		C:      machinesC,
   484  		Id:     m.doc.DocID,
   485  		Assert: machineAssert,
   486  		Update: machineUpdate,
   487  	})
   488  	return ops, nil
   489  }
   490  
   491  var errAlreadyRemoved = errors.New("entity has already been removed")
   492  
   493  // removeOps returns the operations necessary to remove the unit, assuming
   494  // the supplied asserts apply to the unit document.
   495  func (u *Unit) removeOps(asserts bson.D) ([]txn.Op, error) {
   496  	svc, err := u.st.Service(u.doc.Service)
   497  	if errors.IsNotFound(err) {
   498  		// If the service has been removed, the unit must already have been.
   499  		return nil, errAlreadyRemoved
   500  	} else if err != nil {
   501  		return nil, err
   502  	}
   503  	return svc.removeUnitOps(u, asserts)
   504  }
   505  
   506  // ErrUnitHasSubordinates is a standard error to indicate that a Unit
   507  // cannot complete an operation to end its life because it still has
   508  // subordinate services
   509  var ErrUnitHasSubordinates = errors.New("unit has subordinates")
   510  
   511  var unitHasNoSubordinates = bson.D{{
   512  	"$or", []bson.D{
   513  		{{"subordinates", bson.D{{"$size", 0}}}},
   514  		{{"subordinates", bson.D{{"$exists", false}}}},
   515  	},
   516  }}
   517  
   518  // ErrUnitHasStorageAttachments is a standard error to indicate that
   519  // a Unit cannot complete an operation to end its life because it still
   520  // has storage attachments.
   521  var ErrUnitHasStorageAttachments = errors.New("unit has storage attachments")
   522  
   523  var unitHasNoStorageAttachments = bson.D{{
   524  	"$or", []bson.D{
   525  		{{"storageattachmentcount", 0}},
   526  		{{"storageattachmentcount", bson.D{{"$exists", false}}}},
   527  	},
   528  }}
   529  
   530  // EnsureDead sets the unit lifecycle to Dead if it is Alive or Dying.
   531  // It does nothing otherwise. If the unit has subordinates, it will
   532  // return ErrUnitHasSubordinates; otherwise, if it has storage instances,
   533  // it will return ErrUnitHasStorageInstances.
   534  func (u *Unit) EnsureDead() (err error) {
   535  	if u.doc.Life == Dead {
   536  		return nil
   537  	}
   538  	defer func() {
   539  		if err == nil {
   540  			u.doc.Life = Dead
   541  		}
   542  	}()
   543  	assert := append(notDeadDoc, bson.DocElem{
   544  		"$and", []bson.D{
   545  			unitHasNoSubordinates,
   546  			unitHasNoStorageAttachments,
   547  		},
   548  	})
   549  	ops := []txn.Op{{
   550  		C:      unitsC,
   551  		Id:     u.doc.DocID,
   552  		Assert: assert,
   553  		Update: bson.D{{"$set", bson.D{{"life", Dead}}}},
   554  	}}
   555  	if err := u.st.runTransaction(ops); err != txn.ErrAborted {
   556  		return err
   557  	}
   558  	if notDead, err := isNotDead(u.st, unitsC, u.doc.DocID); err != nil {
   559  		return err
   560  	} else if !notDead {
   561  		return nil
   562  	}
   563  	if err := u.Refresh(); errors.IsNotFound(err) {
   564  		return nil
   565  	} else if err != nil {
   566  		return err
   567  	}
   568  	if len(u.doc.Subordinates) > 0 {
   569  		return ErrUnitHasSubordinates
   570  	}
   571  	return ErrUnitHasStorageAttachments
   572  }
   573  
   574  // Remove removes the unit from state, and may remove its service as well, if
   575  // the service is Dying and no other references to it exist. It will fail if
   576  // the unit is not Dead.
   577  func (u *Unit) Remove() (err error) {
   578  	defer errors.DeferredAnnotatef(&err, "cannot remove unit %q", u)
   579  	if u.doc.Life != Dead {
   580  		return errors.New("unit is not dead")
   581  	}
   582  
   583  	// Now the unit is Dead, we can be sure that it's impossible for it to
   584  	// enter relation scopes (once it's Dying, we can be sure of this; but
   585  	// EnsureDead does not require that it already be Dying, so this is the
   586  	// only point at which we can safely backstop lp:1233457 and mitigate
   587  	// the impact of unit agent bugs that leave relation scopes occupied).
   588  	relations, err := serviceRelations(u.st, u.doc.Service)
   589  	if err != nil {
   590  		return err
   591  	}
   592  	for _, rel := range relations {
   593  		ru, err := rel.Unit(u)
   594  		if err != nil {
   595  			return err
   596  		}
   597  		if err := ru.LeaveScope(); err != nil {
   598  			return err
   599  		}
   600  	}
   601  
   602  	// Now we're sure we haven't left any scopes occupied by this unit, we
   603  	// can safely remove the document.
   604  	unit := &Unit{st: u.st, doc: u.doc}
   605  	buildTxn := func(attempt int) ([]txn.Op, error) {
   606  		if attempt > 0 {
   607  			if err := unit.Refresh(); errors.IsNotFound(err) {
   608  				return nil, jujutxn.ErrNoOperations
   609  			} else if err != nil {
   610  				return nil, err
   611  			}
   612  		}
   613  		switch ops, err := unit.removeOps(isDeadDoc); err {
   614  		case errRefresh:
   615  		case errAlreadyDying:
   616  			return nil, jujutxn.ErrNoOperations
   617  		case nil:
   618  			return ops, nil
   619  		default:
   620  			return nil, err
   621  		}
   622  		return nil, jujutxn.ErrNoOperations
   623  	}
   624  	return unit.st.run(buildTxn)
   625  }
   626  
   627  // Resolved returns the resolved mode for the unit.
   628  func (u *Unit) Resolved() ResolvedMode {
   629  	return u.doc.Resolved
   630  }
   631  
   632  // IsPrincipal returns whether the unit is deployed in its own container,
   633  // and can therefore have subordinate services deployed alongside it.
   634  func (u *Unit) IsPrincipal() bool {
   635  	return u.doc.Principal == ""
   636  }
   637  
   638  // SubordinateNames returns the names of any subordinate units.
   639  func (u *Unit) SubordinateNames() []string {
   640  	names := make([]string, len(u.doc.Subordinates))
   641  	copy(names, u.doc.Subordinates)
   642  	return names
   643  }
   644  
   645  // RelationsJoined returns the relations for which the unit has entered scope
   646  // and neither left it nor prepared to leave it
   647  func (u *Unit) RelationsJoined() ([]*Relation, error) {
   648  	return u.relations(func(ru *RelationUnit) (bool, error) {
   649  		return ru.Joined()
   650  	})
   651  }
   652  
   653  // RelationsInScope returns the relations for which the unit has entered scope
   654  // and not left it.
   655  func (u *Unit) RelationsInScope() ([]*Relation, error) {
   656  	return u.relations(func(ru *RelationUnit) (bool, error) {
   657  		return ru.InScope()
   658  	})
   659  }
   660  
   661  type relationPredicate func(ru *RelationUnit) (bool, error)
   662  
   663  // relations implements RelationsJoined and RelationsInScope.
   664  func (u *Unit) relations(predicate relationPredicate) ([]*Relation, error) {
   665  	candidates, err := serviceRelations(u.st, u.doc.Service)
   666  	if err != nil {
   667  		return nil, err
   668  	}
   669  	var filtered []*Relation
   670  	for _, relation := range candidates {
   671  		relationUnit, err := relation.Unit(u)
   672  		if err != nil {
   673  			return nil, err
   674  		}
   675  		if include, err := predicate(relationUnit); err != nil {
   676  			return nil, err
   677  		} else if include {
   678  			filtered = append(filtered, relation)
   679  		}
   680  	}
   681  	return filtered, nil
   682  }
   683  
   684  // DeployerTag returns the tag of the agent responsible for deploying
   685  // the unit. If no such entity can be determined, false is returned.
   686  func (u *Unit) DeployerTag() (names.Tag, bool) {
   687  	if u.doc.Principal != "" {
   688  		return names.NewUnitTag(u.doc.Principal), true
   689  	} else if u.doc.MachineId != "" {
   690  		return names.NewMachineTag(u.doc.MachineId), true
   691  	}
   692  	return nil, false
   693  }
   694  
   695  // PrincipalName returns the name of the unit's principal.
   696  // If the unit is not a subordinate, false is returned.
   697  func (u *Unit) PrincipalName() (string, bool) {
   698  	return u.doc.Principal, u.doc.Principal != ""
   699  }
   700  
   701  // machine returns the unit's machine.
   702  func (u *Unit) machine() (*Machine, error) {
   703  	id, err := u.AssignedMachineId()
   704  	if err != nil {
   705  		return nil, errors.Annotatef(err, "unit %v cannot get assigned machine", u)
   706  	}
   707  	m, err := u.st.Machine(id)
   708  	if err != nil {
   709  		return nil, errors.Annotatef(err, "unit %v misses machine id %v", u, id)
   710  	}
   711  	return m, nil
   712  }
   713  
   714  // PublicAddress returns the public address of the unit.
   715  func (u *Unit) PublicAddress() (network.Address, error) {
   716  	m, err := u.machine()
   717  	if err != nil {
   718  		unitLogger.Errorf("%v", err)
   719  		return network.Address{}, errors.Trace(err)
   720  	}
   721  	return m.PublicAddress()
   722  }
   723  
   724  // PrivateAddress returns the private address of the unit.
   725  func (u *Unit) PrivateAddress() (network.Address, error) {
   726  	m, err := u.machine()
   727  	if err != nil {
   728  		unitLogger.Errorf("%v", err)
   729  		return network.Address{}, errors.Trace(err)
   730  	}
   731  	return m.PrivateAddress()
   732  }
   733  
   734  // AvailabilityZone returns the name of the availability zone into which
   735  // the unit's machine instance was provisioned.
   736  func (u *Unit) AvailabilityZone() (string, error) {
   737  	m, err := u.machine()
   738  	if err != nil {
   739  		return "", errors.Trace(err)
   740  	}
   741  	return m.AvailabilityZone()
   742  }
   743  
   744  // Refresh refreshes the contents of the Unit from the underlying
   745  // state. It an error that satisfies errors.IsNotFound if the unit has
   746  // been removed.
   747  func (u *Unit) Refresh() error {
   748  	units, closer := u.st.getCollection(unitsC)
   749  	defer closer()
   750  
   751  	err := units.FindId(u.doc.DocID).One(&u.doc)
   752  	if err == mgo.ErrNotFound {
   753  		return errors.NotFoundf("unit %q", u)
   754  	}
   755  	if err != nil {
   756  		return fmt.Errorf("cannot refresh unit %q: %v", u, err)
   757  	}
   758  	return nil
   759  }
   760  
   761  // Agent Returns an agent by its unit's name.
   762  func (u *Unit) Agent() *UnitAgent {
   763  	return newUnitAgent(u.st, u.Tag(), u.Name())
   764  }
   765  
   766  // AgentHistory returns an StatusHistoryGetter which can
   767  //be used to query the status history of the unit's agent.
   768  func (u *Unit) AgentHistory() status.StatusHistoryGetter {
   769  	return u.Agent()
   770  }
   771  
   772  // SetAgentStatus calls SetStatus for this unit's agent, this call
   773  // is equivalent to the former call to SetStatus when Agent and Unit
   774  // where not separate entities.
   775  func (u *Unit) SetAgentStatus(agentStatus status.Status, info string, data map[string]interface{}) error {
   776  	agent := newUnitAgent(u.st, u.Tag(), u.Name())
   777  	return agent.SetStatus(agentStatus, info, data)
   778  }
   779  
   780  // AgentStatus calls Status for this unit's agent, this call
   781  // is equivalent to the former call to Status when Agent and Unit
   782  // where not separate entities.
   783  func (u *Unit) AgentStatus() (status.StatusInfo, error) {
   784  	agent := newUnitAgent(u.st, u.Tag(), u.Name())
   785  	return agent.Status()
   786  }
   787  
   788  // StatusHistory returns a slice of at most <size> StatusInfo items
   789  // representing past statuses for this unit.
   790  func (u *Unit) StatusHistory(size int) ([]status.StatusInfo, error) {
   791  	return statusHistory(u.st, u.globalKey(), size)
   792  }
   793  
   794  // Status returns the status of the unit.
   795  // This method relies on globalKey instead of globalAgentKey since it is part of
   796  // the effort to separate Unit from UnitAgent. Now the Status for UnitAgent is in
   797  // the UnitAgent struct.
   798  func (u *Unit) Status() (status.StatusInfo, error) {
   799  	// The current health spec says when a hook error occurs, the workload should
   800  	// be in error state, but the state model more correctly records the agent
   801  	// itself as being in error. So we'll do that model translation here.
   802  	// TODO(fwereade) as on unitagent, this transformation does not belong here.
   803  	// For now, pretend we're always reading the unit status.
   804  	info, err := getStatus(u.st, u.globalAgentKey(), "unit")
   805  	if err != nil {
   806  		return status.StatusInfo{}, err
   807  	}
   808  	if info.Status != status.StatusError {
   809  		info, err = getStatus(u.st, u.globalKey(), "unit")
   810  		if err != nil {
   811  			return status.StatusInfo{}, err
   812  		}
   813  	}
   814  	return info, nil
   815  }
   816  
   817  // SetStatus sets the status of the unit agent. The optional values
   818  // allow to pass additional helpful status data.
   819  // This method relies on globalKey instead of globalAgentKey since it is part of
   820  // the effort to separate Unit from UnitAgent. Now the SetStatus for UnitAgent is in
   821  // the UnitAgent struct.
   822  func (u *Unit) SetStatus(unitStatus status.Status, info string, data map[string]interface{}) error {
   823  	if !status.ValidWorkloadStatus(unitStatus) {
   824  		return errors.Errorf("cannot set invalid status %q", unitStatus)
   825  	}
   826  	return setStatus(u.st, setStatusParams{
   827  		badge:     "unit",
   828  		globalKey: u.globalKey(),
   829  		status:    unitStatus,
   830  		message:   info,
   831  		rawData:   data,
   832  	})
   833  }
   834  
   835  // OpenPortsOnSubnet opens the given port range and protocol for the unit on the
   836  // given subnet, which can be empty. When non-empty, subnetID must refer to an
   837  // existing, alive subnet, otherwise an error is returned. Returns an error if
   838  // opening the requested range conflicts with another already opened range on
   839  // the same subnet and and the unit's assigned machine.
   840  func (u *Unit) OpenPortsOnSubnet(subnetID, protocol string, fromPort, toPort int) (err error) {
   841  	ports, err := NewPortRange(u.Name(), fromPort, toPort, protocol)
   842  	if err != nil {
   843  		return errors.Annotatef(err, "invalid port range %v-%v/%v", fromPort, toPort, protocol)
   844  	}
   845  	defer errors.DeferredAnnotatef(&err, "cannot open ports %v for unit %q on subnet %q", ports, u, subnetID)
   846  
   847  	machineID, err := u.AssignedMachineId()
   848  	if err != nil {
   849  		return errors.Annotatef(err, "unit %q has no assigned machine", u)
   850  	}
   851  
   852  	if err := u.checkSubnetAliveWhenSet(subnetID); err != nil {
   853  		return errors.Trace(err)
   854  	}
   855  
   856  	machinePorts, err := getOrCreatePorts(u.st, machineID, subnetID)
   857  	if err != nil {
   858  		return errors.Annotate(err, "cannot get or create ports")
   859  	}
   860  
   861  	return machinePorts.OpenPorts(ports)
   862  }
   863  
   864  func (u *Unit) checkSubnetAliveWhenSet(subnetID string) error {
   865  	if subnetID == "" {
   866  		return nil
   867  	} else if !names.IsValidSubnet(subnetID) {
   868  		return errors.Errorf("invalid subnet ID %q", subnetID)
   869  	}
   870  
   871  	subnet, err := u.st.Subnet(subnetID)
   872  	if err != nil && !errors.IsNotFound(err) {
   873  		return errors.Annotatef(err, "getting subnet %q", subnetID)
   874  	} else if errors.IsNotFound(err) || subnet.Life() != Alive {
   875  		return errors.Errorf("subnet %q not found or not alive", subnetID)
   876  	}
   877  	return nil
   878  }
   879  
   880  // ClosePortsOnSubnet closes the given port range and protocol for the unit on
   881  // the given subnet, which can be empty. When non-empty, subnetID must refer to
   882  // an existing, alive subnet, otherwise an error is returned.
   883  func (u *Unit) ClosePortsOnSubnet(subnetID, protocol string, fromPort, toPort int) (err error) {
   884  	ports, err := NewPortRange(u.Name(), fromPort, toPort, protocol)
   885  	if err != nil {
   886  		return errors.Annotatef(err, "invalid port range %v-%v/%v", fromPort, toPort, protocol)
   887  	}
   888  	defer errors.DeferredAnnotatef(&err, "cannot close ports %v for unit %q on subnet %q", ports, u, subnetID)
   889  
   890  	machineID, err := u.AssignedMachineId()
   891  	if err != nil {
   892  		return errors.Annotatef(err, "unit %q has no assigned machine", u)
   893  	}
   894  
   895  	if err := u.checkSubnetAliveWhenSet(subnetID); err != nil {
   896  		return errors.Trace(err)
   897  	}
   898  
   899  	machinePorts, err := getOrCreatePorts(u.st, machineID, subnetID)
   900  	if err != nil {
   901  		return errors.Annotate(err, "cannot get or create ports")
   902  	}
   903  
   904  	return machinePorts.ClosePorts(ports)
   905  }
   906  
   907  // OpenPorts opens the given port range and protocol for the unit, if it does
   908  // not conflict with another already opened range on the unit's assigned
   909  // machine.
   910  //
   911  // TODO(dimitern): This should be removed once we use OpenPortsOnSubnet across
   912  // the board, passing subnet IDs explicitly.
   913  func (u *Unit) OpenPorts(protocol string, fromPort, toPort int) error {
   914  	return u.OpenPortsOnSubnet("", protocol, fromPort, toPort)
   915  }
   916  
   917  // ClosePorts closes the given port range and protocol for the unit.
   918  //
   919  // TODO(dimitern): This should be removed once we use ClosePortsOnSubnet across
   920  // the board, passing subnet IDs explicitly.
   921  func (u *Unit) ClosePorts(protocol string, fromPort, toPort int) (err error) {
   922  	return u.ClosePortsOnSubnet("", protocol, fromPort, toPort)
   923  }
   924  
   925  // OpenPortOnSubnet opens the given port and protocol for the unit on the given
   926  // subnet, which can be empty. When non-empty, subnetID must refer to an
   927  // existing, alive subnet, otherwise an error is returned.
   928  func (u *Unit) OpenPortOnSubnet(subnetID, protocol string, number int) error {
   929  	return u.OpenPortsOnSubnet(subnetID, protocol, number, number)
   930  }
   931  
   932  // ClosePortOnSubnet closes the given port and protocol for the unit on the given
   933  // subnet, which can be empty. When non-empty, subnetID must refer to an
   934  // existing, alive subnet, otherwise an error is returned.
   935  func (u *Unit) ClosePortOnSubnet(subnetID, protocol string, number int) error {
   936  	return u.ClosePortsOnSubnet(subnetID, protocol, number, number)
   937  }
   938  
   939  // OpenPort opens the given port and protocol for the unit.
   940  //
   941  // TODO(dimitern): This should be removed once we use OpenPort(s)OnSubnet across
   942  // the board, passing subnet IDs explicitly.
   943  func (u *Unit) OpenPort(protocol string, number int) error {
   944  	return u.OpenPortOnSubnet("", protocol, number)
   945  }
   946  
   947  // ClosePort closes the given port and protocol for the unit.
   948  //
   949  // TODO(dimitern): This should be removed once we use ClosePortsOnSubnet across
   950  // the board, passing subnet IDs explicitly.
   951  func (u *Unit) ClosePort(protocol string, number int) error {
   952  	return u.ClosePortOnSubnet("", protocol, number)
   953  }
   954  
   955  // OpenedPortsOnSubnet returns a slice containing the open port ranges of the
   956  // unit on the given subnet ID, which can be empty. When subnetID is not empty,
   957  // it must refer to an existing, alive subnet, otherwise an error is returned.
   958  // Also, when no ports are yet open for the unit on that subnet, no error and
   959  // empty slice is returned.
   960  func (u *Unit) OpenedPortsOnSubnet(subnetID string) ([]network.PortRange, error) {
   961  	machineID, err := u.AssignedMachineId()
   962  	if err != nil {
   963  		return nil, errors.Annotatef(err, "unit %q has no assigned machine", u)
   964  	}
   965  
   966  	if err := u.checkSubnetAliveWhenSet(subnetID); err != nil {
   967  		return nil, errors.Trace(err)
   968  	}
   969  
   970  	machinePorts, err := getPorts(u.st, machineID, subnetID)
   971  	result := []network.PortRange{}
   972  	if errors.IsNotFound(err) {
   973  		return result, nil
   974  	} else if err != nil {
   975  		return nil, errors.Annotatef(err, "failed getting ports for unit %q, subnet %q", u, subnetID)
   976  	}
   977  	ports := machinePorts.PortsForUnit(u.Name())
   978  	for _, port := range ports {
   979  		result = append(result, network.PortRange{
   980  			Protocol: port.Protocol,
   981  			FromPort: port.FromPort,
   982  			ToPort:   port.ToPort,
   983  		})
   984  	}
   985  	network.SortPortRanges(result)
   986  	return result, nil
   987  }
   988  
   989  // OpenedPorts returns a slice containing the open port ranges of the
   990  // unit.
   991  //
   992  // TODO(dimitern): This should be removed once we use OpenedPortsOnSubnet across
   993  // the board, passing subnet IDs explicitly.
   994  func (u *Unit) OpenedPorts() ([]network.PortRange, error) {
   995  	return u.OpenedPortsOnSubnet("")
   996  }
   997  
   998  // CharmURL returns the charm URL this unit is currently using.
   999  func (u *Unit) CharmURL() (*charm.URL, bool) {
  1000  	if u.doc.CharmURL == nil {
  1001  		return nil, false
  1002  	}
  1003  	return u.doc.CharmURL, true
  1004  }
  1005  
  1006  // SetCharmURL marks the unit as currently using the supplied charm URL.
  1007  // An error will be returned if the unit is dead, or the charm URL not known.
  1008  func (u *Unit) SetCharmURL(curl *charm.URL) error {
  1009  	if curl == nil {
  1010  		return fmt.Errorf("cannot set nil charm url")
  1011  	}
  1012  
  1013  	db, closer := u.st.newDB()
  1014  	defer closer()
  1015  	units, closer := db.GetCollection(unitsC)
  1016  	defer closer()
  1017  	charms, closer := db.GetCollection(charmsC)
  1018  	defer closer()
  1019  
  1020  	buildTxn := func(attempt int) ([]txn.Op, error) {
  1021  		if attempt > 0 {
  1022  			// NOTE: We're explicitly allowing SetCharmURL to succeed
  1023  			// when the unit is Dying, because service/charm upgrades
  1024  			// should still be allowed to apply to dying units, so
  1025  			// that bugs in departed/broken hooks can be addressed at
  1026  			// runtime.
  1027  			if notDead, err := isNotDeadWithSession(units, u.doc.DocID); err != nil {
  1028  				return nil, errors.Trace(err)
  1029  			} else if !notDead {
  1030  				return nil, ErrDead
  1031  			}
  1032  		}
  1033  		sel := bson.D{{"_id", u.doc.DocID}, {"charmurl", curl}}
  1034  		if count, err := units.Find(sel).Count(); err != nil {
  1035  			return nil, errors.Trace(err)
  1036  		} else if count == 1 {
  1037  			// Already set
  1038  			return nil, jujutxn.ErrNoOperations
  1039  		}
  1040  		if count, err := charms.FindId(curl.String()).Count(); err != nil {
  1041  			return nil, errors.Trace(err)
  1042  		} else if count < 1 {
  1043  			return nil, errors.Errorf("unknown charm url %q", curl)
  1044  		}
  1045  
  1046  		// Add a reference to the service settings for the new charm.
  1047  		incOp, err := settingsIncRefOp(u.st, u.doc.Service, curl, false)
  1048  		if err != nil {
  1049  			return nil, errors.Trace(err)
  1050  		}
  1051  
  1052  		// Set the new charm URL.
  1053  		differentCharm := bson.D{{"charmurl", bson.D{{"$ne", curl}}}}
  1054  		ops := []txn.Op{
  1055  			incOp,
  1056  			{
  1057  				C:      unitsC,
  1058  				Id:     u.doc.DocID,
  1059  				Assert: append(notDeadDoc, differentCharm...),
  1060  				Update: bson.D{{"$set", bson.D{{"charmurl", curl}}}},
  1061  			}}
  1062  		if u.doc.CharmURL != nil {
  1063  			// Drop the reference to the old charm.
  1064  			decOps, err := settingsDecRefOps(u.st, u.doc.Service, u.doc.CharmURL)
  1065  			if err != nil {
  1066  				return nil, errors.Trace(err)
  1067  			}
  1068  			ops = append(ops, decOps...)
  1069  		}
  1070  		return ops, nil
  1071  	}
  1072  	err := u.st.run(buildTxn)
  1073  	if err == nil {
  1074  		u.doc.CharmURL = curl
  1075  	}
  1076  	return err
  1077  }
  1078  
  1079  // AgentPresence returns whether the respective remote agent is alive.
  1080  func (u *Unit) AgentPresence() (bool, error) {
  1081  	return u.st.pwatcher.Alive(u.globalAgentKey())
  1082  }
  1083  
  1084  // Tag returns a name identifying the unit.
  1085  // The returned name will be different from other Tag values returned by any
  1086  // other entities from the same state.
  1087  func (u *Unit) Tag() names.Tag {
  1088  	return u.UnitTag()
  1089  }
  1090  
  1091  // UnitTag returns a names.UnitTag representing this Unit, unless the
  1092  // unit Name is invalid, in which case it will panic
  1093  func (u *Unit) UnitTag() names.UnitTag {
  1094  	return names.NewUnitTag(u.Name())
  1095  }
  1096  
  1097  // WaitAgentPresence blocks until the respective agent is alive.
  1098  func (u *Unit) WaitAgentPresence(timeout time.Duration) (err error) {
  1099  	defer errors.DeferredAnnotatef(&err, "waiting for agent of unit %q", u)
  1100  	ch := make(chan presence.Change)
  1101  	u.st.pwatcher.Watch(u.globalAgentKey(), ch)
  1102  	defer u.st.pwatcher.Unwatch(u.globalAgentKey(), ch)
  1103  	for i := 0; i < 2; i++ {
  1104  		select {
  1105  		case change := <-ch:
  1106  			if change.Alive {
  1107  				return nil
  1108  			}
  1109  		case <-time.After(timeout):
  1110  			// TODO(fwereade): 2016-03-17 lp:1558657
  1111  			return fmt.Errorf("still not alive after timeout")
  1112  		case <-u.st.pwatcher.Dead():
  1113  			return u.st.pwatcher.Err()
  1114  		}
  1115  	}
  1116  	panic(fmt.Sprintf("presence reported dead status twice in a row for unit %q", u))
  1117  }
  1118  
  1119  // SetAgentPresence signals that the agent for unit u is alive.
  1120  // It returns the started pinger.
  1121  func (u *Unit) SetAgentPresence() (*presence.Pinger, error) {
  1122  	presenceCollection := u.st.getPresence()
  1123  	p := presence.NewPinger(presenceCollection, u.st.ModelTag(), u.globalAgentKey())
  1124  	err := p.Start()
  1125  	if err != nil {
  1126  		return nil, err
  1127  	}
  1128  	return p, nil
  1129  }
  1130  
  1131  func unitNotAssignedError(u *Unit) error {
  1132  	msg := fmt.Sprintf("unit %q is not assigned to a machine", u)
  1133  	return errors.NewNotAssigned(nil, msg)
  1134  }
  1135  
  1136  // AssignedMachineId returns the id of the assigned machine.
  1137  func (u *Unit) AssignedMachineId() (id string, err error) {
  1138  	if u.IsPrincipal() {
  1139  		if u.doc.MachineId == "" {
  1140  			return "", unitNotAssignedError(u)
  1141  		}
  1142  		return u.doc.MachineId, nil
  1143  	}
  1144  
  1145  	units, closer := u.st.getCollection(unitsC)
  1146  	defer closer()
  1147  
  1148  	pudoc := unitDoc{}
  1149  	err = units.FindId(u.doc.Principal).One(&pudoc)
  1150  	if err == mgo.ErrNotFound {
  1151  		return "", errors.NotFoundf("principal unit %q of %q", u.doc.Principal, u)
  1152  	} else if err != nil {
  1153  		return "", err
  1154  	}
  1155  	if pudoc.MachineId == "" {
  1156  		return "", unitNotAssignedError(u)
  1157  	}
  1158  	return pudoc.MachineId, nil
  1159  }
  1160  
  1161  var (
  1162  	machineNotAliveErr = errors.New("machine is not alive")
  1163  	machineNotCleanErr = errors.New("machine is dirty")
  1164  	unitNotAliveErr    = errors.New("unit is not alive")
  1165  	alreadyAssignedErr = errors.New("unit is already assigned to a machine")
  1166  	inUseErr           = errors.New("machine is not unused")
  1167  )
  1168  
  1169  // assignToMachine is the internal version of AssignToMachine,
  1170  // also used by AssignToUnusedMachine. It returns specific errors
  1171  // in some cases:
  1172  // - machineNotAliveErr when the machine is not alive.
  1173  // - unitNotAliveErr when the unit is not alive.
  1174  // - alreadyAssignedErr when the unit has already been assigned
  1175  // - inUseErr when the machine already has a unit assigned (if unused is true)
  1176  func (u *Unit) assignToMachine(m *Machine, unused bool) (err error) {
  1177  	originalm := m
  1178  	buildTxn := func(attempt int) ([]txn.Op, error) {
  1179  		if attempt > 0 {
  1180  			m, err = u.st.Machine(m.Id())
  1181  			if err != nil {
  1182  				return nil, errors.Trace(err)
  1183  			}
  1184  		}
  1185  		return u.assignToMachineOps(m, unused)
  1186  	}
  1187  	if err := u.st.run(buildTxn); err != nil {
  1188  		// Don't wrap the error, as we want to return specific values
  1189  		// as described in the doc comment.
  1190  		return err
  1191  	}
  1192  	u.doc.MachineId = originalm.doc.Id
  1193  	originalm.doc.Clean = false
  1194  	return nil
  1195  }
  1196  
  1197  func (u *Unit) assignToMachineOps(m *Machine, unused bool) ([]txn.Op, error) {
  1198  	if u.Life() != Alive {
  1199  		return nil, unitNotAliveErr
  1200  	}
  1201  	if u.doc.MachineId != "" {
  1202  		if u.doc.MachineId != m.Id() {
  1203  			return nil, alreadyAssignedErr
  1204  		}
  1205  		return nil, jujutxn.ErrNoOperations
  1206  	}
  1207  	if unused && !m.doc.Clean {
  1208  		return nil, inUseErr
  1209  	}
  1210  	storageParams, err := u.machineStorageParams()
  1211  	if err != nil {
  1212  		return nil, errors.Trace(err)
  1213  	}
  1214  	storagePools, err := machineStoragePools(m.st, storageParams)
  1215  	if err != nil {
  1216  		return nil, errors.Trace(err)
  1217  	}
  1218  	if err := validateUnitMachineAssignment(
  1219  		m, u.doc.Series, u.doc.Principal != "", storagePools,
  1220  	); err != nil {
  1221  		return nil, errors.Trace(err)
  1222  	}
  1223  	storageOps, volumesAttached, filesystemsAttached, err := u.st.machineStorageOps(
  1224  		&m.doc, storageParams,
  1225  	)
  1226  	if err != nil {
  1227  		return nil, errors.Trace(err)
  1228  	}
  1229  	// addMachineStorageAttachmentsOps will add a txn.Op that ensures
  1230  	// that no filesystems were concurrently added to the machine if
  1231  	// any of the filesystems being attached specify a location.
  1232  	attachmentOps, err := addMachineStorageAttachmentsOps(
  1233  		m, volumesAttached, filesystemsAttached,
  1234  	)
  1235  	if err != nil {
  1236  		return nil, errors.Trace(err)
  1237  	}
  1238  	storageOps = append(storageOps, attachmentOps...)
  1239  
  1240  	assert := append(isAliveDoc, bson.D{
  1241  		{"$or", []bson.D{
  1242  			{{"machineid", ""}},
  1243  			{{"machineid", m.Id()}},
  1244  		}},
  1245  	}...)
  1246  	massert := isAliveDoc
  1247  	if unused {
  1248  		massert = append(massert, bson.D{{"clean", bson.D{{"$ne", false}}}}...)
  1249  	}
  1250  	ops := []txn.Op{{
  1251  		C:      unitsC,
  1252  		Id:     u.doc.DocID,
  1253  		Assert: assert,
  1254  		Update: bson.D{{"$set", bson.D{{"machineid", m.doc.Id}}}},
  1255  	}, {
  1256  		C:      machinesC,
  1257  		Id:     m.doc.DocID,
  1258  		Assert: massert,
  1259  		Update: bson.D{{"$addToSet", bson.D{{"principals", u.doc.Name}}}, {"$set", bson.D{{"clean", false}}}},
  1260  	},
  1261  		removeStagedAssignmentOp(u.doc.DocID),
  1262  	}
  1263  	ops = append(ops, storageOps...)
  1264  	return ops, nil
  1265  }
  1266  
  1267  // validateUnitMachineAssignment validates the parameters for assigning a unit
  1268  // to a specified machine.
  1269  func validateUnitMachineAssignment(
  1270  	m *Machine,
  1271  	series string,
  1272  	isSubordinate bool,
  1273  	storagePools set.Strings,
  1274  ) (err error) {
  1275  	if m.Life() != Alive {
  1276  		return machineNotAliveErr
  1277  	}
  1278  	if isSubordinate {
  1279  		return fmt.Errorf("unit is a subordinate")
  1280  	}
  1281  	if series != m.doc.Series {
  1282  		return fmt.Errorf("series does not match")
  1283  	}
  1284  	canHost := false
  1285  	for _, j := range m.doc.Jobs {
  1286  		if j == JobHostUnits {
  1287  			canHost = true
  1288  			break
  1289  		}
  1290  	}
  1291  	if !canHost {
  1292  		return fmt.Errorf("machine %q cannot host units", m)
  1293  	}
  1294  	if err := m.st.supportsUnitPlacement(); err != nil {
  1295  		return errors.Trace(err)
  1296  	}
  1297  	if err := validateDynamicMachineStoragePools(m, storagePools); err != nil {
  1298  		return errors.Trace(err)
  1299  	}
  1300  	return nil
  1301  }
  1302  
  1303  // validateDynamicMachineStorageParams validates that the provided machine
  1304  // storage parameters are compatible with the specified machine.
  1305  func validateDynamicMachineStorageParams(m *Machine, params *machineStorageParams) error {
  1306  	pools, err := machineStoragePools(m.st, params)
  1307  	if err != nil {
  1308  		return err
  1309  	}
  1310  	return validateDynamicMachineStoragePools(m, pools)
  1311  }
  1312  
  1313  // machineStoragePools returns the names of storage pools in each of the
  1314  // volume, filesystem and attachments in the machine storage parameters.
  1315  func machineStoragePools(st *State, params *machineStorageParams) (set.Strings, error) {
  1316  	pools := make(set.Strings)
  1317  	for _, v := range params.volumes {
  1318  		v, err := st.volumeParamsWithDefaults(v.Volume)
  1319  		if err != nil {
  1320  			return nil, errors.Trace(err)
  1321  		}
  1322  		pools.Add(v.Pool)
  1323  	}
  1324  	for _, f := range params.filesystems {
  1325  		f, err := st.filesystemParamsWithDefaults(f.Filesystem)
  1326  		if err != nil {
  1327  			return nil, errors.Trace(err)
  1328  		}
  1329  		pools.Add(f.Pool)
  1330  	}
  1331  	for volumeTag := range params.volumeAttachments {
  1332  		volume, err := st.Volume(volumeTag)
  1333  		if err != nil {
  1334  			return nil, errors.Trace(err)
  1335  		}
  1336  		if params, ok := volume.Params(); ok {
  1337  			pools.Add(params.Pool)
  1338  		} else {
  1339  			info, err := volume.Info()
  1340  			if err != nil {
  1341  				return nil, errors.Trace(err)
  1342  			}
  1343  			pools.Add(info.Pool)
  1344  		}
  1345  	}
  1346  	for filesystemTag := range params.filesystemAttachments {
  1347  		filesystem, err := st.Filesystem(filesystemTag)
  1348  		if err != nil {
  1349  			return nil, errors.Trace(err)
  1350  		}
  1351  		if params, ok := filesystem.Params(); ok {
  1352  			pools.Add(params.Pool)
  1353  		} else {
  1354  			info, err := filesystem.Info()
  1355  			if err != nil {
  1356  				return nil, errors.Trace(err)
  1357  			}
  1358  			pools.Add(info.Pool)
  1359  		}
  1360  	}
  1361  	return pools, nil
  1362  }
  1363  
  1364  // validateDynamicMachineStoragePools validates that all of the specified
  1365  // storage pools support dynamic storage provisioning. If any provider doesn't
  1366  // support dynamic storage, then an IsNotSupported error is returned.
  1367  func validateDynamicMachineStoragePools(m *Machine, pools set.Strings) error {
  1368  	if pools.IsEmpty() {
  1369  		return nil
  1370  	}
  1371  	if m.ContainerType() != "" {
  1372  		// TODO(axw) consult storage providers to check if they
  1373  		// support adding storage to containers. Loop is fine,
  1374  		// for example.
  1375  		//
  1376  		// TODO(axw) later we might allow *any* storage, and
  1377  		// passthrough/bindmount storage. That would imply either
  1378  		// container creation time only, or requiring containers
  1379  		// to be restarted to pick up new configuration.
  1380  		return errors.NotSupportedf("adding storage to %s container", m.ContainerType())
  1381  	}
  1382  	return validateDynamicStoragePools(m.st, pools)
  1383  }
  1384  
  1385  // validateDynamicStoragePools validates that all of the specified storage
  1386  // providers support dynamic storage provisioning. If any provider doesn't
  1387  // support dynamic storage, then an IsNotSupported error is returned.
  1388  func validateDynamicStoragePools(st *State, pools set.Strings) error {
  1389  	for pool := range pools {
  1390  		providerType, provider, err := poolStorageProvider(st, pool)
  1391  		if err != nil {
  1392  			return errors.Trace(err)
  1393  		}
  1394  		if !provider.Dynamic() {
  1395  			return errors.NewNotSupported(err, fmt.Sprintf(
  1396  				"%q storage provider does not support dynamic storage",
  1397  				providerType,
  1398  			))
  1399  		}
  1400  	}
  1401  	return nil
  1402  }
  1403  
  1404  func assignContextf(err *error, unitName string, target string) {
  1405  	if *err != nil {
  1406  		*err = errors.Annotatef(*err,
  1407  			"cannot assign unit %q to %s",
  1408  			unitName, target,
  1409  		)
  1410  	}
  1411  }
  1412  
  1413  // AssignToMachine assigns this unit to a given machine.
  1414  func (u *Unit) AssignToMachine(m *Machine) (err error) {
  1415  	defer assignContextf(&err, u.Name(), fmt.Sprintf("machine %s", m))
  1416  	return u.assignToMachine(m, false)
  1417  }
  1418  
  1419  // assignToNewMachine assigns the unit to a machine created according to
  1420  // the supplied params, with the supplied constraints.
  1421  func (u *Unit) assignToNewMachine(template MachineTemplate, parentId string, containerType instance.ContainerType) error {
  1422  	template.principals = []string{u.doc.Name}
  1423  	template.Dirty = true
  1424  
  1425  	var (
  1426  		mdoc *machineDoc
  1427  		ops  []txn.Op
  1428  		err  error
  1429  	)
  1430  	switch {
  1431  	case parentId == "" && containerType == "":
  1432  		mdoc, ops, err = u.st.addMachineOps(template)
  1433  	case parentId == "":
  1434  		if containerType == "" {
  1435  			return fmt.Errorf("assignToNewMachine called without container type (should never happen)")
  1436  		}
  1437  		// The new parent machine is clean and only hosts units,
  1438  		// regardless of its child.
  1439  		parentParams := template
  1440  		parentParams.Jobs = []MachineJob{JobHostUnits}
  1441  		mdoc, ops, err = u.st.addMachineInsideNewMachineOps(template, parentParams, containerType)
  1442  	default:
  1443  		// Container type is specified but no parent id.
  1444  		mdoc, ops, err = u.st.addMachineInsideMachineOps(template, parentId, containerType)
  1445  	}
  1446  	if err != nil {
  1447  		return err
  1448  	}
  1449  	// Ensure the host machine is really clean.
  1450  	if parentId != "" {
  1451  		parentDocId := u.st.docID(parentId)
  1452  		ops = append(ops, txn.Op{
  1453  			C:      machinesC,
  1454  			Id:     parentDocId,
  1455  			Assert: bson.D{{"clean", true}},
  1456  		}, txn.Op{
  1457  			C:      containerRefsC,
  1458  			Id:     parentDocId,
  1459  			Assert: bson.D{hasNoContainersTerm},
  1460  		})
  1461  	}
  1462  	isUnassigned := bson.D{{"machineid", ""}}
  1463  
  1464  	asserts := append(isAliveDoc, isUnassigned...)
  1465  	ops = append(ops, txn.Op{
  1466  		C:      unitsC,
  1467  		Id:     u.doc.DocID,
  1468  		Assert: asserts,
  1469  		Update: bson.D{{"$set", bson.D{{"machineid", mdoc.Id}}}},
  1470  	},
  1471  		removeStagedAssignmentOp(u.doc.DocID),
  1472  	)
  1473  
  1474  	err = u.st.runTransaction(ops)
  1475  	if err == nil {
  1476  		u.doc.MachineId = mdoc.Id
  1477  		return nil
  1478  	} else if err != txn.ErrAborted {
  1479  		return err
  1480  	}
  1481  
  1482  	// If we assume that the machine ops will never give us an
  1483  	// operation that would fail (because the machine id(s) that it
  1484  	// chooses are unique), then the only reasons that the
  1485  	// transaction could have been aborted are:
  1486  	//  * the unit is no longer alive
  1487  	//  * the unit has been assigned to a different machine
  1488  	//  * the parent machine we want to create a container on was
  1489  	//  clean but became dirty
  1490  	unit, err := u.st.Unit(u.Name())
  1491  	if err != nil {
  1492  		return err
  1493  	}
  1494  	switch {
  1495  	case unit.Life() != Alive:
  1496  		return unitNotAliveErr
  1497  	case unit.doc.MachineId != "":
  1498  		return alreadyAssignedErr
  1499  	}
  1500  	if parentId == "" {
  1501  		return fmt.Errorf("cannot add top level machine: transaction aborted for unknown reason")
  1502  	}
  1503  	m, err := u.st.Machine(parentId)
  1504  	if err != nil {
  1505  		return err
  1506  	}
  1507  	if !m.Clean() {
  1508  		return machineNotCleanErr
  1509  	}
  1510  	containers, err := m.Containers()
  1511  	if err != nil {
  1512  		return err
  1513  	}
  1514  	if len(containers) > 0 {
  1515  		return machineNotCleanErr
  1516  	}
  1517  	return fmt.Errorf("cannot add container within machine: transaction aborted for unknown reason")
  1518  }
  1519  
  1520  // Constraints returns the unit's deployment constraints.
  1521  func (u *Unit) Constraints() (*constraints.Value, error) {
  1522  	cons, err := readConstraints(u.st, u.globalAgentKey())
  1523  	if errors.IsNotFound(err) {
  1524  		// Lack of constraints indicates lack of unit.
  1525  		return nil, errors.NotFoundf("unit")
  1526  	} else if err != nil {
  1527  		return nil, err
  1528  	}
  1529  	return &cons, nil
  1530  }
  1531  
  1532  // AssignToNewMachineOrContainer assigns the unit to a new machine,
  1533  // with constraints determined according to the service and
  1534  // model constraints at the time of unit creation. If a
  1535  // container is required, a clean, empty machine instance is required
  1536  // on which to create the container. An existing clean, empty instance
  1537  // is first searched for, and if not found, a new one is created.
  1538  func (u *Unit) AssignToNewMachineOrContainer() (err error) {
  1539  	defer assignContextf(&err, u.Name(), "new machine or container")
  1540  	if u.doc.Principal != "" {
  1541  		return fmt.Errorf("unit is a subordinate")
  1542  	}
  1543  	cons, err := u.Constraints()
  1544  	if err != nil {
  1545  		return err
  1546  	}
  1547  	if !cons.HasContainer() {
  1548  		return u.AssignToNewMachine()
  1549  	}
  1550  
  1551  	// Find a clean, empty machine on which to create a container.
  1552  	hostCons := *cons
  1553  	noContainer := instance.NONE
  1554  	hostCons.Container = &noContainer
  1555  	query, err := u.findCleanMachineQuery(true, &hostCons)
  1556  	if err != nil {
  1557  		return err
  1558  	}
  1559  	machinesCollection, closer := u.st.getCollection(machinesC)
  1560  	defer closer()
  1561  	var host machineDoc
  1562  	if err := machinesCollection.Find(query).One(&host); err == mgo.ErrNotFound {
  1563  		// No existing clean, empty machine so create a new one.
  1564  		// The container constraint will be used by AssignToNewMachine to create the required container.
  1565  		return u.AssignToNewMachine()
  1566  	} else if err != nil {
  1567  		return err
  1568  	}
  1569  
  1570  	template := MachineTemplate{
  1571  		Series:      u.doc.Series,
  1572  		Constraints: *cons,
  1573  		Jobs:        []MachineJob{JobHostUnits},
  1574  	}
  1575  	err = u.assignToNewMachine(template, host.Id, *cons.Container)
  1576  	if err == machineNotCleanErr {
  1577  		// The clean machine was used before we got a chance to use it so just
  1578  		// stick the unit on a new machine.
  1579  		return u.AssignToNewMachine()
  1580  	}
  1581  	return err
  1582  }
  1583  
  1584  // AssignToNewMachine assigns the unit to a new machine, with constraints
  1585  // determined according to the service and model constraints at the
  1586  // time of unit creation.
  1587  func (u *Unit) AssignToNewMachine() (err error) {
  1588  	defer assignContextf(&err, u.Name(), "new machine")
  1589  	if u.doc.Principal != "" {
  1590  		return fmt.Errorf("unit is a subordinate")
  1591  	}
  1592  	// Get the ops necessary to create a new machine, and the machine doc that
  1593  	// will be added with those operations (which includes the machine id).
  1594  	cons, err := u.Constraints()
  1595  	if err != nil {
  1596  		return err
  1597  	}
  1598  	var containerType instance.ContainerType
  1599  	// Configure to create a new container if required.
  1600  	if cons.HasContainer() {
  1601  		containerType = *cons.Container
  1602  	}
  1603  	storageParams, err := u.machineStorageParams()
  1604  	if err != nil {
  1605  		return errors.Trace(err)
  1606  	}
  1607  	template := MachineTemplate{
  1608  		Series:                u.doc.Series,
  1609  		Constraints:           *cons,
  1610  		Jobs:                  []MachineJob{JobHostUnits},
  1611  		Volumes:               storageParams.volumes,
  1612  		VolumeAttachments:     storageParams.volumeAttachments,
  1613  		Filesystems:           storageParams.filesystems,
  1614  		FilesystemAttachments: storageParams.filesystemAttachments,
  1615  	}
  1616  	return u.assignToNewMachine(template, "", containerType)
  1617  }
  1618  
  1619  // machineStorageParams returns parameters for creating volumes/filesystems
  1620  // and volume/filesystem attachments for a machine that the unit will be
  1621  // assigned to.
  1622  func (u *Unit) machineStorageParams() (*machineStorageParams, error) {
  1623  	storageAttachments, err := u.st.UnitStorageAttachments(u.UnitTag())
  1624  	if err != nil {
  1625  		return nil, errors.Annotate(err, "getting storage attachments")
  1626  	}
  1627  	svc, err := u.Service()
  1628  	if err != nil {
  1629  		return nil, errors.Trace(err)
  1630  	}
  1631  	curl, _ := svc.CharmURL()
  1632  	if curl == nil {
  1633  		return nil, errors.Errorf("no URL set for service %q", svc.Name())
  1634  	}
  1635  	ch, err := u.st.Charm(curl)
  1636  	if err != nil {
  1637  		return nil, errors.Annotate(err, "getting charm")
  1638  	}
  1639  	allCons, err := u.StorageConstraints()
  1640  	if err != nil {
  1641  		return nil, errors.Annotatef(err, "getting storage constraints")
  1642  	}
  1643  
  1644  	chMeta := ch.Meta()
  1645  
  1646  	var volumes []MachineVolumeParams
  1647  	var filesystems []MachineFilesystemParams
  1648  	volumeAttachments := make(map[names.VolumeTag]VolumeAttachmentParams)
  1649  	filesystemAttachments := make(map[names.FilesystemTag]FilesystemAttachmentParams)
  1650  	for _, storageAttachment := range storageAttachments {
  1651  		storage, err := u.st.StorageInstance(storageAttachment.StorageInstance())
  1652  		if err != nil {
  1653  			return nil, errors.Annotatef(err, "getting storage instance")
  1654  		}
  1655  		machineParams, err := machineStorageParamsForStorageInstance(
  1656  			u.st, chMeta, u.UnitTag(), u.Series(), allCons, storage,
  1657  		)
  1658  		if err != nil {
  1659  			return nil, errors.Trace(err)
  1660  		}
  1661  
  1662  		volumes = append(volumes, machineParams.volumes...)
  1663  		for k, v := range machineParams.volumeAttachments {
  1664  			volumeAttachments[k] = v
  1665  		}
  1666  
  1667  		filesystems = append(filesystems, machineParams.filesystems...)
  1668  		for k, v := range machineParams.filesystemAttachments {
  1669  			filesystemAttachments[k] = v
  1670  		}
  1671  	}
  1672  	result := &machineStorageParams{
  1673  		volumes,
  1674  		volumeAttachments,
  1675  		filesystems,
  1676  		filesystemAttachments,
  1677  	}
  1678  	return result, nil
  1679  }
  1680  
  1681  // machineStorageParamsForStorageInstance returns parameters for creating
  1682  // volumes/filesystems and volume/filesystem attachments for a machine that
  1683  // the unit will be assigned to. These parameters are based on a given storage
  1684  // instance.
  1685  func machineStorageParamsForStorageInstance(
  1686  	st *State,
  1687  	charmMeta *charm.Meta,
  1688  	unit names.UnitTag,
  1689  	series string,
  1690  	allCons map[string]StorageConstraints,
  1691  	storage StorageInstance,
  1692  ) (*machineStorageParams, error) {
  1693  
  1694  	charmStorage := charmMeta.Storage[storage.StorageName()]
  1695  
  1696  	var volumes []MachineVolumeParams
  1697  	var filesystems []MachineFilesystemParams
  1698  	volumeAttachments := make(map[names.VolumeTag]VolumeAttachmentParams)
  1699  	filesystemAttachments := make(map[names.FilesystemTag]FilesystemAttachmentParams)
  1700  
  1701  	switch storage.Kind() {
  1702  	case StorageKindBlock:
  1703  		volumeAttachmentParams := VolumeAttachmentParams{
  1704  			charmStorage.ReadOnly,
  1705  		}
  1706  		if unit == storage.Owner() {
  1707  			// The storage instance is owned by the unit, so we'll need
  1708  			// to create a volume.
  1709  			cons := allCons[storage.StorageName()]
  1710  			volumeParams := VolumeParams{
  1711  				storage: storage.StorageTag(),
  1712  				binding: storage.StorageTag(),
  1713  				Pool:    cons.Pool,
  1714  				Size:    cons.Size,
  1715  			}
  1716  			volumes = append(volumes, MachineVolumeParams{
  1717  				volumeParams, volumeAttachmentParams,
  1718  			})
  1719  		} else {
  1720  			// The storage instance is owned by the service, so there
  1721  			// should be a (shared) volume already, for which we will
  1722  			// just add an attachment.
  1723  			volume, err := st.StorageInstanceVolume(storage.StorageTag())
  1724  			if err != nil {
  1725  				return nil, errors.Annotatef(err, "getting volume for storage %q", storage.Tag().Id())
  1726  			}
  1727  			volumeAttachments[volume.VolumeTag()] = volumeAttachmentParams
  1728  		}
  1729  	case StorageKindFilesystem:
  1730  		location, err := filesystemMountPoint(charmStorage, storage.StorageTag(), series)
  1731  		if err != nil {
  1732  			return nil, errors.Annotatef(
  1733  				err, "getting filesystem mount point for storage %s",
  1734  				storage.StorageName(),
  1735  			)
  1736  		}
  1737  		filesystemAttachmentParams := FilesystemAttachmentParams{
  1738  			charmStorage.Location == "", // auto-generated location
  1739  			location,
  1740  			charmStorage.ReadOnly,
  1741  		}
  1742  		if unit == storage.Owner() {
  1743  			// The storage instance is owned by the unit, so we'll need
  1744  			// to create a filesystem.
  1745  			cons := allCons[storage.StorageName()]
  1746  			filesystemParams := FilesystemParams{
  1747  				storage: storage.StorageTag(),
  1748  				binding: storage.StorageTag(),
  1749  				Pool:    cons.Pool,
  1750  				Size:    cons.Size,
  1751  			}
  1752  			filesystems = append(filesystems, MachineFilesystemParams{
  1753  				filesystemParams, filesystemAttachmentParams,
  1754  			})
  1755  		} else {
  1756  			// The storage instance is owned by the service, so there
  1757  			// should be a (shared) filesystem already, for which we will
  1758  			// just add an attachment.
  1759  			filesystem, err := st.StorageInstanceFilesystem(storage.StorageTag())
  1760  			if err != nil {
  1761  				return nil, errors.Annotatef(err, "getting filesystem for storage %q", storage.Tag().Id())
  1762  			}
  1763  			filesystemAttachments[filesystem.FilesystemTag()] = filesystemAttachmentParams
  1764  		}
  1765  	default:
  1766  		return nil, errors.Errorf("invalid storage kind %v", storage.Kind())
  1767  	}
  1768  	result := &machineStorageParams{
  1769  		volumes,
  1770  		volumeAttachments,
  1771  		filesystems,
  1772  		filesystemAttachments,
  1773  	}
  1774  	return result, nil
  1775  }
  1776  
  1777  var noCleanMachines = errors.New("all eligible machines in use")
  1778  
  1779  // AssignToCleanMachine assigns u to a machine which is marked as clean. A machine
  1780  // is clean if it has never had any principal units assigned to it.
  1781  // If there are no clean machines besides any machine(s) running JobHostEnviron,
  1782  // an error is returned.
  1783  // This method does not take constraints into consideration when choosing a
  1784  // machine (lp:1161919).
  1785  func (u *Unit) AssignToCleanMachine() (m *Machine, err error) {
  1786  	return u.assignToCleanMaybeEmptyMachine(false)
  1787  }
  1788  
  1789  // AssignToCleanEmptyMachine assigns u to a machine which is marked as clean and is also
  1790  // not hosting any containers. A machine is clean if it has never had any principal units
  1791  // assigned to it. If there are no clean machines besides any machine(s) running JobHostEnviron,
  1792  // an error is returned.
  1793  // This method does not take constraints into consideration when choosing a
  1794  // machine (lp:1161919).
  1795  func (u *Unit) AssignToCleanEmptyMachine() (m *Machine, err error) {
  1796  	return u.assignToCleanMaybeEmptyMachine(true)
  1797  }
  1798  
  1799  var hasContainerTerm = bson.DocElem{
  1800  	"$and", []bson.D{
  1801  		{{"children", bson.D{{"$not", bson.D{{"$size", 0}}}}}},
  1802  		{{"children", bson.D{{"$exists", true}}}},
  1803  	}}
  1804  
  1805  var hasNoContainersTerm = bson.DocElem{
  1806  	"$or", []bson.D{
  1807  		{{"children", bson.D{{"$size", 0}}}},
  1808  		{{"children", bson.D{{"$exists", false}}}},
  1809  	}}
  1810  
  1811  // findCleanMachineQuery returns a Mongo query to find clean (and possibly empty) machines with
  1812  // characteristics matching the specified constraints.
  1813  func (u *Unit) findCleanMachineQuery(requireEmpty bool, cons *constraints.Value) (bson.D, error) {
  1814  	db, closer := u.st.newDB()
  1815  	defer closer()
  1816  	containerRefsCollection, closer := db.GetCollection(containerRefsC)
  1817  	defer closer()
  1818  
  1819  	// Select all machines that can accept principal units and are clean.
  1820  	var containerRefs []machineContainers
  1821  	// If we need empty machines, first build up a list of machine ids which have containers
  1822  	// so we can exclude those.
  1823  	if requireEmpty {
  1824  		err := containerRefsCollection.Find(bson.D{hasContainerTerm}).All(&containerRefs)
  1825  		if err != nil {
  1826  			return nil, err
  1827  		}
  1828  	}
  1829  	var machinesWithContainers = make([]string, len(containerRefs))
  1830  	for i, cref := range containerRefs {
  1831  		machinesWithContainers[i] = cref.Id
  1832  	}
  1833  	terms := bson.D{
  1834  		{"life", Alive},
  1835  		{"series", u.doc.Series},
  1836  		{"jobs", []MachineJob{JobHostUnits}},
  1837  		{"clean", true},
  1838  		{"machineid", bson.D{{"$nin", machinesWithContainers}}},
  1839  	}
  1840  	// Add the container filter term if necessary.
  1841  	var containerType instance.ContainerType
  1842  	if cons.Container != nil {
  1843  		containerType = *cons.Container
  1844  	}
  1845  	if containerType == instance.NONE {
  1846  		terms = append(terms, bson.DocElem{"containertype", ""})
  1847  	} else if containerType != "" {
  1848  		terms = append(terms, bson.DocElem{"containertype", string(containerType)})
  1849  	}
  1850  
  1851  	// Find the ids of machines which satisfy any required hardware
  1852  	// constraints. If there is no instanceData for a machine, that
  1853  	// machine is not considered as suitable for deploying the unit.
  1854  	// This can happen if the machine is not yet provisioned. It may
  1855  	// be that when the machine is provisioned it will be found to
  1856  	// be suitable, but we don't know that right now and it's best
  1857  	// to err on the side of caution and exclude such machines.
  1858  	var suitableInstanceData []instanceData
  1859  	var suitableTerms bson.D
  1860  	if cons.Arch != nil && *cons.Arch != "" {
  1861  		suitableTerms = append(suitableTerms, bson.DocElem{"arch", *cons.Arch})
  1862  	}
  1863  	if cons.Mem != nil && *cons.Mem > 0 {
  1864  		suitableTerms = append(suitableTerms, bson.DocElem{"mem", bson.D{{"$gte", *cons.Mem}}})
  1865  	}
  1866  	if cons.RootDisk != nil && *cons.RootDisk > 0 {
  1867  		suitableTerms = append(suitableTerms, bson.DocElem{"rootdisk", bson.D{{"$gte", *cons.RootDisk}}})
  1868  	}
  1869  	if cons.CpuCores != nil && *cons.CpuCores > 0 {
  1870  		suitableTerms = append(suitableTerms, bson.DocElem{"cpucores", bson.D{{"$gte", *cons.CpuCores}}})
  1871  	}
  1872  	if cons.CpuPower != nil && *cons.CpuPower > 0 {
  1873  		suitableTerms = append(suitableTerms, bson.DocElem{"cpupower", bson.D{{"$gte", *cons.CpuPower}}})
  1874  	}
  1875  	if cons.Tags != nil && len(*cons.Tags) > 0 {
  1876  		suitableTerms = append(suitableTerms, bson.DocElem{"tags", bson.D{{"$all", *cons.Tags}}})
  1877  	}
  1878  	if len(suitableTerms) > 0 {
  1879  		instanceDataCollection, closer := db.GetCollection(instanceDataC)
  1880  		defer closer()
  1881  		err := instanceDataCollection.Find(suitableTerms).Select(bson.M{"_id": 1}).All(&suitableInstanceData)
  1882  		if err != nil {
  1883  			return nil, err
  1884  		}
  1885  		var suitableIds = make([]string, len(suitableInstanceData))
  1886  		for i, m := range suitableInstanceData {
  1887  			suitableIds[i] = m.DocID
  1888  		}
  1889  		terms = append(terms, bson.DocElem{"_id", bson.D{{"$in", suitableIds}}})
  1890  	}
  1891  	return terms, nil
  1892  }
  1893  
  1894  // assignToCleanMaybeEmptyMachine implements AssignToCleanMachine and AssignToCleanEmptyMachine.
  1895  // A 'machine' may be a machine instance or container depending on the service constraints.
  1896  func (u *Unit) assignToCleanMaybeEmptyMachine(requireEmpty bool) (m *Machine, err error) {
  1897  	context := "clean"
  1898  	if requireEmpty {
  1899  		context += ", empty"
  1900  	}
  1901  	context += " machine"
  1902  
  1903  	if u.doc.Principal != "" {
  1904  		err = fmt.Errorf("unit is a subordinate")
  1905  		assignContextf(&err, u.Name(), context)
  1906  		return nil, err
  1907  	}
  1908  
  1909  	// If required storage is not all dynamic, then assigning
  1910  	// to a new machine is required.
  1911  	storageParams, err := u.machineStorageParams()
  1912  	if err != nil {
  1913  		assignContextf(&err, u.Name(), context)
  1914  		return nil, err
  1915  	}
  1916  	storagePools, err := machineStoragePools(u.st, storageParams)
  1917  	if err != nil {
  1918  		assignContextf(&err, u.Name(), context)
  1919  		return nil, err
  1920  	}
  1921  	if err := validateDynamicStoragePools(u.st, storagePools); err != nil {
  1922  		if errors.IsNotSupported(err) {
  1923  			return nil, noCleanMachines
  1924  		}
  1925  		assignContextf(&err, u.Name(), context)
  1926  		return nil, err
  1927  	}
  1928  
  1929  	// Get the unit constraints to see what deployment requirements we have to adhere to.
  1930  	cons, err := u.Constraints()
  1931  	if err != nil {
  1932  		assignContextf(&err, u.Name(), context)
  1933  		return nil, err
  1934  	}
  1935  	query, err := u.findCleanMachineQuery(requireEmpty, cons)
  1936  	if err != nil {
  1937  		assignContextf(&err, u.Name(), context)
  1938  		return nil, err
  1939  	}
  1940  
  1941  	// Find all of the candidate machines, and associated
  1942  	// instances for those that are provisioned. Instances
  1943  	// will be distributed across in preference to
  1944  	// unprovisioned machines.
  1945  	machinesCollection, closer := u.st.getCollection(machinesC)
  1946  	defer closer()
  1947  	var mdocs []*machineDoc
  1948  	if err := machinesCollection.Find(query).All(&mdocs); err != nil {
  1949  		assignContextf(&err, u.Name(), context)
  1950  		return nil, err
  1951  	}
  1952  	var unprovisioned []*Machine
  1953  	var instances []instance.Id
  1954  	instanceMachines := make(map[instance.Id]*Machine)
  1955  	for _, mdoc := range mdocs {
  1956  		m := newMachine(u.st, mdoc)
  1957  		instance, err := m.InstanceId()
  1958  		if errors.IsNotProvisioned(err) {
  1959  			unprovisioned = append(unprovisioned, m)
  1960  		} else if err != nil {
  1961  			assignContextf(&err, u.Name(), context)
  1962  			return nil, err
  1963  		} else {
  1964  			instances = append(instances, instance)
  1965  			instanceMachines[instance] = m
  1966  		}
  1967  	}
  1968  
  1969  	// Filter the list of instances that are suitable for
  1970  	// distribution, and then map them back to machines.
  1971  	//
  1972  	// TODO(axw) 2014-05-30 #1324904
  1973  	// Shuffle machines to reduce likelihood of collisions.
  1974  	// The partition of provisioned/unprovisioned machines
  1975  	// must be maintained.
  1976  	if instances, err = distributeUnit(u, instances); err != nil {
  1977  		assignContextf(&err, u.Name(), context)
  1978  		return nil, err
  1979  	}
  1980  	machines := make([]*Machine, len(instances), len(instances)+len(unprovisioned))
  1981  	for i, instance := range instances {
  1982  		m, ok := instanceMachines[instance]
  1983  		if !ok {
  1984  			err := fmt.Errorf("invalid instance returned: %v", instance)
  1985  			assignContextf(&err, u.Name(), context)
  1986  			return nil, err
  1987  		}
  1988  		machines[i] = m
  1989  	}
  1990  	machines = append(machines, unprovisioned...)
  1991  
  1992  	// TODO(axw) 2014-05-30 #1253704
  1993  	// We should not select a machine that is in the process
  1994  	// of being provisioned. There's no point asserting that
  1995  	// the machine hasn't been provisioned, as there'll still
  1996  	// be a period of time during which the machine may be
  1997  	// provisioned without the fact having yet been recorded
  1998  	// in state.
  1999  	for _, m := range machines {
  2000  		// Check that the unit storage is compatible with
  2001  		// the machine in question.
  2002  		if err := validateDynamicMachineStorageParams(m, storageParams); err != nil {
  2003  			if errors.IsNotSupported(err) {
  2004  				continue
  2005  			}
  2006  			assignContextf(&err, u.Name(), context)
  2007  			return nil, err
  2008  		}
  2009  		err := u.assignToMachine(m, true)
  2010  		if err == nil {
  2011  			return m, nil
  2012  		}
  2013  		switch errors.Cause(err) {
  2014  		case inUseErr, machineNotAliveErr:
  2015  		default:
  2016  			assignContextf(&err, u.Name(), context)
  2017  			return nil, err
  2018  		}
  2019  	}
  2020  	return nil, noCleanMachines
  2021  }
  2022  
  2023  // UnassignFromMachine removes the assignment between this unit and the
  2024  // machine it's assigned to.
  2025  func (u *Unit) UnassignFromMachine() (err error) {
  2026  	// TODO check local machine id and add an assert that the
  2027  	// machine id is as expected.
  2028  	ops := []txn.Op{{
  2029  		C:      unitsC,
  2030  		Id:     u.doc.DocID,
  2031  		Assert: txn.DocExists,
  2032  		Update: bson.D{{"$set", bson.D{{"machineid", ""}}}},
  2033  	}}
  2034  	if u.doc.MachineId != "" {
  2035  		ops = append(ops, txn.Op{
  2036  			C:      machinesC,
  2037  			Id:     u.st.docID(u.doc.MachineId),
  2038  			Assert: txn.DocExists,
  2039  			Update: bson.D{{"$pull", bson.D{{"principals", u.doc.Name}}}},
  2040  		})
  2041  	}
  2042  	err = u.st.runTransaction(ops)
  2043  	if err != nil {
  2044  		return fmt.Errorf("cannot unassign unit %q from machine: %v", u, onAbort(err, errors.NotFoundf("machine")))
  2045  	}
  2046  	u.doc.MachineId = ""
  2047  	return nil
  2048  }
  2049  
  2050  // ActionSpecsByName is a map of action names to their respective ActionSpec.
  2051  type ActionSpecsByName map[string]charm.ActionSpec
  2052  
  2053  // AddAction adds a new Action of type name and using arguments payload to
  2054  // this Unit, and returns its ID.  Note that the use of spec.InsertDefaults
  2055  // mutates payload.
  2056  func (u *Unit) AddAction(name string, payload map[string]interface{}) (Action, error) {
  2057  	if len(name) == 0 {
  2058  		return nil, errors.New("no action name given")
  2059  	}
  2060  
  2061  	// If the action is predefined inside juju, get spec from map
  2062  	spec, ok := actions.PredefinedActionsSpec[name]
  2063  	if !ok {
  2064  		specs, err := u.ActionSpecs()
  2065  		if err != nil {
  2066  			return nil, err
  2067  		}
  2068  		spec, ok = specs[name]
  2069  		if !ok {
  2070  			return nil, errors.Errorf("action %q not defined on unit %q", name, u.Name())
  2071  		}
  2072  	}
  2073  	// Reject bad payloads before attempting to insert defaults.
  2074  	err := spec.ValidateParams(payload)
  2075  	if err != nil {
  2076  		return nil, err
  2077  	}
  2078  	payloadWithDefaults, err := spec.InsertDefaults(payload)
  2079  	if err != nil {
  2080  		return nil, err
  2081  	}
  2082  	return u.st.EnqueueAction(u.Tag(), name, payloadWithDefaults)
  2083  }
  2084  
  2085  // ActionSpecs gets the ActionSpec map for the Unit's charm.
  2086  func (u *Unit) ActionSpecs() (ActionSpecsByName, error) {
  2087  	none := ActionSpecsByName{}
  2088  	curl, _ := u.CharmURL()
  2089  	if curl == nil {
  2090  		// If unit charm URL is not yet set, fall back to service
  2091  		svc, err := u.Service()
  2092  		if err != nil {
  2093  			return none, err
  2094  		}
  2095  		curl, _ = svc.CharmURL()
  2096  		if curl == nil {
  2097  			return none, errors.Errorf("no URL set for service %q", svc.Name())
  2098  		}
  2099  	}
  2100  	ch, err := u.st.Charm(curl)
  2101  	if err != nil {
  2102  		return none, errors.Annotatef(err, "unable to get charm with URL %q", curl.String())
  2103  	}
  2104  	chActions := ch.Actions()
  2105  	if chActions == nil || len(chActions.ActionSpecs) == 0 {
  2106  		return none, errors.Errorf("no actions defined on charm %q", ch.String())
  2107  	}
  2108  	return chActions.ActionSpecs, nil
  2109  }
  2110  
  2111  // CancelAction removes a pending Action from the queue for this
  2112  // ActionReceiver and marks it as cancelled.
  2113  func (u *Unit) CancelAction(action Action) (Action, error) {
  2114  	return action.Finish(ActionResults{Status: ActionCancelled})
  2115  }
  2116  
  2117  // WatchActionNotifications starts and returns a StringsWatcher that
  2118  // notifies when actions with Id prefixes matching this Unit are added
  2119  func (u *Unit) WatchActionNotifications() StringsWatcher {
  2120  	return u.st.watchEnqueuedActionsFilteredBy(u)
  2121  }
  2122  
  2123  // Actions returns a list of actions pending or completed for this unit.
  2124  func (u *Unit) Actions() ([]Action, error) {
  2125  	return u.st.matchingActions(u)
  2126  }
  2127  
  2128  // CompletedActions returns a list of actions that have finished for
  2129  // this unit.
  2130  func (u *Unit) CompletedActions() ([]Action, error) {
  2131  	return u.st.matchingActionsCompleted(u)
  2132  }
  2133  
  2134  // PendingActions returns a list of actions pending for this unit.
  2135  func (u *Unit) PendingActions() ([]Action, error) {
  2136  	return u.st.matchingActionsPending(u)
  2137  }
  2138  
  2139  // RunningActions returns a list of actions running on this unit.
  2140  func (u *Unit) RunningActions() ([]Action, error) {
  2141  	return u.st.matchingActionsRunning(u)
  2142  }
  2143  
  2144  // Resolve marks the unit as having had any previous state transition
  2145  // problems resolved, and informs the unit that it may attempt to
  2146  // reestablish normal workflow. The retryHooks parameter informs
  2147  // whether to attempt to reexecute previous failed hooks or to continue
  2148  // as if they had succeeded before.
  2149  func (u *Unit) Resolve(retryHooks bool) error {
  2150  	// We currently check agent status to see if a unit is
  2151  	// in error state. As the new Juju Health work is completed,
  2152  	// this will change to checking the unit status.
  2153  	statusInfo, err := u.Status()
  2154  	if err != nil {
  2155  		return err
  2156  	}
  2157  	if statusInfo.Status != status.StatusError {
  2158  		return errors.Errorf("unit %q is not in an error state", u)
  2159  	}
  2160  	mode := ResolvedNoHooks
  2161  	if retryHooks {
  2162  		mode = ResolvedRetryHooks
  2163  	}
  2164  	return u.SetResolved(mode)
  2165  }
  2166  
  2167  // SetResolved marks the unit as having had any previous state transition
  2168  // problems resolved, and informs the unit that it may attempt to
  2169  // reestablish normal workflow. The resolved mode parameter informs
  2170  // whether to attempt to reexecute previous failed hooks or to continue
  2171  // as if they had succeeded before.
  2172  func (u *Unit) SetResolved(mode ResolvedMode) (err error) {
  2173  	defer errors.DeferredAnnotatef(&err, "cannot set resolved mode for unit %q", u)
  2174  	switch mode {
  2175  	case ResolvedRetryHooks, ResolvedNoHooks:
  2176  	default:
  2177  		return fmt.Errorf("invalid error resolution mode: %q", mode)
  2178  	}
  2179  	// TODO(fwereade): assert unit has error status.
  2180  	resolvedNotSet := bson.D{{"resolved", ResolvedNone}}
  2181  	ops := []txn.Op{{
  2182  		C:      unitsC,
  2183  		Id:     u.doc.DocID,
  2184  		Assert: append(notDeadDoc, resolvedNotSet...),
  2185  		Update: bson.D{{"$set", bson.D{{"resolved", mode}}}},
  2186  	}}
  2187  	if err := u.st.runTransaction(ops); err == nil {
  2188  		u.doc.Resolved = mode
  2189  		return nil
  2190  	} else if err != txn.ErrAborted {
  2191  		return err
  2192  	}
  2193  	if ok, err := isNotDead(u.st, unitsC, u.doc.DocID); err != nil {
  2194  		return err
  2195  	} else if !ok {
  2196  		return ErrDead
  2197  	}
  2198  	// For now, the only remaining assert is that resolved was unset.
  2199  	return fmt.Errorf("already resolved")
  2200  }
  2201  
  2202  // ClearResolved removes any resolved setting on the unit.
  2203  func (u *Unit) ClearResolved() error {
  2204  	ops := []txn.Op{{
  2205  		C:      unitsC,
  2206  		Id:     u.doc.DocID,
  2207  		Assert: txn.DocExists,
  2208  		Update: bson.D{{"$set", bson.D{{"resolved", ResolvedNone}}}},
  2209  	}}
  2210  	err := u.st.runTransaction(ops)
  2211  	if err != nil {
  2212  		return fmt.Errorf("cannot clear resolved mode for unit %q: %v", u, errors.NotFoundf("unit"))
  2213  	}
  2214  	u.doc.Resolved = ResolvedNone
  2215  	return nil
  2216  }
  2217  
  2218  // StorageConstraints returns the unit's storage constraints.
  2219  func (u *Unit) StorageConstraints() (map[string]StorageConstraints, error) {
  2220  	// TODO(axw) eventually we should be able to override service
  2221  	// storage constraints at the unit level.
  2222  	return readStorageConstraints(u.st, serviceGlobalKey(u.doc.Service))
  2223  }
  2224  
  2225  type addUnitOpsArgs struct {
  2226  	unitDoc           *unitDoc
  2227  	agentStatusDoc    statusDoc
  2228  	workloadStatusDoc statusDoc
  2229  	meterStatusDoc    *meterStatusDoc
  2230  }
  2231  
  2232  // addUnitOps returns the operations required to add a unit to the units
  2233  // collection, along with all the associated expected other unit entries. This
  2234  // method is used by both the *Service.addUnitOpsWithCons method and the
  2235  // migration import code.
  2236  func addUnitOps(st *State, args addUnitOpsArgs) []txn.Op {
  2237  	name := args.unitDoc.Name
  2238  	agentGlobalKey := unitAgentGlobalKey(name)
  2239  	// TODO: consider the constraints op
  2240  	// TODO: consider storageOps
  2241  	return []txn.Op{
  2242  		createStatusOp(st, unitGlobalKey(name), args.workloadStatusDoc),
  2243  		createStatusOp(st, agentGlobalKey, args.agentStatusDoc),
  2244  		createMeterStatusOp(st, agentGlobalKey, args.meterStatusDoc),
  2245  		{
  2246  			C:      unitsC,
  2247  			Id:     name,
  2248  			Assert: txn.DocMissing,
  2249  			Insert: args.unitDoc,
  2250  		},
  2251  	}
  2252  }