launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/state/unit.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state
     5  
     6  import (
     7  	"fmt"
     8  	errgo "launchpad.net/errgo/errors"
     9  	"time"
    10  
    11  	"github.com/loggo/loggo"
    12  	"labix.org/v2/mgo"
    13  	"labix.org/v2/mgo/bson"
    14  	"labix.org/v2/mgo/txn"
    15  
    16  	"launchpad.net/juju-core/charm"
    17  	"launchpad.net/juju-core/constraints"
    18  	"launchpad.net/juju-core/errors"
    19  	"launchpad.net/juju-core/instance"
    20  	"launchpad.net/juju-core/names"
    21  	"launchpad.net/juju-core/state/api/params"
    22  	"launchpad.net/juju-core/state/presence"
    23  	"launchpad.net/juju-core/tools"
    24  	"launchpad.net/juju-core/utils"
    25  	"launchpad.net/juju-core/version"
    26  )
    27  
    28  var unitLogger = loggo.GetLogger("juju.state.unit")
    29  
    30  // AssignmentPolicy controls what machine a unit will be assigned to.
    31  type AssignmentPolicy string
    32  
    33  const (
    34  	// AssignLocal indicates that all service units should be assigned
    35  	// to machine 0.
    36  	AssignLocal AssignmentPolicy = "local"
    37  
    38  	// AssignClean indicates that every service unit should be assigned
    39  	// to a machine which never previously has hosted any units, and that
    40  	// new machines should be launched if required.
    41  	AssignClean AssignmentPolicy = "clean"
    42  
    43  	// AssignCleanEmpty indicates that every service unit should be assigned
    44  	// to a machine which never previously has hosted any units, and which is not
    45  	// currently hosting any containers, and that new machines should be launched if required.
    46  	AssignCleanEmpty AssignmentPolicy = "clean-empty"
    47  
    48  	// AssignNew indicates that every service unit should be assigned to a new
    49  	// dedicated machine.  A new machine will be launched for each new unit.
    50  	AssignNew AssignmentPolicy = "new"
    51  )
    52  
    53  // ResolvedMode describes the way state transition errors
    54  // are resolved.
    55  type ResolvedMode string
    56  
    57  const (
    58  	ResolvedNone       ResolvedMode = ""
    59  	ResolvedRetryHooks ResolvedMode = "retry-hooks"
    60  	ResolvedNoHooks    ResolvedMode = "no-hooks"
    61  )
    62  
    63  // unitDoc represents the internal state of a unit in MongoDB.
    64  // Note the correspondence with UnitInfo in state/api/params.
    65  type unitDoc struct {
    66  	Name           string `bson:"_id"`
    67  	Service        string
    68  	Series         string
    69  	CharmURL       *charm.URL
    70  	Principal      string
    71  	Subordinates   []string
    72  	PublicAddress  string
    73  	PrivateAddress string
    74  	MachineId      string
    75  	Resolved       ResolvedMode
    76  	Tools          *tools.Tools `bson:",omitempty"`
    77  	Ports          []instance.Port
    78  	Life           Life
    79  	TxnRevno       int64 `bson:"txn-revno"`
    80  	PasswordHash   string
    81  }
    82  
    83  // Unit represents the state of a service unit.
    84  type Unit struct {
    85  	st  *State
    86  	doc unitDoc
    87  	annotator
    88  }
    89  
    90  func newUnit(st *State, udoc *unitDoc) *Unit {
    91  	unit := &Unit{
    92  		st:  st,
    93  		doc: *udoc,
    94  	}
    95  	unit.annotator = annotator{
    96  		globalKey: unit.globalKey(),
    97  		tag:       unit.Tag(),
    98  		st:        st,
    99  	}
   100  	return unit
   101  }
   102  
   103  // Service returns the service.
   104  func (u *Unit) Service() (*Service, error) {
   105  	return u.st.Service(u.doc.Service)
   106  }
   107  
   108  // ConfigSettings returns the complete set of service charm config settings
   109  // available to the unit. Unset values will be replaced with the default
   110  // value for the associated option, and may thus be nil when no default is
   111  // specified.
   112  func (u *Unit) ConfigSettings() (charm.Settings, error) {
   113  	if u.doc.CharmURL == nil {
   114  		return nil, errgo.Newf("unit charm not set")
   115  	}
   116  	settings, err := readSettings(u.st, serviceSettingsKey(u.doc.Service, u.doc.CharmURL))
   117  	if err != nil {
   118  		return nil, mask(err)
   119  	}
   120  	charm, err := u.st.Charm(u.doc.CharmURL)
   121  	if err != nil {
   122  		return nil, mask(err)
   123  	}
   124  	result := charm.Config().DefaultSettings()
   125  	for name, value := range settings.Map() {
   126  		result[name] = value
   127  	}
   128  	return result, nil
   129  }
   130  
   131  // ServiceName returns the service name.
   132  func (u *Unit) ServiceName() string {
   133  	return u.doc.Service
   134  }
   135  
   136  // Series returns the deployed charm's series.
   137  func (u *Unit) Series() string {
   138  	return u.doc.Series
   139  }
   140  
   141  // String returns the unit as string.
   142  func (u *Unit) String() string {
   143  	return u.doc.Name
   144  }
   145  
   146  // Name returns the unit name.
   147  func (u *Unit) Name() string {
   148  	return u.doc.Name
   149  }
   150  
   151  // unitGlobalKey returns the global database key for the named unit.
   152  func unitGlobalKey(name string) string {
   153  	return "u#" + name
   154  }
   155  
   156  // globalKey returns the global database key for the unit.
   157  func (u *Unit) globalKey() string {
   158  	return unitGlobalKey(u.doc.Name)
   159  }
   160  
   161  // Life returns whether the unit is Alive, Dying or Dead.
   162  func (u *Unit) Life() Life {
   163  	return u.doc.Life
   164  }
   165  
   166  // AgentTools returns the tools that the agent is currently running.
   167  // It an error that satisfies IsNotFound if the tools have not yet been set.
   168  func (u *Unit) AgentTools() (*tools.Tools, error) {
   169  	if u.doc.Tools == nil {
   170  		return nil, errors.NotFoundf("agent tools for unit %q", u)
   171  	}
   172  	tools := *u.doc.Tools
   173  	return &tools, nil
   174  }
   175  
   176  // SetAgentVersion sets the version of juju that the agent is
   177  // currently running.
   178  func (u *Unit) SetAgentVersion(v version.Binary) (err error) {
   179  	defer utils.ErrorContextf(&err, "cannot set agent version for unit %q", u)
   180  	if err = checkVersionValidity(v); err != nil {
   181  		return mask(err)
   182  	}
   183  	tools := &tools.Tools{Version: v}
   184  	ops := []txn.Op{{
   185  		C:      u.st.units.Name,
   186  		Id:     u.doc.Name,
   187  		Assert: notDeadDoc,
   188  		Update: D{{"$set", D{{"tools", tools}}}},
   189  	}}
   190  	if err := u.st.runTransaction(ops); err != nil {
   191  		return onAbort(err, errDead)
   192  	}
   193  	u.doc.Tools = tools
   194  	return nil
   195  }
   196  
   197  // SetMongoPassword sets the password the agent responsible for the unit
   198  // should use to communicate with the state servers.  Previous passwords
   199  // are invalidated.
   200  func (u *Unit) SetMongoPassword(password string) error {
   201  	return u.st.setMongoPassword(u.Tag(), password)
   202  }
   203  
   204  // SetPassword sets the password for the machine's agent.
   205  func (u *Unit) SetPassword(password string) error {
   206  	if len(password) < utils.MinAgentPasswordLength {
   207  		return errgo.Newf("password is only %d bytes long, and is not a valid Agent password", len(password))
   208  	}
   209  	return u.setPasswordHash(utils.AgentPasswordHash(password))
   210  }
   211  
   212  // setPasswordHash sets the underlying password hash in the database directly
   213  // to the value supplied. This is split out from SetPassword to allow direct
   214  // manipulation in tests (to check for backwards compatibility).
   215  func (u *Unit) setPasswordHash(passwordHash string) error {
   216  	ops := []txn.Op{{
   217  		C:      u.st.units.Name,
   218  		Id:     u.doc.Name,
   219  		Assert: notDeadDoc,
   220  		Update: D{{"$set", D{{"passwordhash", passwordHash}}}},
   221  	}}
   222  	err := u.st.runTransaction(ops)
   223  	if err != nil {
   224  		return errgo.Newf("cannot set password of unit %q: %v", u, onAbort(err, errDead))
   225  	}
   226  	u.doc.PasswordHash = passwordHash
   227  	return nil
   228  }
   229  
   230  // Return the underlying PasswordHash stored in the database. Used by the test
   231  // suite to check that the PasswordHash gets properly updated to new values
   232  // when compatibility mode is detected.
   233  func (u *Unit) getPasswordHash() string {
   234  	return u.doc.PasswordHash
   235  }
   236  
   237  // PasswordValid returns whether the given password is valid
   238  // for the given unit.
   239  func (u *Unit) PasswordValid(password string) bool {
   240  	agentHash := utils.AgentPasswordHash(password)
   241  	if agentHash == u.doc.PasswordHash {
   242  		return true
   243  	}
   244  	// In Juju 1.16 and older we used the slower password hash for unit
   245  	// agents. So check to see if the supplied password matches the old
   246  	// path, and if so, update it to the new mechanism.
   247  	// We ignore any error in setting the password hash, as we'll just try
   248  	// again next time
   249  	if utils.UserPasswordHash(password, utils.CompatSalt) == u.doc.PasswordHash {
   250  		logger.Debugf("%s logged in with old password hash, changing to AgentPasswordHash",
   251  			u.Tag())
   252  		u.setPasswordHash(agentHash)
   253  		return true
   254  	}
   255  	return false
   256  }
   257  
   258  // Destroy, when called on a Alive unit, advances its lifecycle as far as
   259  // possible; it otherwise has no effect. In most situations, the unit's
   260  // life is just set to Dying; but if a principal unit that is not assigned
   261  // to a provisioned machine is Destroyed, it will be removed from state
   262  // directly.
   263  func (u *Unit) Destroy() (err error) {
   264  	defer func() {
   265  		if err == nil {
   266  			// This is a white lie; the document might actually be removed.
   267  			u.doc.Life = Dying
   268  		}
   269  	}()
   270  	unit := &Unit{st: u.st, doc: u.doc}
   271  	for i := 0; i < 5; i++ {
   272  		switch ops, err := unit.destroyOps(); err {
   273  		case errRefresh:
   274  		case errAlreadyDying:
   275  			return nil
   276  		case nil:
   277  			if err := unit.st.runTransaction(ops); err != txn.ErrAborted {
   278  				return mask(err)
   279  			}
   280  		default:
   281  			return err
   282  		}
   283  		if err := unit.Refresh(); errors.IsNotFoundError(err) {
   284  			return nil
   285  		} else if err != nil {
   286  			return mask(err)
   287  		}
   288  	}
   289  	return ErrExcessiveContention
   290  }
   291  
   292  // destroyOps returns the operations required to destroy the unit. If it
   293  // returns errRefresh, the unit should be refreshed and the destruction
   294  // operations recalculated.
   295  func (u *Unit) destroyOps() ([]txn.Op, error) {
   296  	if u.doc.Life != Alive {
   297  		return nil, errAlreadyDying
   298  	}
   299  
   300  	// Where possible, we'd like to be able to short-circuit unit destruction
   301  	// such that units can be removed directly rather than waiting for their
   302  	// agents to start, observe Dying, set Dead, and shut down; this takes a
   303  	// long time and is vexing to users. This turns out to be possible if and
   304  	// only if the unit agent has not yet set its status; this implies that the
   305  	// most the unit could possibly have done is to run its install hook.
   306  	//
   307  	// There's no harm in removing a unit that's run its install hook only --
   308  	// or, at least, there is no more harm than there is in removing a unit
   309  	// that's run its stop hook, and that's the usual condition.
   310  	//
   311  	// Principals with subordinates are never eligible for this shortcut,
   312  	// because the unit agent must inevitably have set a status before getting
   313  	// to the point where it can actually create its subordinate.
   314  	//
   315  	// Subordinates should be eligible for the shortcut but are not currently
   316  	// considered, on the basis that (1) they were created by active principals
   317  	// and can be expected to be deployed pretty soon afterwards, so we don't
   318  	// lose much time and (2) by maintaining this restriction, I can reduce
   319  	// the number of tests that have to change and defer that improvement to
   320  	// its own CL.
   321  	minUnitsOp := minUnitsTriggerOp(u.st, u.ServiceName())
   322  	setDyingOps := []txn.Op{{
   323  		C:      u.st.units.Name,
   324  		Id:     u.doc.Name,
   325  		Assert: isAliveDoc,
   326  		Update: D{{"$set", D{{"life", Dying}}}},
   327  	}, minUnitsOp}
   328  	if u.doc.Principal != "" {
   329  		return setDyingOps, nil
   330  	} else if len(u.doc.Subordinates) != 0 {
   331  		return setDyingOps, nil
   332  	}
   333  
   334  	sdocId := u.globalKey()
   335  	sdoc, err := getStatus(u.st, sdocId)
   336  	if errors.IsNotFoundError(err) {
   337  		return nil, errAlreadyDying
   338  	} else if err != nil {
   339  		return nil, mask(err)
   340  	}
   341  	if sdoc.Status != params.StatusPending {
   342  		return setDyingOps, nil
   343  	}
   344  	ops := []txn.Op{{
   345  		C:      u.st.statuses.Name,
   346  		Id:     sdocId,
   347  		Assert: D{{"status", params.StatusPending}},
   348  	}, minUnitsOp}
   349  	removeAsserts := append(isAliveDoc, unitHasNoSubordinates...)
   350  	removeOps, err := u.removeOps(removeAsserts)
   351  	if errgo.Cause(err) == errAlreadyRemoved {
   352  		return nil, errAlreadyDying
   353  	} else if err != nil {
   354  		return nil, mask(err)
   355  	}
   356  	return append(ops, removeOps...), nil
   357  }
   358  
   359  var errAlreadyRemoved = errgo.New("entity has already been removed")
   360  
   361  // removeOps returns the operations necessary to remove the unit, assuming
   362  // the supplied asserts apply to the unit document.
   363  func (u *Unit) removeOps(asserts D) ([]txn.Op, error) {
   364  	svc, err := u.st.Service(u.doc.Service)
   365  	if errors.IsNotFoundError(err) {
   366  		// If the service has been removed, the unit must already have been.
   367  		return nil, errAlreadyRemoved
   368  	} else if err != nil {
   369  		return nil, mask(err)
   370  	}
   371  	return svc.removeUnitOps(u, asserts)
   372  }
   373  
   374  var ErrUnitHasSubordinates = errgo.New("unit has subordinates")
   375  
   376  var unitHasNoSubordinates = D{{
   377  	"$or", []D{
   378  		{{"subordinates", D{{"$size", 0}}}},
   379  		{{"subordinates", D{{"$exists", false}}}},
   380  	},
   381  }}
   382  
   383  // EnsureDead sets the unit lifecycle to Dead if it is Alive or Dying.
   384  // It does nothing otherwise. If the unit has subordinates, it will
   385  // return ErrUnitHasSubordinates.
   386  func (u *Unit) EnsureDead() (err error) {
   387  	if u.doc.Life == Dead {
   388  		return nil
   389  	}
   390  	defer func() {
   391  		if err == nil {
   392  			u.doc.Life = Dead
   393  		}
   394  	}()
   395  	ops := []txn.Op{{
   396  		C:      u.st.units.Name,
   397  		Id:     u.doc.Name,
   398  		Assert: append(notDeadDoc, unitHasNoSubordinates...),
   399  		Update: D{{"$set", D{{"life", Dead}}}},
   400  	}}
   401  	if err := u.st.runTransaction(ops); err != txn.ErrAborted {
   402  		return mask(err)
   403  	}
   404  	if notDead, err := isNotDead(u.st.units, u.doc.Name); err != nil {
   405  		return mask(err)
   406  	} else if !notDead {
   407  		return nil
   408  	}
   409  	return ErrUnitHasSubordinates
   410  }
   411  
   412  // Remove removes the unit from state, and may remove its service as well, if
   413  // the service is Dying and no other references to it exist. It will fail if
   414  // the unit is not Dead.
   415  func (u *Unit) Remove() (err error) {
   416  	defer utils.ErrorContextf(&err, "cannot remove unit %q", u)
   417  	if u.doc.Life != Dead {
   418  		return errgo.New("unit is not dead")
   419  	}
   420  
   421  	// Now the unit is Dead, we can be sure that it's impossible for it to
   422  	// enter relation scopes (once it's Dying, we can be sure of this; but
   423  	// EnsureDead does not require that it already be Dying, so this is the
   424  	// only point at which we can safely backstop lp:1233457 and mitigate
   425  	// the impact of unit agent bugs that leave relation scopes occupied).
   426  	relations, err := serviceRelations(u.st, u.doc.Service)
   427  	if err != nil {
   428  		return mask(err)
   429  	}
   430  	for _, rel := range relations {
   431  		ru, err := rel.Unit(u)
   432  		if err != nil {
   433  			return mask(err)
   434  		}
   435  		if err := ru.LeaveScope(); err != nil {
   436  			return mask(err)
   437  		}
   438  	}
   439  
   440  	// Now we're sure we haven't left any scopes occupied by this unit, we
   441  	// can safely remove the document.
   442  	unit := &Unit{st: u.st, doc: u.doc}
   443  	for i := 0; i < 5; i++ {
   444  		switch ops, err := unit.removeOps(isDeadDoc); err {
   445  		case errRefresh:
   446  		case errAlreadyRemoved:
   447  			return nil
   448  		case nil:
   449  			if err := u.st.runTransaction(ops); err != txn.ErrAborted {
   450  				return mask(err)
   451  			}
   452  		default:
   453  			return err
   454  		}
   455  		if err := unit.Refresh(); errors.IsNotFoundError(err) {
   456  			return nil
   457  		} else if err != nil {
   458  			return mask(err)
   459  		}
   460  	}
   461  	return ErrExcessiveContention
   462  }
   463  
   464  // Resolved returns the resolved mode for the unit.
   465  func (u *Unit) Resolved() ResolvedMode {
   466  	return u.doc.Resolved
   467  }
   468  
   469  // IsPrincipal returns whether the unit is deployed in its own container,
   470  // and can therefore have subordinate services deployed alongside it.
   471  func (u *Unit) IsPrincipal() bool {
   472  	return u.doc.Principal == ""
   473  }
   474  
   475  // SubordinateNames returns the names of any subordinate units.
   476  func (u *Unit) SubordinateNames() []string {
   477  	names := make([]string, len(u.doc.Subordinates))
   478  	copy(names, u.doc.Subordinates)
   479  	return names
   480  }
   481  
   482  // DeployerTag returns the tag of the agent responsible for deploying
   483  // the unit. If no such entity can be determined, false is returned.
   484  func (u *Unit) DeployerTag() (string, bool) {
   485  	if u.doc.Principal != "" {
   486  		return names.UnitTag(u.doc.Principal), true
   487  	} else if u.doc.MachineId != "" {
   488  		return names.MachineTag(u.doc.MachineId), true
   489  	}
   490  	return "", false
   491  }
   492  
   493  // PrincipalName returns the name of the unit's principal.
   494  // If the unit is not a subordinate, false is returned.
   495  func (u *Unit) PrincipalName() (string, bool) {
   496  	return u.doc.Principal, u.doc.Principal != ""
   497  }
   498  
   499  // addressesOfMachine returns Addresses of the related machine if present.
   500  func (u *Unit) addressesOfMachine() []instance.Address {
   501  	id := u.doc.MachineId
   502  	if id != "" {
   503  		m, err := u.st.Machine(id)
   504  		if err == nil {
   505  			return m.Addresses()
   506  		}
   507  		unitLogger.Errorf("unit %v misses machine id %v", u, id)
   508  	}
   509  	return nil
   510  }
   511  
   512  // PublicAddress returns the public address of the unit and whether it is valid.
   513  func (u *Unit) PublicAddress() (string, bool) {
   514  	publicAddress := u.doc.PublicAddress
   515  	addresses := u.addressesOfMachine()
   516  	if len(addresses) > 0 {
   517  		publicAddress = instance.SelectPublicAddress(addresses)
   518  	}
   519  	return publicAddress, publicAddress != ""
   520  }
   521  
   522  // PrivateAddress returns the private address of the unit and whether it is valid.
   523  func (u *Unit) PrivateAddress() (string, bool) {
   524  	privateAddress := u.doc.PrivateAddress
   525  	addresses := u.addressesOfMachine()
   526  	if len(addresses) > 0 {
   527  		privateAddress = instance.SelectInternalAddress(addresses, false)
   528  	}
   529  	return privateAddress, privateAddress != ""
   530  }
   531  
   532  // Refresh refreshes the contents of the Unit from the underlying
   533  // state. It an error that satisfies IsNotFound if the unit has been removed.
   534  func (u *Unit) Refresh() error {
   535  	err := u.st.units.FindId(u.doc.Name).One(&u.doc)
   536  	if errgo.Cause(err) == mgo.ErrNotFound {
   537  		return errors.NotFoundf("unit %q", u)
   538  	}
   539  	if err != nil {
   540  		return errgo.Notef(err, "cannot refresh unit %q", u)
   541  	}
   542  	return nil
   543  }
   544  
   545  // Status returns the status of the unit.
   546  func (u *Unit) Status() (status params.Status, info string, data params.StatusData, err error) {
   547  	doc, err := getStatus(u.st, u.globalKey())
   548  	if err != nil {
   549  		return "", "", nil, mask(err)
   550  	}
   551  	status = doc.Status
   552  	info = doc.StatusInfo
   553  	data = doc.StatusData
   554  	return
   555  }
   556  
   557  // SetStatus sets the status of the unit. The optional values
   558  // allow to pass additional helpful status data.
   559  func (u *Unit) SetStatus(status params.Status, info string, data params.StatusData) error {
   560  	doc := statusDoc{
   561  		Status:     status,
   562  		StatusInfo: info,
   563  		StatusData: data,
   564  	}
   565  	if err := doc.validateSet(); err != nil {
   566  		return mask(err)
   567  	}
   568  	ops := []txn.Op{{
   569  		C:      u.st.units.Name,
   570  		Id:     u.doc.Name,
   571  		Assert: notDeadDoc,
   572  	},
   573  		updateStatusOp(u.st, u.globalKey(), doc),
   574  	}
   575  	err := u.st.runTransaction(ops)
   576  	if err != nil {
   577  		return errgo.Newf("cannot set status of unit %q: %v", u, onAbort(err, errDead))
   578  	}
   579  	return nil
   580  }
   581  
   582  // OpenPort sets the policy of the port with protocol and number to be opened.
   583  func (u *Unit) OpenPort(protocol string, number int) (err error) {
   584  	port := instance.Port{Protocol: protocol, Number: number}
   585  	defer utils.ErrorContextf(&err, "cannot open port %v for unit %q", port, u)
   586  	ops := []txn.Op{{
   587  		C:      u.st.units.Name,
   588  		Id:     u.doc.Name,
   589  		Assert: notDeadDoc,
   590  		Update: D{{"$addToSet", D{{"ports", port}}}},
   591  	}}
   592  	err = u.st.runTransaction(ops)
   593  	if err != nil {
   594  		return onAbort(err, errDead)
   595  	}
   596  	found := false
   597  	for _, p := range u.doc.Ports {
   598  		if p == port {
   599  			break
   600  		}
   601  	}
   602  	if !found {
   603  		u.doc.Ports = append(u.doc.Ports, port)
   604  	}
   605  	return nil
   606  }
   607  
   608  // ClosePort sets the policy of the port with protocol and number to be closed.
   609  func (u *Unit) ClosePort(protocol string, number int) (err error) {
   610  	port := instance.Port{Protocol: protocol, Number: number}
   611  	defer utils.ErrorContextf(&err, "cannot close port %v for unit %q", port, u)
   612  	ops := []txn.Op{{
   613  		C:      u.st.units.Name,
   614  		Id:     u.doc.Name,
   615  		Assert: notDeadDoc,
   616  		Update: D{{"$pull", D{{"ports", port}}}},
   617  	}}
   618  	err = u.st.runTransaction(ops)
   619  	if err != nil {
   620  		return onAbort(err, errDead)
   621  	}
   622  	newPorts := make([]instance.Port, 0, len(u.doc.Ports))
   623  	for _, p := range u.doc.Ports {
   624  		if p != port {
   625  			newPorts = append(newPorts, p)
   626  		}
   627  	}
   628  	u.doc.Ports = newPorts
   629  	return nil
   630  }
   631  
   632  // OpenedPorts returns a slice containing the open ports of the unit.
   633  func (u *Unit) OpenedPorts() []instance.Port {
   634  	ports := append([]instance.Port{}, u.doc.Ports...)
   635  	instance.SortPorts(ports)
   636  	return ports
   637  }
   638  
   639  // CharmURL returns the charm URL this unit is currently using.
   640  func (u *Unit) CharmURL() (*charm.URL, bool) {
   641  	if u.doc.CharmURL == nil {
   642  		return nil, false
   643  	}
   644  	return u.doc.CharmURL, true
   645  }
   646  
   647  // SetCharmURL marks the unit as currently using the supplied charm URL.
   648  // An error will be returned if the unit is dead, or the charm URL not known.
   649  func (u *Unit) SetCharmURL(curl *charm.URL) (err error) {
   650  	defer func() {
   651  		if err == nil {
   652  			u.doc.CharmURL = curl
   653  		}
   654  	}()
   655  	if curl == nil {
   656  		return errgo.Newf("cannot set nil charm url")
   657  	}
   658  	for i := 0; i < 5; i++ {
   659  		if notDead, err := isNotDead(u.st.units, u.doc.Name); err != nil {
   660  			return mask(err)
   661  		} else if !notDead {
   662  			return errgo.Newf("unit %q is dead", u)
   663  		}
   664  		sel := D{{"_id", u.doc.Name}, {"charmurl", curl}}
   665  		if count, err := u.st.units.Find(sel).Count(); err != nil {
   666  			return mask(err)
   667  		} else if count == 1 {
   668  			// Already set
   669  			return nil
   670  		}
   671  		if count, err := u.st.charms.FindId(curl).Count(); err != nil {
   672  			return mask(err)
   673  		} else if count < 1 {
   674  			return errgo.Newf("unknown charm url %q", curl)
   675  		}
   676  
   677  		// Add a reference to the service settings for the new charm.
   678  		incOp, err := settingsIncRefOp(u.st, u.doc.Service, curl, false)
   679  		if err != nil {
   680  			return mask(err)
   681  		}
   682  
   683  		// Set the new charm URL.
   684  		differentCharm := D{{"charmurl", D{{"$ne", curl}}}}
   685  		ops := []txn.Op{
   686  			incOp,
   687  			{
   688  				C:      u.st.units.Name,
   689  				Id:     u.doc.Name,
   690  				Assert: append(notDeadDoc, differentCharm...),
   691  				Update: D{{"$set", D{{"charmurl", curl}}}},
   692  			}}
   693  		if u.doc.CharmURL != nil {
   694  			// Drop the reference to the old charm.
   695  			decOps, err := settingsDecRefOps(u.st, u.doc.Service, u.doc.CharmURL)
   696  			if err != nil {
   697  				return mask(err)
   698  			}
   699  			ops = append(ops, decOps...)
   700  		}
   701  		if err := u.st.runTransaction(ops); err != txn.ErrAborted {
   702  			return mask(err)
   703  		}
   704  	}
   705  	return ErrExcessiveContention
   706  }
   707  
   708  // AgentAlive returns whether the respective remote agent is alive.
   709  func (u *Unit) AgentAlive() (bool, error) {
   710  	return u.st.pwatcher.Alive(u.globalKey())
   711  }
   712  
   713  // Tag returns a name identifying the unit that is safe to use
   714  // as a file name.  The returned name will be different from other
   715  // Tag values returned by any other entities from the same state.
   716  func (u *Unit) Tag() string {
   717  	return names.UnitTag(u.Name())
   718  }
   719  
   720  // WaitAgentAlive blocks until the respective agent is alive.
   721  func (u *Unit) WaitAgentAlive(timeout time.Duration) (err error) {
   722  	defer utils.ErrorContextf(&err, "waiting for agent of unit %q", u)
   723  	ch := make(chan presence.Change)
   724  	u.st.pwatcher.Watch(u.globalKey(), ch)
   725  	defer u.st.pwatcher.Unwatch(u.globalKey(), ch)
   726  	for i := 0; i < 2; i++ {
   727  		select {
   728  		case change := <-ch:
   729  			if change.Alive {
   730  				return nil
   731  			}
   732  		case <-time.After(timeout):
   733  			return errgo.Newf("still not alive after timeout")
   734  		case <-u.st.pwatcher.Dead():
   735  			return u.st.pwatcher.Err()
   736  		}
   737  	}
   738  	panic(fmt.Sprintf("presence reported dead status twice in a row for unit %q", u))
   739  }
   740  
   741  // SetAgentAlive signals that the agent for unit u is alive.
   742  // It returns the started pinger.
   743  func (u *Unit) SetAgentAlive() (*presence.Pinger, error) {
   744  	p := presence.NewPinger(u.st.presence, u.globalKey())
   745  	err := p.Start()
   746  	if err != nil {
   747  		return nil, mask(err)
   748  	}
   749  	return p, nil
   750  }
   751  
   752  // NotAssignedError indicates that a unit is not assigned to a machine (and, in
   753  // the case of subordinate units, that the unit's principal is not assigned).
   754  type NotAssignedError struct{ Unit *Unit }
   755  
   756  func (e *NotAssignedError) Error() string {
   757  	return fmt.Sprintf("unit %q is not assigned to a machine", e.Unit)
   758  }
   759  
   760  func IsNotAssigned(err error) bool {
   761  	_, ok := err.(*NotAssignedError)
   762  	return ok
   763  }
   764  
   765  // AssignedMachineId returns the id of the assigned machine.
   766  func (u *Unit) AssignedMachineId() (id string, err error) {
   767  	if u.IsPrincipal() {
   768  		if u.doc.MachineId == "" {
   769  			return "", &NotAssignedError{u}
   770  		}
   771  		return u.doc.MachineId, nil
   772  	}
   773  	pudoc := unitDoc{}
   774  	err = u.st.units.Find(D{{"_id", u.doc.Principal}}).One(&pudoc)
   775  	if errgo.Cause(err) == mgo.ErrNotFound {
   776  		return "", errors.NotFoundf("principal unit %q of %q", u.doc.Principal, u)
   777  	} else if err != nil {
   778  		return "", mask(err)
   779  	}
   780  	if pudoc.MachineId == "" {
   781  		return "", &NotAssignedError{u}
   782  	}
   783  	return pudoc.MachineId, nil
   784  }
   785  
   786  var (
   787  	machineNotAliveErr = errgo.New("machine is not alive")
   788  	machineNotCleanErr = errgo.New("machine is dirty")
   789  	unitNotAliveErr    = errgo.New("unit is not alive")
   790  	alreadyAssignedErr = errgo.New("unit is already assigned to a machine")
   791  	inUseErr           = errgo.New("machine is not unused")
   792  )
   793  
   794  // assignToMachine is the internal version of AssignToMachine,
   795  // also used by AssignToUnusedMachine. It returns specific errors
   796  // in some cases:
   797  // - machineNotAliveErr when the machine is not alive.
   798  // - unitNotAliveErr when the unit is not alive.
   799  // - alreadyAssignedErr when the unit has already been assigned
   800  // - inUseErr when the machine already has a unit assigned (if unused is true)
   801  func (u *Unit) assignToMachine(m *Machine, unused bool) (err error) {
   802  	if u.doc.Series != m.doc.Series {
   803  		return errgo.Newf("series does not match")
   804  	}
   805  	if u.doc.MachineId != "" {
   806  		if u.doc.MachineId != m.Id() {
   807  			return alreadyAssignedErr
   808  		}
   809  		return nil
   810  	}
   811  	if u.doc.Principal != "" {
   812  		return errgo.Newf("unit is a subordinate")
   813  	}
   814  	canHost := false
   815  	for _, j := range m.doc.Jobs {
   816  		if j == JobHostUnits {
   817  			canHost = true
   818  			break
   819  		}
   820  	}
   821  	if !canHost {
   822  		return errgo.Newf("machine %q cannot host units", m)
   823  	}
   824  	assert := append(isAliveDoc, D{
   825  		{"$or", []D{
   826  			{{"machineid", ""}},
   827  			{{"machineid", m.Id()}},
   828  		}},
   829  	}...)
   830  	massert := isAliveDoc
   831  	if unused {
   832  		massert = append(massert, D{{"clean", D{{"$ne", false}}}}...)
   833  	}
   834  	ops := []txn.Op{{
   835  		C:      u.st.units.Name,
   836  		Id:     u.doc.Name,
   837  		Assert: assert,
   838  		Update: D{{"$set", D{{"machineid", m.doc.Id}}}},
   839  	}, {
   840  		C:      u.st.machines.Name,
   841  		Id:     m.doc.Id,
   842  		Assert: massert,
   843  		Update: D{{"$addToSet", D{{"principals", u.doc.Name}}}, {"$set", D{{"clean", false}}}},
   844  	}}
   845  	err = u.st.runTransaction(ops)
   846  	if err == nil {
   847  		u.doc.MachineId = m.doc.Id
   848  		m.doc.Clean = false
   849  		return nil
   850  	}
   851  	if err != txn.ErrAborted {
   852  		return mask(err)
   853  	}
   854  	u0, err := u.st.Unit(u.Name())
   855  	if err != nil {
   856  		return mask(err)
   857  	}
   858  	m0, err := u.st.Machine(m.Id())
   859  	if err != nil {
   860  		return mask(err)
   861  	}
   862  	switch {
   863  	case u0.Life() != Alive:
   864  		return unitNotAliveErr
   865  	case m0.Life() != Alive:
   866  		return machineNotAliveErr
   867  	case u0.doc.MachineId != "" || !unused:
   868  		return alreadyAssignedErr
   869  	}
   870  	return inUseErr
   871  }
   872  
   873  func assignContextf(err *error, unit *Unit, target string) {
   874  	if *err != nil {
   875  		*err = errgo.Newf("cannot assign unit %q to %s: %v", unit, target, *err)
   876  	}
   877  }
   878  
   879  // AssignToMachine assigns this unit to a given machine.
   880  func (u *Unit) AssignToMachine(m *Machine) (err error) {
   881  	defer assignContextf(&err, u, fmt.Sprintf("machine %s", m))
   882  	return u.assignToMachine(m, false)
   883  }
   884  
   885  // assignToNewMachine assigns the unit to a machine created according to
   886  // the supplied params, with the supplied constraints.
   887  func (u *Unit) assignToNewMachine(template MachineTemplate, parentId string, containerType instance.ContainerType) error {
   888  	template.principals = []string{u.doc.Name}
   889  	template.Dirty = true
   890  
   891  	var (
   892  		mdoc *machineDoc
   893  		ops  []txn.Op
   894  		err  error
   895  	)
   896  	switch {
   897  	case parentId == "" && containerType == "":
   898  		mdoc, ops, err = u.st.addMachineOps(template)
   899  	case parentId == "":
   900  		if containerType == "" {
   901  			return errgo.Newf("assignToNewMachine called without container type (should never happen)")
   902  		}
   903  		// The new parent machine is clean and only hosts units,
   904  		// regardless of its child.
   905  		parentParams := template
   906  		parentParams.Jobs = []MachineJob{JobHostUnits}
   907  		mdoc, ops, err = u.st.addMachineInsideNewMachineOps(template, parentParams, containerType)
   908  	default:
   909  		// Container type is specified but no parent id.
   910  		mdoc, ops, err = u.st.addMachineInsideMachineOps(template, parentId, containerType)
   911  	}
   912  	if err != nil {
   913  		return mask(err)
   914  	}
   915  
   916  	// Ensure the host machine is really clean.
   917  	if parentId != "" {
   918  		ops = append(ops, txn.Op{
   919  			C:      u.st.machines.Name,
   920  			Id:     parentId,
   921  			Assert: D{{"clean", true}},
   922  		}, txn.Op{
   923  			C:      u.st.containerRefs.Name,
   924  			Id:     parentId,
   925  			Assert: D{hasNoContainersTerm},
   926  		})
   927  	}
   928  	isUnassigned := D{{"machineid", ""}}
   929  	asserts := append(isAliveDoc, isUnassigned...)
   930  	ops = append(ops, txn.Op{
   931  		C:      u.st.units.Name,
   932  		Id:     u.doc.Name,
   933  		Assert: asserts,
   934  		Update: D{{"$set", D{{"machineid", mdoc.Id}}}},
   935  	})
   936  
   937  	err = u.st.runTransaction(ops)
   938  	if err == nil {
   939  		u.doc.MachineId = mdoc.Id
   940  		return nil
   941  	} else if err != txn.ErrAborted {
   942  		return mask(err)
   943  	}
   944  
   945  	// If we assume that the machine ops will never give us an
   946  	// operation that would fail (because the machine id(s) that it
   947  	// chooses are unique), then the only reasons that the
   948  	// transaction could have been aborted are:
   949  	//  * the unit is no longer alive
   950  	//  * the unit has been assigned to a different machine
   951  	//  * the parent machine we want to create a container on was
   952  	//  clean but became dirty
   953  	unit, err := u.st.Unit(u.Name())
   954  	if err != nil {
   955  		return mask(err)
   956  	}
   957  	switch {
   958  	case unit.Life() != Alive:
   959  		return unitNotAliveErr
   960  	case unit.doc.MachineId != "":
   961  		return alreadyAssignedErr
   962  	}
   963  	if parentId == "" {
   964  		return errgo.Newf("cannot add top level machine: transaction aborted for unknown reason")
   965  	}
   966  	m, err := u.st.Machine(parentId)
   967  	if err != nil {
   968  		return mask(err)
   969  	}
   970  	if !m.Clean() {
   971  		return machineNotCleanErr
   972  	}
   973  	containers, err := m.Containers()
   974  	if err != nil {
   975  		return mask(err)
   976  	}
   977  	if len(containers) > 0 {
   978  		return machineNotCleanErr
   979  	}
   980  	return errgo.Newf("cannot add container within machine: transaction aborted for unknown reason")
   981  }
   982  
   983  // constraints is a helper function to return a unit's deployment constraints.
   984  func (u *Unit) constraints() (*constraints.Value, error) {
   985  	cons, err := readConstraints(u.st, u.globalKey())
   986  	if errors.IsNotFoundError(err) {
   987  		// Lack of constraints indicates lack of unit.
   988  		return nil, errors.NotFoundf("unit")
   989  	} else if err != nil {
   990  		return nil, mask(err)
   991  	}
   992  	return &cons, nil
   993  }
   994  
   995  // AssignToNewMachineOrContainer assigns the unit to a new machine, with constraints
   996  // determined according to the service and environment constraints at the time of unit creation.
   997  // If a container is required, a clean, empty machine instance is required on which to create
   998  // the container. An existing clean, empty instance is first searched for, and if not found,
   999  // a new one is created.
  1000  func (u *Unit) AssignToNewMachineOrContainer() (err error) {
  1001  	defer assignContextf(&err, u, "new machine or container")
  1002  	if u.doc.Principal != "" {
  1003  		return errgo.Newf("unit is a subordinate")
  1004  	}
  1005  	cons, err := u.constraints()
  1006  	if err != nil {
  1007  		return mask(err)
  1008  	}
  1009  	if !cons.HasContainer() {
  1010  		return u.AssignToNewMachine()
  1011  	}
  1012  
  1013  	// Find a clean, empty machine on which to create a container.
  1014  	var host machineDoc
  1015  	hostCons := *cons
  1016  	noContainer := instance.NONE
  1017  	hostCons.Container = &noContainer
  1018  	query, err := u.findCleanMachineQuery(true, &hostCons)
  1019  	if err != nil {
  1020  		return mask(err)
  1021  	}
  1022  	err = query.One(&host)
  1023  	if errgo.Cause(err) == mgo.ErrNotFound {
  1024  		// No existing clean, empty machine so create a new one.
  1025  		// The container constraint will be used by AssignToNewMachine to create the required container.
  1026  		return u.AssignToNewMachine()
  1027  	} else if err != nil {
  1028  		return mask(err)
  1029  	}
  1030  	template := MachineTemplate{
  1031  		Series:      u.doc.Series,
  1032  		Constraints: *cons,
  1033  		Jobs:        []MachineJob{JobHostUnits},
  1034  	}
  1035  	err = u.assignToNewMachine(template, host.Id, *cons.Container)
  1036  	if errgo.Cause(err) == machineNotCleanErr {
  1037  		// The clean machine was used before we got a chance to use it so just
  1038  		// stick the unit on a new machine.
  1039  		return u.AssignToNewMachine()
  1040  	}
  1041  	return err
  1042  }
  1043  
  1044  // AssignToNewMachine assigns the unit to a new machine, with constraints
  1045  // determined according to the service and environment constraints at the
  1046  // time of unit creation.
  1047  func (u *Unit) AssignToNewMachine() (err error) {
  1048  	defer assignContextf(&err, u, "new machine")
  1049  	if u.doc.Principal != "" {
  1050  		return errgo.Newf("unit is a subordinate")
  1051  	}
  1052  	// Get the ops necessary to create a new machine, and the machine doc that
  1053  	// will be added with those operations (which includes the machine id).
  1054  	cons, err := u.constraints()
  1055  	if err != nil {
  1056  		return mask(err)
  1057  	}
  1058  	var containerType instance.ContainerType
  1059  	// Configure to create a new container if required.
  1060  	if cons.HasContainer() {
  1061  		containerType = *cons.Container
  1062  	}
  1063  	template := MachineTemplate{
  1064  		Series:      u.doc.Series,
  1065  		Constraints: *cons,
  1066  		Jobs:        []MachineJob{JobHostUnits},
  1067  	}
  1068  	return u.assignToNewMachine(template, "", containerType)
  1069  }
  1070  
  1071  var noCleanMachines = errgo.New("all eligible machines in use")
  1072  
  1073  // AssignToCleanMachine assigns u to a machine which is marked as clean. A machine
  1074  // is clean if it has never had any principal units assigned to it.
  1075  // If there are no clean machines besides any machine(s) running JobHostEnviron,
  1076  // an error is returned.
  1077  // This method does not take constraints into consideration when choosing a
  1078  // machine (lp:1161919).
  1079  func (u *Unit) AssignToCleanMachine() (m *Machine, err error) {
  1080  	return u.assignToCleanMaybeEmptyMachine(false)
  1081  }
  1082  
  1083  // AssignToCleanMachine assigns u to a machine which is marked as clean and is also
  1084  // not hosting any containers. A machine is clean if it has never had any principal units
  1085  // assigned to it. If there are no clean machines besides any machine(s) running JobHostEnviron,
  1086  // an error is returned.
  1087  // This method does not take constraints into consideration when choosing a
  1088  // machine (lp:1161919).
  1089  func (u *Unit) AssignToCleanEmptyMachine() (m *Machine, err error) {
  1090  	return u.assignToCleanMaybeEmptyMachine(true)
  1091  }
  1092  
  1093  var hasContainerTerm = bson.DocElem{
  1094  	"$and", []D{
  1095  		{{"children", D{{"$not", D{{"$size", 0}}}}}},
  1096  		{{"children", D{{"$exists", true}}}},
  1097  	}}
  1098  
  1099  var hasNoContainersTerm = bson.DocElem{
  1100  	"$or", []D{
  1101  		{{"children", D{{"$size", 0}}}},
  1102  		{{"children", D{{"$exists", false}}}},
  1103  	}}
  1104  
  1105  // findCleanMachineQuery returns a Mongo query to find clean (and possibly empty) machines with
  1106  // characteristics matching the specified constraints.
  1107  func (u *Unit) findCleanMachineQuery(requireEmpty bool, cons *constraints.Value) (*mgo.Query, error) {
  1108  	// Select all machines that can accept principal units and are clean.
  1109  	var containerRefs []machineContainers
  1110  	// If we need empty machines, first build up a list of machine ids which have containers
  1111  	// so we can exclude those.
  1112  	if requireEmpty {
  1113  		err := u.st.containerRefs.Find(D{hasContainerTerm}).All(&containerRefs)
  1114  		if err != nil {
  1115  			return nil, mask(err)
  1116  		}
  1117  	}
  1118  	var machinesWithContainers = make([]string, len(containerRefs))
  1119  	for i, cref := range containerRefs {
  1120  		machinesWithContainers[i] = cref.Id
  1121  	}
  1122  	terms := D{
  1123  		{"life", Alive},
  1124  		{"series", u.doc.Series},
  1125  		{"jobs", []MachineJob{JobHostUnits}},
  1126  		{"clean", true},
  1127  		{"_id", D{{"$nin", machinesWithContainers}}},
  1128  	}
  1129  	// Add the container filter term if necessary.
  1130  	var containerType instance.ContainerType
  1131  	if cons.Container != nil {
  1132  		containerType = *cons.Container
  1133  	}
  1134  	if containerType == instance.NONE {
  1135  		terms = append(terms, bson.DocElem{"containertype", ""})
  1136  	} else if containerType != "" {
  1137  		terms = append(terms, bson.DocElem{"containertype", string(containerType)})
  1138  	}
  1139  
  1140  	// Find the ids of machines which satisfy any required hardware
  1141  	// constraints. If there is no instanceData for a machine, that
  1142  	// machine is not considered as suitable for deploying the unit.
  1143  	// This can happen if the machine is not yet provisioned. It may
  1144  	// be that when the machine is provisioned it will be found to
  1145  	// be suitable, but we don't know that right now and it's best
  1146  	// to err on the side of caution and exclude such machines.
  1147  	var suitableInstanceData []instanceData
  1148  	var suitableTerms D
  1149  	if cons.Arch != nil && *cons.Arch != "" {
  1150  		suitableTerms = append(suitableTerms, bson.DocElem{"arch", *cons.Arch})
  1151  	}
  1152  	if cons.Mem != nil && *cons.Mem > 0 {
  1153  		suitableTerms = append(suitableTerms, bson.DocElem{"mem", D{{"$gte", *cons.Mem}}})
  1154  	}
  1155  	if cons.RootDisk != nil && *cons.RootDisk > 0 {
  1156  		suitableTerms = append(suitableTerms, bson.DocElem{"rootdisk", D{{"$gte", *cons.RootDisk}}})
  1157  	}
  1158  	if cons.CpuCores != nil && *cons.CpuCores > 0 {
  1159  		suitableTerms = append(suitableTerms, bson.DocElem{"cpucores", D{{"$gte", *cons.CpuCores}}})
  1160  	}
  1161  	if cons.CpuPower != nil && *cons.CpuPower > 0 {
  1162  		suitableTerms = append(suitableTerms, bson.DocElem{"cpupower", D{{"$gte", *cons.CpuPower}}})
  1163  	}
  1164  	if cons.Tags != nil && len(*cons.Tags) > 0 {
  1165  		suitableTerms = append(suitableTerms, bson.DocElem{"tags", D{{"$all", *cons.Tags}}})
  1166  	}
  1167  	if len(suitableTerms) > 0 {
  1168  		err := u.st.instanceData.Find(suitableTerms).Select(bson.M{"_id": 1}).All(&suitableInstanceData)
  1169  		if err != nil {
  1170  			return nil, mask(err)
  1171  		}
  1172  		var suitableIds = make([]string, len(suitableInstanceData))
  1173  		for i, m := range suitableInstanceData {
  1174  			suitableIds[i] = m.Id
  1175  		}
  1176  		terms = append(terms, bson.DocElem{"_id", D{{"$in", suitableIds}}})
  1177  	}
  1178  	return u.st.machines.Find(terms), nil
  1179  }
  1180  
  1181  // assignToCleanMaybeEmptyMachine implements AssignToCleanMachine and AssignToCleanEmptyMachine.
  1182  // A 'machine' may be a machine instance or container depending on the service constraints.
  1183  func (u *Unit) assignToCleanMaybeEmptyMachine(requireEmpty bool) (m *Machine, err error) {
  1184  	context := "clean"
  1185  	if requireEmpty {
  1186  		context += ", empty"
  1187  	}
  1188  	context += " machine"
  1189  
  1190  	if u.doc.Principal != "" {
  1191  		err = errgo.Newf("unit is a subordinate")
  1192  		assignContextf(&err, u, context)
  1193  		return nil, err
  1194  	}
  1195  
  1196  	// Get the unit constraints to see what deployment requirements we have to adhere to.
  1197  	cons, err := u.constraints()
  1198  	if err != nil {
  1199  		assignContextf(&err, u, context)
  1200  		return nil, err
  1201  	}
  1202  	query, err := u.findCleanMachineQuery(requireEmpty, cons)
  1203  	if err != nil {
  1204  		assignContextf(&err, u, context)
  1205  		return nil, err
  1206  	}
  1207  
  1208  	// TODO(rog) Fix so this is more efficient when there are concurrent uses.
  1209  	// Possible solution: pick the highest and the smallest id of all
  1210  	// unused machines, and try to assign to the first one >= a random id in the
  1211  	// middle.
  1212  	iter := query.Batch(1).Prefetch(0).Iter()
  1213  	var mdoc machineDoc
  1214  	for iter.Next(&mdoc) {
  1215  		m := newMachine(u.st, &mdoc)
  1216  		err := u.assignToMachine(m, true)
  1217  		if err == nil {
  1218  			return m, nil
  1219  		}
  1220  		if err != inUseErr && err != machineNotAliveErr {
  1221  			assignContextf(&err, u, context)
  1222  			return nil, err
  1223  		}
  1224  	}
  1225  	if err := iter.Err(); err != nil {
  1226  		assignContextf(&err, u, context)
  1227  		return nil, err
  1228  	}
  1229  	return nil, noCleanMachines
  1230  }
  1231  
  1232  // UnassignFromMachine removes the assignment between this unit and the
  1233  // machine it's assigned to.
  1234  func (u *Unit) UnassignFromMachine() (err error) {
  1235  	// TODO check local machine id and add an assert that the
  1236  	// machine id is as expected.
  1237  	ops := []txn.Op{{
  1238  		C:      u.st.units.Name,
  1239  		Id:     u.doc.Name,
  1240  		Assert: txn.DocExists,
  1241  		Update: D{{"$set", D{{"machineid", ""}}}},
  1242  	}}
  1243  	if u.doc.MachineId != "" {
  1244  		ops = append(ops, txn.Op{
  1245  			C:      u.st.machines.Name,
  1246  			Id:     u.doc.MachineId,
  1247  			Assert: txn.DocExists,
  1248  			Update: D{{"$pull", D{{"principals", u.doc.Name}}}},
  1249  		})
  1250  	}
  1251  	err = u.st.runTransaction(ops)
  1252  	if err != nil {
  1253  		return errgo.Newf("cannot unassign unit %q from machine: %v", u, onAbort(err, errors.NotFoundf("machine")))
  1254  	}
  1255  	u.doc.MachineId = ""
  1256  	return nil
  1257  }
  1258  
  1259  // SetPublicAddress sets the public address of the unit.
  1260  func (u *Unit) SetPublicAddress(address string) (err error) {
  1261  	ops := []txn.Op{{
  1262  		C:      u.st.units.Name,
  1263  		Id:     u.doc.Name,
  1264  		Assert: txn.DocExists,
  1265  		Update: D{{"$set", D{{"publicaddress", address}}}},
  1266  	}}
  1267  	if err := u.st.runTransaction(ops); err != nil {
  1268  		return errgo.Newf("cannot set public address of unit %q: %v", u, onAbort(err, errors.NotFoundf("unit")))
  1269  	}
  1270  	u.doc.PublicAddress = address
  1271  	return nil
  1272  }
  1273  
  1274  // SetPrivateAddress sets the private address of the unit.
  1275  func (u *Unit) SetPrivateAddress(address string) error {
  1276  	ops := []txn.Op{{
  1277  		C:      u.st.units.Name,
  1278  		Id:     u.doc.Name,
  1279  		Assert: notDeadDoc,
  1280  		Update: D{{"$set", D{{"privateaddress", address}}}},
  1281  	}}
  1282  	err := u.st.runTransaction(ops)
  1283  	if err != nil {
  1284  		return errgo.Newf("cannot set private address of unit %q: %v", u, onAbort(err, errors.NotFoundf("unit")))
  1285  	}
  1286  	u.doc.PrivateAddress = address
  1287  	return nil
  1288  }
  1289  
  1290  // Resolve marks the unit as having had any previous state transition
  1291  // problems resolved, and informs the unit that it may attempt to
  1292  // reestablish normal workflow. The retryHooks parameter informs
  1293  // whether to attempt to reexecute previous failed hooks or to continue
  1294  // as if they had succeeded before.
  1295  func (u *Unit) Resolve(retryHooks bool) error {
  1296  	status, _, _, err := u.Status()
  1297  	if err != nil {
  1298  		return mask(err)
  1299  	}
  1300  	if status != params.StatusError {
  1301  		return errgo.Newf("unit %q is not in an error state", u)
  1302  	}
  1303  	mode := ResolvedNoHooks
  1304  	if retryHooks {
  1305  		mode = ResolvedRetryHooks
  1306  	}
  1307  	return u.SetResolved(mode)
  1308  }
  1309  
  1310  // SetResolved marks the unit as having had any previous state transition
  1311  // problems resolved, and informs the unit that it may attempt to
  1312  // reestablish normal workflow. The resolved mode parameter informs
  1313  // whether to attempt to reexecute previous failed hooks or to continue
  1314  // as if they had succeeded before.
  1315  func (u *Unit) SetResolved(mode ResolvedMode) (err error) {
  1316  	defer utils.ErrorContextf(&err, "cannot set resolved mode for unit %q", u)
  1317  	switch mode {
  1318  	case ResolvedRetryHooks, ResolvedNoHooks:
  1319  	default:
  1320  		return errgo.Newf("invalid error resolution mode: %q", mode)
  1321  	}
  1322  	// TODO(fwereade): assert unit has error status.
  1323  	resolvedNotSet := D{{"resolved", ResolvedNone}}
  1324  	ops := []txn.Op{{
  1325  		C:      u.st.units.Name,
  1326  		Id:     u.doc.Name,
  1327  		Assert: append(notDeadDoc, resolvedNotSet...),
  1328  		Update: D{{"$set", D{{"resolved", mode}}}},
  1329  	}}
  1330  	if err := u.st.runTransaction(ops); err == nil {
  1331  		u.doc.Resolved = mode
  1332  		return nil
  1333  	} else if err != txn.ErrAborted {
  1334  		return mask(err)
  1335  	}
  1336  	if ok, err := isNotDead(u.st.units, u.doc.Name); err != nil {
  1337  		return mask(err)
  1338  	} else if !ok {
  1339  		return errDead
  1340  	}
  1341  	// For now, the only remaining assert is that resolved was unset.
  1342  	return errgo.Newf("already resolved")
  1343  }
  1344  
  1345  // ClearResolved removes any resolved setting on the unit.
  1346  func (u *Unit) ClearResolved() error {
  1347  	ops := []txn.Op{{
  1348  		C:      u.st.units.Name,
  1349  		Id:     u.doc.Name,
  1350  		Assert: txn.DocExists,
  1351  		Update: D{{"$set", D{{"resolved", ResolvedNone}}}},
  1352  	}}
  1353  	err := u.st.runTransaction(ops)
  1354  	if err != nil {
  1355  		return errgo.Newf("cannot clear resolved mode for unit %q: %v", u, errors.NotFoundf("unit"))
  1356  	}
  1357  	u.doc.Resolved = ResolvedNone
  1358  	return nil
  1359  }