github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/state/machine.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  	"strings"
     9  	"time"
    10  
    11  	"github.com/juju/errors"
    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/mgo.v2"
    18  	"gopkg.in/mgo.v2/bson"
    19  	"gopkg.in/mgo.v2/txn"
    20  
    21  	"github.com/juju/juju/constraints"
    22  	"github.com/juju/juju/core/actions"
    23  	"github.com/juju/juju/instance"
    24  	"github.com/juju/juju/mongo"
    25  	"github.com/juju/juju/network"
    26  	"github.com/juju/juju/state/multiwatcher"
    27  	"github.com/juju/juju/state/presence"
    28  	"github.com/juju/juju/status"
    29  	"github.com/juju/juju/tools"
    30  )
    31  
    32  // Machine represents the state of a machine.
    33  type Machine struct {
    34  	st  *State
    35  	doc machineDoc
    36  }
    37  
    38  // MachineJob values define responsibilities that machines may be
    39  // expected to fulfil.
    40  type MachineJob int
    41  
    42  const (
    43  	_ MachineJob = iota
    44  	JobHostUnits
    45  	JobManageModel
    46  	JobManageNetworking
    47  )
    48  
    49  var (
    50  	jobNames = map[MachineJob]multiwatcher.MachineJob{
    51  		JobHostUnits:        multiwatcher.JobHostUnits,
    52  		JobManageModel:      multiwatcher.JobManageModel,
    53  		JobManageNetworking: multiwatcher.JobManageNetworking,
    54  	}
    55  	jobMigrationValue = map[MachineJob]string{
    56  		JobHostUnits:        "host-units",
    57  		JobManageModel:      "api-server",
    58  		JobManageNetworking: "manage-networking",
    59  	}
    60  )
    61  
    62  // AllJobs returns all supported machine jobs.
    63  func AllJobs() []MachineJob {
    64  	return []MachineJob{
    65  		JobHostUnits,
    66  		JobManageModel,
    67  		JobManageNetworking,
    68  	}
    69  }
    70  
    71  // ToParams returns the job as multiwatcher.MachineJob.
    72  func (job MachineJob) ToParams() multiwatcher.MachineJob {
    73  	if jujuJob, ok := jobNames[job]; ok {
    74  		return jujuJob
    75  	}
    76  	return multiwatcher.MachineJob(fmt.Sprintf("<unknown job %d>", int(job)))
    77  }
    78  
    79  // params.JobsFromJobs converts state jobs to juju jobs.
    80  func paramsJobsFromJobs(jobs []MachineJob) []multiwatcher.MachineJob {
    81  	jujuJobs := make([]multiwatcher.MachineJob, len(jobs))
    82  	for i, machineJob := range jobs {
    83  		jujuJobs[i] = machineJob.ToParams()
    84  	}
    85  	return jujuJobs
    86  }
    87  
    88  // MigrationValue converts the state job into a useful human readable
    89  // string for model migration.
    90  func (job MachineJob) MigrationValue() string {
    91  	if value, ok := jobMigrationValue[job]; ok {
    92  		return value
    93  	}
    94  	return "unknown"
    95  }
    96  
    97  func (job MachineJob) String() string {
    98  	return string(job.ToParams())
    99  }
   100  
   101  // manualMachinePrefix signals as prefix of Nonce that a machine is
   102  // manually provisioned.
   103  const manualMachinePrefix = "manual:"
   104  
   105  // machineDoc represents the internal state of a machine in MongoDB.
   106  // Note the correspondence with MachineInfo in apiserver/juju.
   107  type machineDoc struct {
   108  	DocID         string `bson:"_id"`
   109  	Id            string `bson:"machineid"`
   110  	ModelUUID     string `bson:"model-uuid"`
   111  	Nonce         string
   112  	Series        string
   113  	ContainerType string
   114  	Principals    []string
   115  	Life          Life
   116  	Tools         *tools.Tools `bson:",omitempty"`
   117  	Jobs          []MachineJob
   118  	NoVote        bool
   119  	HasVote       bool
   120  	PasswordHash  string
   121  	Clean         bool
   122  
   123  	// TODO(axw) 2015-06-22 #1467379
   124  	// We need an upgrade step to populate "volumes" and "filesystems"
   125  	// for entities created in 1.24.
   126  	//
   127  	// Volumes contains the names of volumes attached to the machine.
   128  	Volumes []string `bson:"volumes,omitempty"`
   129  	// Filesystems contains the names of filesystems attached to the machine.
   130  	Filesystems []string `bson:"filesystems,omitempty"`
   131  
   132  	// We store 2 different sets of addresses for the machine, obtained
   133  	// from different sources.
   134  	// Addresses is the set of addresses obtained by asking the provider.
   135  	Addresses []address
   136  
   137  	// MachineAddresses is the set of addresses obtained from the machine itself.
   138  	MachineAddresses []address
   139  
   140  	// PreferredPublicAddress is the preferred address to be used for
   141  	// the machine when a public address is requested.
   142  	PreferredPublicAddress address `bson:",omitempty"`
   143  
   144  	// PreferredPrivateAddress is the preferred address to be used for
   145  	// the machine when a private address is requested.
   146  	PreferredPrivateAddress address `bson:",omitempty"`
   147  
   148  	// The SupportedContainers attributes are used to advertise what containers this
   149  	// machine is capable of hosting.
   150  	SupportedContainersKnown bool
   151  	SupportedContainers      []instance.ContainerType `bson:",omitempty"`
   152  	// Placement is the placement directive that should be used when provisioning
   153  	// an instance for the machine.
   154  	Placement string `bson:",omitempty"`
   155  
   156  	// StopMongoUntilVersion holds the version that must be checked to
   157  	// know if mongo must be stopped.
   158  	StopMongoUntilVersion string `bson:",omitempty"`
   159  }
   160  
   161  func newMachine(st *State, doc *machineDoc) *Machine {
   162  	machine := &Machine{
   163  		st:  st,
   164  		doc: *doc,
   165  	}
   166  	return machine
   167  }
   168  
   169  func wantsVote(jobs []MachineJob, noVote bool) bool {
   170  	return hasJob(jobs, JobManageModel) && !noVote
   171  }
   172  
   173  // Id returns the machine id.
   174  func (m *Machine) Id() string {
   175  	return m.doc.Id
   176  }
   177  
   178  // Principals returns the principals for the machine.
   179  func (m *Machine) Principals() []string {
   180  	return m.doc.Principals
   181  }
   182  
   183  // Series returns the operating system series running on the machine.
   184  func (m *Machine) Series() string {
   185  	return m.doc.Series
   186  }
   187  
   188  // ContainerType returns the type of container hosting this machine.
   189  func (m *Machine) ContainerType() instance.ContainerType {
   190  	return instance.ContainerType(m.doc.ContainerType)
   191  }
   192  
   193  // machineGlobalKey returns the global database key for the identified machine.
   194  func machineGlobalKey(id string) string {
   195  	return "m#" + id
   196  }
   197  
   198  // machineGlobalInstanceKey returns the global database key for the identified machine's instance.
   199  func machineGlobalInstanceKey(id string) string {
   200  	return machineGlobalKey(id) + "#instance"
   201  }
   202  
   203  // globalInstanceKey returns the global database key for the machinei's instance.
   204  func (m *Machine) globalInstanceKey() string {
   205  	return machineGlobalInstanceKey(m.doc.Id)
   206  }
   207  
   208  // globalKey returns the global database key for the machine.
   209  func (m *Machine) globalKey() string {
   210  	return machineGlobalKey(m.doc.Id)
   211  }
   212  
   213  // instanceData holds attributes relevant to a provisioned machine.
   214  type instanceData struct {
   215  	DocID      string      `bson:"_id"`
   216  	MachineId  string      `bson:"machineid"`
   217  	InstanceId instance.Id `bson:"instanceid"`
   218  	ModelUUID  string      `bson:"model-uuid"`
   219  	Status     string      `bson:"status,omitempty"`
   220  	Arch       *string     `bson:"arch,omitempty"`
   221  	Mem        *uint64     `bson:"mem,omitempty"`
   222  	RootDisk   *uint64     `bson:"rootdisk,omitempty"`
   223  	CpuCores   *uint64     `bson:"cpucores,omitempty"`
   224  	CpuPower   *uint64     `bson:"cpupower,omitempty"`
   225  	Tags       *[]string   `bson:"tags,omitempty"`
   226  	AvailZone  *string     `bson:"availzone,omitempty"`
   227  }
   228  
   229  func hardwareCharacteristics(instData instanceData) *instance.HardwareCharacteristics {
   230  	return &instance.HardwareCharacteristics{
   231  		Arch:             instData.Arch,
   232  		Mem:              instData.Mem,
   233  		RootDisk:         instData.RootDisk,
   234  		CpuCores:         instData.CpuCores,
   235  		CpuPower:         instData.CpuPower,
   236  		Tags:             instData.Tags,
   237  		AvailabilityZone: instData.AvailZone,
   238  	}
   239  }
   240  
   241  // TODO(wallyworld): move this method to a service.
   242  func (m *Machine) HardwareCharacteristics() (*instance.HardwareCharacteristics, error) {
   243  	instData, err := getInstanceData(m.st, m.Id())
   244  	if err != nil {
   245  		return nil, err
   246  	}
   247  	return hardwareCharacteristics(instData), nil
   248  }
   249  
   250  func getInstanceData(st *State, id string) (instanceData, error) {
   251  	instanceDataCollection, closer := st.getCollection(instanceDataC)
   252  	defer closer()
   253  
   254  	var instData instanceData
   255  	err := instanceDataCollection.FindId(id).One(&instData)
   256  	if err == mgo.ErrNotFound {
   257  		return instanceData{}, errors.NotFoundf("instance data for machine %v", id)
   258  	}
   259  	if err != nil {
   260  		return instanceData{}, fmt.Errorf("cannot get instance data for machine %v: %v", id, err)
   261  	}
   262  	return instData, nil
   263  }
   264  
   265  // Tag returns a tag identifying the machine. The String method provides a
   266  // string representation that is safe to use as a file name. The returned name
   267  // will be different from other Tag values returned by any other entities
   268  // from the same state.
   269  func (m *Machine) Tag() names.Tag {
   270  	return m.MachineTag()
   271  }
   272  
   273  // MachineTag returns the more specific MachineTag type as opposed
   274  // to the more generic Tag type.
   275  func (m *Machine) MachineTag() names.MachineTag {
   276  	return names.NewMachineTag(m.Id())
   277  }
   278  
   279  // Life returns whether the machine is Alive, Dying or Dead.
   280  func (m *Machine) Life() Life {
   281  	return m.doc.Life
   282  }
   283  
   284  // Jobs returns the responsibilities that must be fulfilled by m's agent.
   285  func (m *Machine) Jobs() []MachineJob {
   286  	return m.doc.Jobs
   287  }
   288  
   289  // WantsVote reports whether the machine is a controller
   290  // that wants to take part in peer voting.
   291  func (m *Machine) WantsVote() bool {
   292  	return wantsVote(m.doc.Jobs, m.doc.NoVote)
   293  }
   294  
   295  // HasVote reports whether that machine is currently a voting
   296  // member of the replica set.
   297  func (m *Machine) HasVote() bool {
   298  	return m.doc.HasVote
   299  }
   300  
   301  // SetHasVote sets whether the machine is currently a voting
   302  // member of the replica set. It should only be called
   303  // from the worker that maintains the replica set.
   304  func (m *Machine) SetHasVote(hasVote bool) error {
   305  	ops := []txn.Op{{
   306  		C:      machinesC,
   307  		Id:     m.doc.DocID,
   308  		Assert: notDeadDoc,
   309  		Update: bson.D{{"$set", bson.D{{"hasvote", hasVote}}}},
   310  	}}
   311  	if err := m.st.runTransaction(ops); err != nil {
   312  		return fmt.Errorf("cannot set HasVote of machine %v: %v", m, onAbort(err, ErrDead))
   313  	}
   314  	m.doc.HasVote = hasVote
   315  	return nil
   316  }
   317  
   318  // SetStopMongoUntilVersion sets a version that is to be checked against
   319  // the agent config before deciding if mongo must be started on a
   320  // state server.
   321  func (m *Machine) SetStopMongoUntilVersion(v mongo.Version) error {
   322  	ops := []txn.Op{{
   323  		C:      machinesC,
   324  		Id:     m.doc.DocID,
   325  		Update: bson.D{{"$set", bson.D{{"stopmongountilversion", v.String()}}}},
   326  	}}
   327  	if err := m.st.runTransaction(ops); err != nil {
   328  		return fmt.Errorf("cannot set StopMongoUntilVersion %v: %v", m, onAbort(err, ErrDead))
   329  	}
   330  	m.doc.StopMongoUntilVersion = v.String()
   331  	return nil
   332  }
   333  
   334  // StopMongoUntilVersion returns the current minimum version that
   335  // is required for this machine to have mongo running.
   336  func (m *Machine) StopMongoUntilVersion() (mongo.Version, error) {
   337  	return mongo.NewVersion(m.doc.StopMongoUntilVersion)
   338  }
   339  
   340  // IsManager returns true if the machine has JobManageModel.
   341  func (m *Machine) IsManager() bool {
   342  	return hasJob(m.doc.Jobs, JobManageModel)
   343  }
   344  
   345  // IsManual returns true if the machine was manually provisioned.
   346  func (m *Machine) IsManual() (bool, error) {
   347  	// Apart from the bootstrap machine, manually provisioned
   348  	// machines have a nonce prefixed with "manual:". This is
   349  	// unique to manual provisioning.
   350  	if strings.HasPrefix(m.doc.Nonce, manualMachinePrefix) {
   351  		return true, nil
   352  	}
   353  	// The bootstrap machine uses BootstrapNonce, so in that
   354  	// case we need to check if its provider type is "manual".
   355  	// We also check for "null", which is an alias for manual.
   356  	if m.doc.Id == "0" {
   357  		cfg, err := m.st.ModelConfig()
   358  		if err != nil {
   359  			return false, err
   360  		}
   361  		t := cfg.Type()
   362  		return t == "null" || t == "manual", nil
   363  	}
   364  	return false, nil
   365  }
   366  
   367  // AgentTools returns the tools that the agent is currently running.
   368  // It returns an error that satisfies errors.IsNotFound if the tools
   369  // have not yet been set.
   370  func (m *Machine) AgentTools() (*tools.Tools, error) {
   371  	if m.doc.Tools == nil {
   372  		return nil, errors.NotFoundf("agent tools for machine %v", m)
   373  	}
   374  	tools := *m.doc.Tools
   375  	return &tools, nil
   376  }
   377  
   378  // checkVersionValidity checks whether the given version is suitable
   379  // for passing to SetAgentVersion.
   380  func checkVersionValidity(v version.Binary) error {
   381  	if v.Series == "" || v.Arch == "" {
   382  		return fmt.Errorf("empty series or arch")
   383  	}
   384  	return nil
   385  }
   386  
   387  // SetAgentVersion sets the version of juju that the agent is
   388  // currently running.
   389  func (m *Machine) SetAgentVersion(v version.Binary) (err error) {
   390  	defer errors.DeferredAnnotatef(&err, "cannot set agent version for machine %v", m)
   391  	if err = checkVersionValidity(v); err != nil {
   392  		return err
   393  	}
   394  	tools := &tools.Tools{Version: v}
   395  	ops := []txn.Op{{
   396  		C:      machinesC,
   397  		Id:     m.doc.DocID,
   398  		Assert: notDeadDoc,
   399  		Update: bson.D{{"$set", bson.D{{"tools", tools}}}},
   400  	}}
   401  	// A "raw" transaction is needed here because this function gets
   402  	// called before database migraions have run so we don't
   403  	// necessarily want the env UUID added to the id.
   404  	if err := m.st.runRawTransaction(ops); err != nil {
   405  		return onAbort(err, ErrDead)
   406  	}
   407  	m.doc.Tools = tools
   408  	return nil
   409  }
   410  
   411  // SetMongoPassword sets the password the agent responsible for the machine
   412  // should use to communicate with the controllers.  Previous passwords
   413  // are invalidated.
   414  func (m *Machine) SetMongoPassword(password string) error {
   415  	if !m.IsManager() {
   416  		return errors.NotSupportedf("setting mongo password for non-controller machine %v", m)
   417  	}
   418  	return mongo.SetAdminMongoPassword(m.st.session, m.Tag().String(), password)
   419  }
   420  
   421  // SetPassword sets the password for the machine's agent.
   422  func (m *Machine) SetPassword(password string) error {
   423  	if len(password) < utils.MinAgentPasswordLength {
   424  		return fmt.Errorf("password is only %d bytes long, and is not a valid Agent password", len(password))
   425  	}
   426  	return m.setPasswordHash(utils.AgentPasswordHash(password))
   427  }
   428  
   429  // setPasswordHash sets the underlying password hash in the database directly
   430  // to the value supplied. This is split out from SetPassword to allow direct
   431  // manipulation in tests (to check for backwards compatibility).
   432  func (m *Machine) setPasswordHash(passwordHash string) error {
   433  	ops := []txn.Op{{
   434  		C:      machinesC,
   435  		Id:     m.doc.DocID,
   436  		Assert: notDeadDoc,
   437  		Update: bson.D{{"$set", bson.D{{"passwordhash", passwordHash}}}},
   438  	}}
   439  	// A "raw" transaction is used here because this code has to work
   440  	// before the machine env UUID DB migration has run. In this case
   441  	// we don't want the automatic env UUID prefixing to the doc _id
   442  	// to occur.
   443  	if err := m.st.runRawTransaction(ops); err != nil {
   444  		return fmt.Errorf("cannot set password of machine %v: %v", m, onAbort(err, ErrDead))
   445  	}
   446  	m.doc.PasswordHash = passwordHash
   447  	return nil
   448  }
   449  
   450  // Return the underlying PasswordHash stored in the database. Used by the test
   451  // suite to check that the PasswordHash gets properly updated to new values
   452  // when compatibility mode is detected.
   453  func (m *Machine) getPasswordHash() string {
   454  	return m.doc.PasswordHash
   455  }
   456  
   457  // PasswordValid returns whether the given password is valid
   458  // for the given machine.
   459  func (m *Machine) PasswordValid(password string) bool {
   460  	agentHash := utils.AgentPasswordHash(password)
   461  	return agentHash == m.doc.PasswordHash
   462  }
   463  
   464  // Destroy sets the machine lifecycle to Dying if it is Alive. It does
   465  // nothing otherwise. Destroy will fail if the machine has principal
   466  // units assigned, or if the machine has JobManageModel.
   467  // If the machine has assigned units, Destroy will return
   468  // a HasAssignedUnitsError.
   469  func (m *Machine) Destroy() error {
   470  	return m.advanceLifecycle(Dying)
   471  }
   472  
   473  // ForceDestroy queues the machine for complete removal, including the
   474  // destruction of all units and containers on the machine.
   475  func (m *Machine) ForceDestroy() error {
   476  	ops, err := m.forceDestroyOps()
   477  	if err != nil {
   478  		return errors.Trace(err)
   479  	}
   480  	if err := m.st.runTransaction(ops); err != txn.ErrAborted {
   481  		return errors.Trace(err)
   482  	}
   483  	return nil
   484  }
   485  
   486  var managerMachineError = errors.New("machine is required by the model")
   487  
   488  func (m *Machine) forceDestroyOps() ([]txn.Op, error) {
   489  	if m.IsManager() {
   490  		return nil, errors.Trace(managerMachineError)
   491  	}
   492  
   493  	return []txn.Op{{
   494  		C:      machinesC,
   495  		Id:     m.doc.DocID,
   496  		Assert: bson.D{{"jobs", bson.D{{"$nin", []MachineJob{JobManageModel}}}}},
   497  	}, m.st.newCleanupOp(cleanupForceDestroyedMachine, m.doc.Id)}, nil
   498  }
   499  
   500  // EnsureDead sets the machine lifecycle to Dead if it is Alive or Dying.
   501  // It does nothing otherwise. EnsureDead will fail if the machine has
   502  // principal units assigned, or if the machine has JobManageModel.
   503  // If the machine has assigned units, EnsureDead will return
   504  // a HasAssignedUnitsError.
   505  func (m *Machine) EnsureDead() error {
   506  	return m.advanceLifecycle(Dead)
   507  }
   508  
   509  type HasAssignedUnitsError struct {
   510  	MachineId string
   511  	UnitNames []string
   512  }
   513  
   514  func (e *HasAssignedUnitsError) Error() string {
   515  	return fmt.Sprintf("machine %s has unit %q assigned", e.MachineId, e.UnitNames[0])
   516  }
   517  
   518  func IsHasAssignedUnitsError(err error) bool {
   519  	_, ok := err.(*HasAssignedUnitsError)
   520  	return ok
   521  }
   522  
   523  // Containers returns the container ids belonging to a parent machine.
   524  // TODO(wallyworld): move this method to a service
   525  func (m *Machine) Containers() ([]string, error) {
   526  	containerRefs, closer := m.st.getCollection(containerRefsC)
   527  	defer closer()
   528  
   529  	var mc machineContainers
   530  	err := containerRefs.FindId(m.doc.DocID).One(&mc)
   531  	if err == nil {
   532  		return mc.Children, nil
   533  	}
   534  	if err == mgo.ErrNotFound {
   535  		return nil, errors.NotFoundf("container info for machine %v", m.Id())
   536  	}
   537  	return nil, err
   538  }
   539  
   540  // ParentId returns the Id of the host machine if this machine is a container.
   541  func (m *Machine) ParentId() (string, bool) {
   542  	parentId := ParentId(m.Id())
   543  	return parentId, parentId != ""
   544  }
   545  
   546  // IsContainer returns true if the machine is a container.
   547  func (m *Machine) IsContainer() bool {
   548  	_, isContainer := m.ParentId()
   549  	return isContainer
   550  }
   551  
   552  type HasContainersError struct {
   553  	MachineId    string
   554  	ContainerIds []string
   555  }
   556  
   557  func (e *HasContainersError) Error() string {
   558  	return fmt.Sprintf("machine %s is hosting containers %q", e.MachineId, strings.Join(e.ContainerIds, ","))
   559  }
   560  
   561  // IsHasContainersError reports whether or not the error is a
   562  // HasContainersError, indicating that an attempt to destroy
   563  // a machine failed due to it having containers.
   564  func IsHasContainersError(err error) bool {
   565  	_, ok := errors.Cause(err).(*HasContainersError)
   566  	return ok
   567  }
   568  
   569  // HasAttachmentsError is the error returned by EnsureDead if the machine
   570  // has attachments to resources that must be cleaned up first.
   571  type HasAttachmentsError struct {
   572  	MachineId   string
   573  	Attachments []names.Tag
   574  }
   575  
   576  func (e *HasAttachmentsError) Error() string {
   577  	return fmt.Sprintf(
   578  		"machine %s has attachments %s",
   579  		e.MachineId, e.Attachments,
   580  	)
   581  }
   582  
   583  // IsHasAttachmentsError reports whether or not the error is a
   584  // HasAttachmentsError, indicating that an attempt to destroy
   585  // a machine failed due to it having storage attachments.
   586  func IsHasAttachmentsError(err error) bool {
   587  	_, ok := errors.Cause(err).(*HasAttachmentsError)
   588  	return ok
   589  }
   590  
   591  // advanceLifecycle ensures that the machine's lifecycle is no earlier
   592  // than the supplied value. If the machine already has that lifecycle
   593  // value, or a later one, no changes will be made to remote state. If
   594  // the machine has any responsibilities that preclude a valid change in
   595  // lifecycle, it will return an error.
   596  func (original *Machine) advanceLifecycle(life Life) (err error) {
   597  	containers, err := original.Containers()
   598  	if err != nil {
   599  		return err
   600  	}
   601  	if len(containers) > 0 {
   602  		return &HasContainersError{
   603  			MachineId:    original.doc.Id,
   604  			ContainerIds: containers,
   605  		}
   606  	}
   607  	m := original
   608  	defer func() {
   609  		if err == nil {
   610  			// The machine's lifecycle is known to have advanced; it may be
   611  			// known to have already advanced further than requested, in
   612  			// which case we set the latest known valid value.
   613  			if m == nil {
   614  				life = Dead
   615  			} else if m.doc.Life > life {
   616  				life = m.doc.Life
   617  			}
   618  			original.doc.Life = life
   619  		}
   620  	}()
   621  	// op and
   622  	op := txn.Op{
   623  		C:      machinesC,
   624  		Id:     m.doc.DocID,
   625  		Update: bson.D{{"$set", bson.D{{"life", life}}}},
   626  	}
   627  	// noUnits asserts that the machine has no principal units.
   628  	noUnits := bson.DocElem{
   629  		"$or", []bson.D{
   630  			{{"principals", bson.D{{"$size", 0}}}},
   631  			{{"principals", bson.D{{"$exists", false}}}},
   632  		},
   633  	}
   634  	cleanupOp := m.st.newCleanupOp(cleanupDyingMachine, m.doc.Id)
   635  	// multiple attempts: one with original data, one with refreshed data, and a final
   636  	// one intended to determine the cause of failure of the preceding attempt.
   637  	buildTxn := func(attempt int) ([]txn.Op, error) {
   638  		advanceAsserts := bson.D{
   639  			{"jobs", bson.D{{"$nin", []MachineJob{JobManageModel}}}},
   640  			{"hasvote", bson.D{{"$ne", true}}},
   641  		}
   642  		// Grab a fresh copy of the machine data.
   643  		// We don't write to original, because the expectation is that state-
   644  		// changing methods only set the requested change on the receiver; a case
   645  		// could perhaps be made that this is not a helpful convention in the
   646  		// context of the new state API, but we maintain consistency in the
   647  		// face of uncertainty.
   648  		if m, err = m.st.Machine(m.doc.Id); errors.IsNotFound(err) {
   649  			return nil, jujutxn.ErrNoOperations
   650  		} else if err != nil {
   651  			return nil, err
   652  		}
   653  		// Check that the life change is sane, and collect the assertions
   654  		// necessary to determine that it remains so.
   655  		switch life {
   656  		case Dying:
   657  			if m.doc.Life != Alive {
   658  				return nil, jujutxn.ErrNoOperations
   659  			}
   660  			advanceAsserts = append(advanceAsserts, isAliveDoc...)
   661  		case Dead:
   662  			if m.doc.Life == Dead {
   663  				return nil, jujutxn.ErrNoOperations
   664  			}
   665  			advanceAsserts = append(advanceAsserts, notDeadDoc...)
   666  		default:
   667  			panic(fmt.Errorf("cannot advance lifecycle to %v", life))
   668  		}
   669  		// Check that the machine does not have any responsibilities that
   670  		// prevent a lifecycle change.
   671  		if hasJob(m.doc.Jobs, JobManageModel) {
   672  			// (NOTE: When we enable multiple JobManageModel machines,
   673  			// this restriction will be lifted, but we will assert that the
   674  			// machine is not voting)
   675  			return nil, fmt.Errorf("machine %s is required by the model", m.doc.Id)
   676  		}
   677  		if m.doc.HasVote {
   678  			return nil, fmt.Errorf("machine %s is a voting replica set member", m.doc.Id)
   679  		}
   680  		// If there are no alive units left on the machine, or all the services are dying,
   681  		// then the machine may be soon destroyed by a cleanup worker.
   682  		// In that case, we don't want to return any error about not being able to
   683  		// destroy a machine with units as it will be a lie.
   684  		if life == Dying {
   685  			canDie := true
   686  			var principalUnitnames []string
   687  			for _, principalUnit := range m.doc.Principals {
   688  				principalUnitnames = append(principalUnitnames, principalUnit)
   689  				u, err := m.st.Unit(principalUnit)
   690  				if err != nil {
   691  					return nil, errors.Annotatef(err, "reading machine %s principal unit %v", m, m.doc.Principals[0])
   692  				}
   693  				svc, err := u.Service()
   694  				if err != nil {
   695  					return nil, errors.Annotatef(err, "reading machine %s principal unit service %v", m, u.doc.Service)
   696  				}
   697  				if u.Life() == Alive && svc.Life() == Alive {
   698  					canDie = false
   699  					break
   700  				}
   701  			}
   702  			if canDie {
   703  				containers, err := m.Containers()
   704  				if err != nil {
   705  					return nil, errors.Annotatef(err, "reading machine %s containers", m)
   706  				}
   707  				canDie = len(containers) == 0
   708  			}
   709  			if canDie {
   710  				checkUnits := bson.DocElem{
   711  					"$or", []bson.D{
   712  						{{"principals", principalUnitnames}},
   713  						{{"principals", bson.D{{"$size", 0}}}},
   714  						{{"principals", bson.D{{"$exists", false}}}},
   715  					},
   716  				}
   717  				op.Assert = append(advanceAsserts, checkUnits)
   718  				containerCheck := txn.Op{
   719  					C:  containerRefsC,
   720  					Id: m.doc.DocID,
   721  					Assert: bson.D{{"$or", []bson.D{
   722  						{{"children", bson.D{{"$size", 0}}}},
   723  						{{"children", bson.D{{"$exists", false}}}},
   724  					}}},
   725  				}
   726  				return []txn.Op{op, containerCheck, cleanupOp}, nil
   727  			}
   728  		}
   729  
   730  		if len(m.doc.Principals) > 0 {
   731  			return nil, &HasAssignedUnitsError{
   732  				MachineId: m.doc.Id,
   733  				UnitNames: m.doc.Principals,
   734  			}
   735  		}
   736  		advanceAsserts = append(advanceAsserts, noUnits)
   737  
   738  		if life == Dead {
   739  			// A machine may not become Dead until it has no more
   740  			// attachments to inherently machine-bound storage.
   741  			storageAsserts, err := m.assertNoPersistentStorage()
   742  			if err != nil {
   743  				return nil, errors.Trace(err)
   744  			}
   745  			advanceAsserts = append(advanceAsserts, storageAsserts...)
   746  		}
   747  
   748  		// Add the additional asserts needed for this transaction.
   749  		op.Assert = advanceAsserts
   750  		return []txn.Op{op, cleanupOp}, nil
   751  	}
   752  	if err = m.st.run(buildTxn); err == jujutxn.ErrExcessiveContention {
   753  		err = errors.Annotatef(err, "machine %s cannot advance lifecycle", m)
   754  	}
   755  	return err
   756  }
   757  
   758  // assertNoPersistentStorage ensures that there are no persistent volumes or
   759  // filesystems attached to the machine, and returns any mgo/txn assertions
   760  // required to ensure that remains true.
   761  func (m *Machine) assertNoPersistentStorage() (bson.D, error) {
   762  	attachments := make(set.Tags)
   763  	for _, v := range m.doc.Volumes {
   764  		tag := names.NewVolumeTag(v)
   765  		machineBound, err := isVolumeInherentlyMachineBound(m.st, tag)
   766  		if err != nil {
   767  			return nil, errors.Trace(err)
   768  		}
   769  		if !machineBound {
   770  			attachments.Add(tag)
   771  		}
   772  	}
   773  	for _, f := range m.doc.Filesystems {
   774  		tag := names.NewFilesystemTag(f)
   775  		machineBound, err := isFilesystemInherentlyMachineBound(m.st, tag)
   776  		if err != nil {
   777  			return nil, errors.Trace(err)
   778  		}
   779  		if !machineBound {
   780  			attachments.Add(tag)
   781  		}
   782  	}
   783  	if len(attachments) > 0 {
   784  		return nil, &HasAttachmentsError{
   785  			MachineId:   m.doc.Id,
   786  			Attachments: attachments.SortedValues(),
   787  		}
   788  	}
   789  	if m.doc.Life == Dying {
   790  		return nil, nil
   791  	}
   792  	// A Dying machine cannot have attachments added to it,
   793  	// but if we're advancing from Alive to Dead then we
   794  	// must ensure no concurrent attachments are made.
   795  	noNewVolumes := bson.DocElem{
   796  		"volumes", bson.D{{
   797  			"$not", bson.D{{
   798  				"$elemMatch", bson.D{{
   799  					"$nin", m.doc.Volumes,
   800  				}},
   801  			}},
   802  		}},
   803  		// There are no volumes that are not in
   804  		// the set of volumes we previously knew
   805  		// about => the current set of volumes
   806  		// is a subset of the previously known set.
   807  	}
   808  	noNewFilesystems := bson.DocElem{
   809  		"filesystems", bson.D{{
   810  			"$not", bson.D{{
   811  				"$elemMatch", bson.D{{
   812  					"$nin", m.doc.Filesystems,
   813  				}},
   814  			}},
   815  		}},
   816  	}
   817  	return bson.D{noNewVolumes, noNewFilesystems}, nil
   818  }
   819  
   820  func (m *Machine) removePortsOps() ([]txn.Op, error) {
   821  	if m.doc.Life != Dead {
   822  		return nil, errors.Errorf("machine is not dead")
   823  	}
   824  	ports, err := m.AllPorts()
   825  	if err != nil {
   826  		return nil, err
   827  	}
   828  	var ops []txn.Op
   829  	for _, p := range ports {
   830  		ops = append(ops, p.removeOps()...)
   831  	}
   832  	return ops, nil
   833  }
   834  
   835  // Remove removes the machine from state. It will fail if the machine
   836  // is not Dead.
   837  func (m *Machine) Remove() (err error) {
   838  	defer errors.DeferredAnnotatef(&err, "cannot remove machine %s", m.doc.Id)
   839  	if m.doc.Life != Dead {
   840  		return fmt.Errorf("machine is not dead")
   841  	}
   842  	ops := []txn.Op{
   843  		{
   844  			C:      machinesC,
   845  			Id:     m.doc.DocID,
   846  			Assert: txn.DocExists,
   847  			Remove: true,
   848  		},
   849  		{
   850  			C:      machinesC,
   851  			Id:     m.doc.DocID,
   852  			Assert: isDeadDoc,
   853  		},
   854  		removeStatusOp(m.st, m.globalKey()),
   855  		removeStatusOp(m.st, m.globalInstanceKey()),
   856  		removeConstraintsOp(m.st, m.globalKey()),
   857  		annotationRemoveOp(m.st, m.globalKey()),
   858  		removeRebootDocOp(m.st, m.globalKey()),
   859  		removeMachineBlockDevicesOp(m.Id()),
   860  		removeModelMachineRefOp(m.st, m.Id()),
   861  		removeSSHHostKeyOp(m.st, m.globalKey()),
   862  	}
   863  	linkLayerDevicesOps, err := m.removeAllLinkLayerDevicesOps()
   864  	if err != nil {
   865  		return err
   866  	}
   867  	devicesAddressesOps, err := m.removeAllAddressesOps()
   868  	if err != nil {
   869  		return err
   870  	}
   871  	portsOps, err := m.removePortsOps()
   872  	if err != nil {
   873  		return err
   874  	}
   875  	filesystemOps, err := m.st.removeMachineFilesystemsOps(m.MachineTag())
   876  	if err != nil {
   877  		return err
   878  	}
   879  	volumeOps, err := m.st.removeMachineVolumesOps(m.MachineTag())
   880  	if err != nil {
   881  		return err
   882  	}
   883  	ops = append(ops, linkLayerDevicesOps...)
   884  	ops = append(ops, devicesAddressesOps...)
   885  	ops = append(ops, portsOps...)
   886  	ops = append(ops, removeContainerRefOps(m.st, m.Id())...)
   887  	ops = append(ops, filesystemOps...)
   888  	ops = append(ops, volumeOps...)
   889  	ipAddresses, err := m.st.AllocatedIPAddresses(m.Id())
   890  	if err != nil {
   891  		return errors.Trace(err)
   892  	}
   893  	for _, address := range ipAddresses {
   894  		logger.Tracef("creating op to set IP addr %q to Dead", address.Value())
   895  		ops = append(ops, ensureIPAddressDeadOp(address))
   896  	}
   897  	logger.Tracef("removing machine %q", m.Id())
   898  	// The only abort conditions in play indicate that the machine has already
   899  	// been removed.
   900  	return onAbort(m.st.runTransaction(ops), nil)
   901  }
   902  
   903  // Refresh refreshes the contents of the machine from the underlying
   904  // state. It returns an error that satisfies errors.IsNotFound if the
   905  // machine has been removed.
   906  func (m *Machine) Refresh() error {
   907  	mdoc, err := m.st.getMachineDoc(m.Id())
   908  	if err != nil {
   909  		if errors.IsNotFound(err) {
   910  			return err
   911  		}
   912  		return errors.Annotatef(err, "cannot refresh machine %v", m)
   913  	}
   914  	m.doc = *mdoc
   915  	return nil
   916  }
   917  
   918  // AgentPresence returns whether the respective remote agent is alive.
   919  func (m *Machine) AgentPresence() (bool, error) {
   920  	b, err := m.st.pwatcher.Alive(m.globalKey())
   921  	return b, err
   922  }
   923  
   924  // WaitAgentPresence blocks until the respective agent is alive.
   925  func (m *Machine) WaitAgentPresence(timeout time.Duration) (err error) {
   926  	defer errors.DeferredAnnotatef(&err, "waiting for agent of machine %v", m)
   927  	ch := make(chan presence.Change)
   928  	m.st.pwatcher.Watch(m.globalKey(), ch)
   929  	defer m.st.pwatcher.Unwatch(m.globalKey(), ch)
   930  	for i := 0; i < 2; i++ {
   931  		select {
   932  		case change := <-ch:
   933  			if change.Alive {
   934  				return nil
   935  			}
   936  		case <-time.After(timeout):
   937  			// TODO(fwereade): 2016-03-17 lp:1558657
   938  			return fmt.Errorf("still not alive after timeout")
   939  		case <-m.st.pwatcher.Dead():
   940  			return m.st.pwatcher.Err()
   941  		}
   942  	}
   943  	panic(fmt.Sprintf("presence reported dead status twice in a row for machine %v", m))
   944  }
   945  
   946  // SetAgentPresence signals that the agent for machine m is alive.
   947  // It returns the started pinger.
   948  func (m *Machine) SetAgentPresence() (*presence.Pinger, error) {
   949  	presenceCollection := m.st.getPresence()
   950  	p := presence.NewPinger(presenceCollection, m.st.modelTag, m.globalKey())
   951  	err := p.Start()
   952  	if err != nil {
   953  		return nil, err
   954  	}
   955  	// We preform a manual sync here so that the
   956  	// presence pinger has the most up-to-date information when it
   957  	// starts. This ensures that commands run immediately after bootstrap
   958  	// like status or enable-ha will have an accurate values
   959  	// for agent-state.
   960  	//
   961  	// TODO: Does not work for multiple controllers. Trigger a sync across all controllers.
   962  	if m.IsManager() {
   963  		m.st.pwatcher.Sync()
   964  	}
   965  	return p, nil
   966  }
   967  
   968  // InstanceId returns the provider specific instance id for this
   969  // machine, or a NotProvisionedError, if not set.
   970  func (m *Machine) InstanceId() (instance.Id, error) {
   971  	instData, err := getInstanceData(m.st, m.Id())
   972  	if errors.IsNotFound(err) {
   973  		err = errors.NotProvisionedf("machine %v", m.Id())
   974  	}
   975  	if err != nil {
   976  		return "", err
   977  	}
   978  	return instData.InstanceId, err
   979  }
   980  
   981  // InstanceStatus returns the provider specific instance status for this machine,
   982  // or a NotProvisionedError if instance is not yet provisioned.
   983  func (m *Machine) InstanceStatus() (status.StatusInfo, error) {
   984  	machineStatus, err := getStatus(m.st, m.globalInstanceKey(), "instance")
   985  	if err != nil {
   986  		logger.Warningf("error when retrieving instance status for machine: %s, %v", m.Id(), err)
   987  		return status.StatusInfo{}, err
   988  	}
   989  	return machineStatus, nil
   990  }
   991  
   992  // SetInstanceStatus sets the provider specific instance status for a machine.
   993  func (m *Machine) SetInstanceStatus(instanceStatus status.Status, info string, data map[string]interface{}) (err error) {
   994  	return setStatus(m.st, setStatusParams{
   995  		badge:     "instance",
   996  		globalKey: m.globalInstanceKey(),
   997  		status:    instanceStatus,
   998  		message:   info,
   999  		rawData:   data,
  1000  	})
  1001  
  1002  }
  1003  
  1004  // InstanceStatusHistory returns a slice of at most <size> StatusInfo items
  1005  // representing past statuses for this machine instance.
  1006  // Instance represents the provider underlying [v]hardware or container where
  1007  // this juju machine is deployed.
  1008  func (u *Machine) InstanceStatusHistory(size int) ([]status.StatusInfo, error) {
  1009  	return statusHistory(u.st, u.globalInstanceKey(), size)
  1010  }
  1011  
  1012  // AvailabilityZone returns the provier-specific instance availability
  1013  // zone in which the machine was provisioned.
  1014  func (m *Machine) AvailabilityZone() (string, error) {
  1015  	instData, err := getInstanceData(m.st, m.Id())
  1016  	if errors.IsNotFound(err) {
  1017  		return "", errors.Trace(errors.NotProvisionedf("machine %v", m.Id()))
  1018  	}
  1019  	if err != nil {
  1020  		return "", errors.Trace(err)
  1021  	}
  1022  	var zone string
  1023  	if instData.AvailZone != nil {
  1024  		zone = *instData.AvailZone
  1025  	}
  1026  	return zone, nil
  1027  }
  1028  
  1029  // Units returns all the units that have been assigned to the machine.
  1030  func (m *Machine) Units() (units []*Unit, err error) {
  1031  	defer errors.DeferredAnnotatef(&err, "cannot get units assigned to machine %v", m)
  1032  	unitsCollection, closer := m.st.getCollection(unitsC)
  1033  	defer closer()
  1034  
  1035  	pudocs := []unitDoc{}
  1036  	err = unitsCollection.Find(bson.D{{"machineid", m.doc.Id}}).All(&pudocs)
  1037  	if err != nil {
  1038  		return nil, err
  1039  	}
  1040  	for _, pudoc := range pudocs {
  1041  		units = append(units, newUnit(m.st, &pudoc))
  1042  		docs := []unitDoc{}
  1043  		err = unitsCollection.Find(bson.D{{"principal", pudoc.Name}}).All(&docs)
  1044  		if err != nil {
  1045  			return nil, err
  1046  		}
  1047  		for _, doc := range docs {
  1048  			units = append(units, newUnit(m.st, &doc))
  1049  		}
  1050  	}
  1051  	return units, nil
  1052  }
  1053  
  1054  // SetProvisioned sets the provider specific machine id, nonce and also metadata for
  1055  // this machine. Once set, the instance id cannot be changed.
  1056  //
  1057  // When provisioning an instance, a nonce should be created and passed
  1058  // when starting it, before adding the machine to the state. This means
  1059  // that if the provisioner crashes (or its connection to the state is
  1060  // lost) after starting the instance, we can be sure that only a single
  1061  // instance will be able to act for that machine.
  1062  func (m *Machine) SetProvisioned(id instance.Id, nonce string, characteristics *instance.HardwareCharacteristics) (err error) {
  1063  	defer errors.DeferredAnnotatef(&err, "cannot set instance data for machine %q", m)
  1064  
  1065  	if id == "" || nonce == "" {
  1066  		return fmt.Errorf("instance id and nonce cannot be empty")
  1067  	}
  1068  
  1069  	if characteristics == nil {
  1070  		characteristics = &instance.HardwareCharacteristics{}
  1071  	}
  1072  	instData := &instanceData{
  1073  		DocID:      m.doc.DocID,
  1074  		MachineId:  m.doc.Id,
  1075  		InstanceId: id,
  1076  		ModelUUID:  m.doc.ModelUUID,
  1077  		Arch:       characteristics.Arch,
  1078  		Mem:        characteristics.Mem,
  1079  		RootDisk:   characteristics.RootDisk,
  1080  		CpuCores:   characteristics.CpuCores,
  1081  		CpuPower:   characteristics.CpuPower,
  1082  		Tags:       characteristics.Tags,
  1083  		AvailZone:  characteristics.AvailabilityZone,
  1084  	}
  1085  
  1086  	ops := []txn.Op{
  1087  		{
  1088  			C:      machinesC,
  1089  			Id:     m.doc.DocID,
  1090  			Assert: append(isAliveDoc, bson.DocElem{"nonce", ""}),
  1091  			Update: bson.D{{"$set", bson.D{{"nonce", nonce}}}},
  1092  		}, {
  1093  			C:      instanceDataC,
  1094  			Id:     m.doc.DocID,
  1095  			Assert: txn.DocMissing,
  1096  			Insert: instData,
  1097  		},
  1098  	}
  1099  
  1100  	if err = m.st.runTransaction(ops); err == nil {
  1101  		m.doc.Nonce = nonce
  1102  		return nil
  1103  	} else if err != txn.ErrAborted {
  1104  		return err
  1105  	} else if alive, err := isAlive(m.st, machinesC, m.doc.DocID); err != nil {
  1106  		return err
  1107  	} else if !alive {
  1108  		return errNotAlive
  1109  	}
  1110  	return fmt.Errorf("already set")
  1111  }
  1112  
  1113  // SetInstanceInfo is used to provision a machine and in one steps set it's
  1114  // instance id, nonce, hardware characteristics, add link-layer devices and set
  1115  // their addresses as needed.
  1116  func (m *Machine) SetInstanceInfo(
  1117  	id instance.Id, nonce string, characteristics *instance.HardwareCharacteristics,
  1118  	devicesArgs []LinkLayerDeviceArgs, devicesAddrs []LinkLayerDeviceAddress,
  1119  	volumes map[names.VolumeTag]VolumeInfo,
  1120  	volumeAttachments map[names.VolumeTag]VolumeAttachmentInfo,
  1121  ) error {
  1122  
  1123  	if err := m.SetParentLinkLayerDevicesBeforeTheirChildren(devicesArgs); err != nil {
  1124  		return errors.Trace(err)
  1125  	}
  1126  	if err := m.SetDevicesAddressesIdempotently(devicesAddrs); err != nil {
  1127  		return errors.Trace(err)
  1128  	}
  1129  	if err := setProvisionedVolumeInfo(m.st, volumes); err != nil {
  1130  		return errors.Trace(err)
  1131  	}
  1132  	if err := setMachineVolumeAttachmentInfo(m.st, m.Id(), volumeAttachments); err != nil {
  1133  		return errors.Trace(err)
  1134  	}
  1135  	return m.SetProvisioned(id, nonce, characteristics)
  1136  }
  1137  
  1138  // Addresses returns any hostnames and ips associated with a machine,
  1139  // determined both by the machine itself, and by asking the provider.
  1140  //
  1141  // The addresses returned by the provider shadow any of the addresses
  1142  // that the machine reported with the same address value.
  1143  // Provider-reported addresses always come before machine-reported
  1144  // addresses. Duplicates are removed.
  1145  func (m *Machine) Addresses() (addresses []network.Address) {
  1146  	return network.MergedAddresses(networkAddresses(m.doc.MachineAddresses), networkAddresses(m.doc.Addresses))
  1147  }
  1148  
  1149  func containsAddress(addresses []address, address address) bool {
  1150  	for _, addr := range addresses {
  1151  		if addr.Value == address.Value {
  1152  			return true
  1153  		}
  1154  	}
  1155  	return false
  1156  }
  1157  
  1158  // PublicAddress returns a public address for the machine. If no address is
  1159  // available it returns an error that satisfies network.IsNoAddress.
  1160  func (m *Machine) PublicAddress() (network.Address, error) {
  1161  	publicAddress := m.doc.PreferredPublicAddress.networkAddress()
  1162  	var err error
  1163  	if publicAddress.Value == "" {
  1164  		err = network.NoAddressf("public")
  1165  	}
  1166  	return publicAddress, err
  1167  }
  1168  
  1169  // maybeGetNewAddress determines if the current address is the most appropriate
  1170  // match, and if not it selects the best from the slice of all available
  1171  // addresses. It returns the new address and a bool indicating if a different
  1172  // one was picked.
  1173  func maybeGetNewAddress(addr address, providerAddresses, machineAddresses []address, getAddr func([]address) network.Address, checkScope func(address) bool) (address, bool) {
  1174  	// For picking the best address, try provider addresses first.
  1175  	var newAddr address
  1176  	netAddr := getAddr(providerAddresses)
  1177  	if netAddr.Value == "" {
  1178  		netAddr = getAddr(machineAddresses)
  1179  		newAddr = fromNetworkAddress(netAddr, OriginMachine)
  1180  	} else {
  1181  		newAddr = fromNetworkAddress(netAddr, OriginProvider)
  1182  	}
  1183  	// The order of these checks is important. If the stored address is
  1184  	// empty we *always* want to check for a new address so we do that
  1185  	// first. If the stored address is unavilable we also *must* check for
  1186  	// a new address so we do that next. If the original is a machine
  1187  	// address and a provider address is available we want to switch to
  1188  	// that. Finally we check to see if a better match on scope from the
  1189  	// same origin is available.
  1190  	if addr.Value == "" {
  1191  		return newAddr, newAddr.Value != ""
  1192  	}
  1193  	if !containsAddress(providerAddresses, addr) && !containsAddress(machineAddresses, addr) {
  1194  		return newAddr, true
  1195  	}
  1196  	if Origin(addr.Origin) != OriginProvider && Origin(newAddr.Origin) == OriginProvider {
  1197  		return newAddr, true
  1198  	}
  1199  	if !checkScope(addr) {
  1200  		// If addr.Origin is machine and newAddr.Origin is provider we will
  1201  		// have already caught that, and for the inverse we don't want to
  1202  		// replace the address.
  1203  		if addr.Origin == newAddr.Origin {
  1204  			return newAddr, checkScope(newAddr)
  1205  		}
  1206  	}
  1207  	return addr, false
  1208  }
  1209  
  1210  // PrivateAddress returns a private address for the machine. If no address is
  1211  // available it returns an error that satisfies network.IsNoAddress.
  1212  func (m *Machine) PrivateAddress() (network.Address, error) {
  1213  	privateAddress := m.doc.PreferredPrivateAddress.networkAddress()
  1214  	var err error
  1215  	if privateAddress.Value == "" {
  1216  		err = network.NoAddressf("private")
  1217  	}
  1218  	return privateAddress, err
  1219  }
  1220  
  1221  func (m *Machine) setPreferredAddressOps(addr address, isPublic bool) []txn.Op {
  1222  	fieldName := "preferredprivateaddress"
  1223  	current := m.doc.PreferredPrivateAddress
  1224  	if isPublic {
  1225  		fieldName = "preferredpublicaddress"
  1226  		current = m.doc.PreferredPublicAddress
  1227  	}
  1228  	// Assert that the field is either missing (never been set) or is
  1229  	// unchanged from its previous value.
  1230  	assert := bson.D{{"$or", []bson.D{{{fieldName, current}}, {{fieldName, nil}}}}}
  1231  
  1232  	ops := []txn.Op{{
  1233  		C:      machinesC,
  1234  		Id:     m.doc.DocID,
  1235  		Update: bson.D{{"$set", bson.D{{fieldName, addr}}}},
  1236  		Assert: assert,
  1237  	}}
  1238  	return ops
  1239  }
  1240  
  1241  func (m *Machine) setPublicAddressOps(providerAddresses []address, machineAddresses []address) ([]txn.Op, address, bool) {
  1242  	publicAddress := m.doc.PreferredPublicAddress
  1243  	// Always prefer an exact match if available.
  1244  	checkScope := func(addr address) bool {
  1245  		return network.ExactScopeMatch(addr.networkAddress(), network.ScopePublic)
  1246  	}
  1247  	// Without an exact match, prefer a fallback match.
  1248  	getAddr := func(addresses []address) network.Address {
  1249  		addr, _ := network.SelectPublicAddress(networkAddresses(addresses))
  1250  		return addr
  1251  	}
  1252  
  1253  	newAddr, changed := maybeGetNewAddress(publicAddress, providerAddresses, machineAddresses, getAddr, checkScope)
  1254  	if !changed {
  1255  		// No change, so no ops.
  1256  		return []txn.Op{}, publicAddress, false
  1257  	}
  1258  
  1259  	ops := m.setPreferredAddressOps(newAddr, true)
  1260  	return ops, newAddr, true
  1261  }
  1262  
  1263  func (m *Machine) setPrivateAddressOps(providerAddresses []address, machineAddresses []address) ([]txn.Op, address, bool) {
  1264  	privateAddress := m.doc.PreferredPrivateAddress
  1265  	// Always prefer an exact match if available.
  1266  	checkScope := func(addr address) bool {
  1267  		return network.ExactScopeMatch(addr.networkAddress(), network.ScopeMachineLocal, network.ScopeCloudLocal)
  1268  	}
  1269  	// Without an exact match, prefer a fallback match.
  1270  	getAddr := func(addresses []address) network.Address {
  1271  		addr, _ := network.SelectInternalAddress(networkAddresses(addresses), false)
  1272  		return addr
  1273  	}
  1274  
  1275  	newAddr, changed := maybeGetNewAddress(privateAddress, providerAddresses, machineAddresses, getAddr, checkScope)
  1276  	if !changed {
  1277  		// No change, so no ops.
  1278  		return []txn.Op{}, privateAddress, false
  1279  	}
  1280  	ops := m.setPreferredAddressOps(newAddr, false)
  1281  	return ops, newAddr, true
  1282  }
  1283  
  1284  // SetProviderAddresses records any addresses related to the machine, sourced
  1285  // by asking the provider.
  1286  func (m *Machine) SetProviderAddresses(addresses ...network.Address) (err error) {
  1287  	mdoc, err := m.st.getMachineDoc(m.Id())
  1288  	if err != nil {
  1289  		return errors.Annotatef(err, "cannot refresh provider addresses for machine %s", m)
  1290  	}
  1291  	if err = m.setAddresses(addresses, &mdoc.Addresses, "addresses"); err != nil {
  1292  		return fmt.Errorf("cannot set addresses of machine %v: %v", m, err)
  1293  	}
  1294  	m.doc.Addresses = mdoc.Addresses
  1295  	return nil
  1296  }
  1297  
  1298  // ProviderAddresses returns any hostnames and ips associated with a machine,
  1299  // as determined by asking the provider.
  1300  func (m *Machine) ProviderAddresses() (addresses []network.Address) {
  1301  	for _, address := range m.doc.Addresses {
  1302  		addresses = append(addresses, address.networkAddress())
  1303  	}
  1304  	return
  1305  }
  1306  
  1307  // MachineAddresses returns any hostnames and ips associated with a machine,
  1308  // determined by asking the machine itself.
  1309  func (m *Machine) MachineAddresses() (addresses []network.Address) {
  1310  	for _, address := range m.doc.MachineAddresses {
  1311  		addresses = append(addresses, address.networkAddress())
  1312  	}
  1313  	return
  1314  }
  1315  
  1316  // SetMachineAddresses records any addresses related to the machine, sourced
  1317  // by asking the machine.
  1318  func (m *Machine) SetMachineAddresses(addresses ...network.Address) (err error) {
  1319  	mdoc, err := m.st.getMachineDoc(m.Id())
  1320  	if err != nil {
  1321  		return errors.Annotatef(err, "cannot refresh machine addresses for machine %s", m)
  1322  	}
  1323  	if err = m.setAddresses(addresses, &mdoc.MachineAddresses, "machineaddresses"); err != nil {
  1324  		return fmt.Errorf("cannot set machine addresses of machine %v: %v", m, err)
  1325  	}
  1326  	m.doc.MachineAddresses = mdoc.MachineAddresses
  1327  	return nil
  1328  }
  1329  
  1330  // setAddresses updates the machine's addresses (either Addresses or
  1331  // MachineAddresses, depending on the field argument). Changes are
  1332  // only predicated on the machine not being Dead; concurrent address
  1333  // changes are ignored.
  1334  func (m *Machine) setAddresses(addresses []network.Address, field *[]address, fieldName string) error {
  1335  	var addressesToSet []network.Address
  1336  	if !m.IsContainer() {
  1337  		// Check addresses first. We'll only add those addresses
  1338  		// which are not in the IP address collection.
  1339  		ipAddresses, closer := m.st.getCollection(legacyipaddressesC)
  1340  		defer closer()
  1341  
  1342  		addressValues := make([]string, len(addresses))
  1343  		for i, address := range addresses {
  1344  			addressValues[i] = address.Value
  1345  		}
  1346  		ipDocs := []ipaddressDoc{}
  1347  		sel := bson.D{{"value", bson.D{{"$in", addressValues}}}, {"state", AddressStateAllocated}}
  1348  		err := ipAddresses.Find(sel).All(&ipDocs)
  1349  		if err != nil {
  1350  			return err
  1351  		}
  1352  		ipDocValues := set.NewStrings()
  1353  		for _, ipDoc := range ipDocs {
  1354  			ipDocValues.Add(ipDoc.Value)
  1355  		}
  1356  		for _, address := range addresses {
  1357  			if !ipDocValues.Contains(address.Value) {
  1358  				addressesToSet = append(addressesToSet, address)
  1359  			}
  1360  		}
  1361  	} else {
  1362  		// Containers will set all addresses.
  1363  		addressesToSet = make([]network.Address, len(addresses))
  1364  		copy(addressesToSet, addresses)
  1365  	}
  1366  
  1367  	// Update addresses now.
  1368  	envConfig, err := m.st.ModelConfig()
  1369  	if err != nil {
  1370  		return err
  1371  	}
  1372  	network.SortAddresses(addressesToSet, envConfig.PreferIPv6())
  1373  	origin := OriginProvider
  1374  	if fieldName == "machineaddresses" {
  1375  		origin = OriginMachine
  1376  	}
  1377  	stateAddresses := fromNetworkAddresses(addressesToSet, origin)
  1378  
  1379  	var newPrivate, newPublic address
  1380  	var changedPrivate, changedPublic bool
  1381  	machine := m
  1382  	buildTxn := func(attempt int) ([]txn.Op, error) {
  1383  		if attempt != 0 {
  1384  			if machine, err = machine.st.Machine(machine.doc.Id); err != nil {
  1385  				return nil, err
  1386  			}
  1387  		}
  1388  		if machine.doc.Life == Dead {
  1389  			return nil, errNotAlive
  1390  		}
  1391  		ops := []txn.Op{{
  1392  			C:      machinesC,
  1393  			Id:     machine.doc.DocID,
  1394  			Assert: notDeadDoc,
  1395  			Update: bson.D{{"$set", bson.D{{fieldName, stateAddresses}}}},
  1396  		}}
  1397  
  1398  		var providerAddresses []address
  1399  		var machineAddresses []address
  1400  		if fieldName == "machineaddresses" {
  1401  			providerAddresses = machine.doc.Addresses
  1402  			machineAddresses = stateAddresses
  1403  		} else {
  1404  			machineAddresses = machine.doc.MachineAddresses
  1405  			providerAddresses = stateAddresses
  1406  		}
  1407  
  1408  		var setPrivateAddressOps, setPublicAddressOps []txn.Op
  1409  		setPrivateAddressOps, newPrivate, changedPrivate = machine.setPrivateAddressOps(providerAddresses, machineAddresses)
  1410  		setPublicAddressOps, newPublic, changedPublic = machine.setPublicAddressOps(providerAddresses, machineAddresses)
  1411  		ops = append(ops, setPrivateAddressOps...)
  1412  		ops = append(ops, setPublicAddressOps...)
  1413  		return ops, nil
  1414  	}
  1415  	err = m.st.run(buildTxn)
  1416  	if err != nil {
  1417  		if err == txn.ErrAborted {
  1418  			return ErrDead
  1419  		}
  1420  		return errors.Trace(err)
  1421  	}
  1422  
  1423  	*field = stateAddresses
  1424  	if changedPrivate {
  1425  		m.doc.PreferredPrivateAddress = newPrivate
  1426  	}
  1427  	if changedPublic {
  1428  		m.doc.PreferredPublicAddress = newPublic
  1429  	}
  1430  	return nil
  1431  }
  1432  
  1433  // CheckProvisioned returns true if the machine was provisioned with the given nonce.
  1434  func (m *Machine) CheckProvisioned(nonce string) bool {
  1435  	return nonce == m.doc.Nonce && nonce != ""
  1436  }
  1437  
  1438  // String returns a unique description of this machine.
  1439  func (m *Machine) String() string {
  1440  	return m.doc.Id
  1441  }
  1442  
  1443  // Placement returns the machine's Placement structure that should be used when
  1444  // provisioning an instance for the machine.
  1445  func (m *Machine) Placement() string {
  1446  	return m.doc.Placement
  1447  }
  1448  
  1449  // Constraints returns the exact constraints that should apply when provisioning
  1450  // an instance for the machine.
  1451  func (m *Machine) Constraints() (constraints.Value, error) {
  1452  	return readConstraints(m.st, m.globalKey())
  1453  }
  1454  
  1455  // SetConstraints sets the exact constraints to apply when provisioning an
  1456  // instance for the machine. It will fail if the machine is Dead, or if it
  1457  // is already provisioned.
  1458  func (m *Machine) SetConstraints(cons constraints.Value) (err error) {
  1459  	defer errors.DeferredAnnotatef(&err, "cannot set constraints")
  1460  	unsupported, err := m.st.validateConstraints(cons)
  1461  	if len(unsupported) > 0 {
  1462  		logger.Warningf(
  1463  			"setting constraints on machine %q: unsupported constraints: %v", m.Id(), strings.Join(unsupported, ","))
  1464  	} else if err != nil {
  1465  		return err
  1466  	}
  1467  	notSetYet := bson.D{{"nonce", ""}}
  1468  	ops := []txn.Op{{
  1469  		C:      machinesC,
  1470  		Id:     m.doc.DocID,
  1471  		Assert: append(isAliveDoc, notSetYet...),
  1472  	}}
  1473  	mcons, err := m.st.resolveMachineConstraints(cons)
  1474  	if err != nil {
  1475  		return err
  1476  	}
  1477  
  1478  	ops = append(ops, setConstraintsOp(m.st, m.globalKey(), mcons))
  1479  	// make multiple attempts to push the ErrExcessiveContention case out of the
  1480  	// realm of plausibility: it implies local state indicating unprovisioned,
  1481  	// and remote state indicating provisioned (reasonable); but which changes
  1482  	// back to unprovisioned and then to provisioned again with *very* specific
  1483  	// timing in the course of this loop.
  1484  	buildTxn := func(attempt int) ([]txn.Op, error) {
  1485  		if attempt > 0 {
  1486  			if m, err = m.st.Machine(m.doc.Id); err != nil {
  1487  				return nil, err
  1488  			}
  1489  		}
  1490  		if m.doc.Life != Alive {
  1491  			return nil, errNotAlive
  1492  		}
  1493  		if _, err := m.InstanceId(); err == nil {
  1494  			return nil, fmt.Errorf("machine is already provisioned")
  1495  		} else if !errors.IsNotProvisioned(err) {
  1496  			return nil, err
  1497  		}
  1498  		return ops, nil
  1499  	}
  1500  	return m.st.run(buildTxn)
  1501  }
  1502  
  1503  // Status returns the status of the machine.
  1504  func (m *Machine) Status() (status.StatusInfo, error) {
  1505  	mStatus, err := getStatus(m.st, m.globalKey(), "machine")
  1506  	if err != nil {
  1507  		return mStatus, err
  1508  	}
  1509  	return mStatus, nil
  1510  }
  1511  
  1512  // SetStatus sets the status of the machine.
  1513  func (m *Machine) SetStatus(machineStatus status.Status, info string, data map[string]interface{}) error {
  1514  	switch machineStatus {
  1515  	case status.StatusStarted, status.StatusStopped:
  1516  	case status.StatusError:
  1517  		if info == "" {
  1518  			return errors.Errorf("cannot set status %q without info", machineStatus)
  1519  		}
  1520  	case status.StatusPending:
  1521  		// If a machine is not yet provisioned, we allow its status
  1522  		// to be set back to pending (when a retry is to occur).
  1523  		_, err := m.InstanceId()
  1524  		allowPending := errors.IsNotProvisioned(err)
  1525  		if allowPending {
  1526  			break
  1527  		}
  1528  		fallthrough
  1529  	case status.StatusDown:
  1530  		return errors.Errorf("cannot set status %q", machineStatus)
  1531  	default:
  1532  		return errors.Errorf("cannot set invalid status %q", machineStatus)
  1533  	}
  1534  	return setStatus(m.st, setStatusParams{
  1535  		badge:     "machine",
  1536  		globalKey: m.globalKey(),
  1537  		status:    machineStatus,
  1538  		message:   info,
  1539  		rawData:   data,
  1540  	})
  1541  }
  1542  
  1543  // StatusHistory returns a slice of at most <size> StatusInfo items
  1544  // representing past statuses for this machine.
  1545  func (m *Machine) StatusHistory(size int) ([]status.StatusInfo, error) {
  1546  	return statusHistory(m.st, m.globalKey(), size)
  1547  }
  1548  
  1549  // Clean returns true if the machine does not have any deployed units or containers.
  1550  func (m *Machine) Clean() bool {
  1551  	return m.doc.Clean
  1552  }
  1553  
  1554  // SupportedContainers returns any containers this machine is capable of hosting, and a bool
  1555  // indicating if the supported containers have been determined or not.
  1556  func (m *Machine) SupportedContainers() ([]instance.ContainerType, bool) {
  1557  	return m.doc.SupportedContainers, m.doc.SupportedContainersKnown
  1558  }
  1559  
  1560  // SupportsNoContainers records the fact that this machine doesn't support any containers.
  1561  func (m *Machine) SupportsNoContainers() (err error) {
  1562  	if err = m.updateSupportedContainers([]instance.ContainerType{}); err != nil {
  1563  		return err
  1564  	}
  1565  	return m.markInvalidContainers()
  1566  }
  1567  
  1568  // SetSupportedContainers sets the list of containers supported by this machine.
  1569  func (m *Machine) SetSupportedContainers(containers []instance.ContainerType) (err error) {
  1570  	if len(containers) == 0 {
  1571  		return fmt.Errorf("at least one valid container type is required")
  1572  	}
  1573  	for _, container := range containers {
  1574  		if container == instance.NONE {
  1575  			return fmt.Errorf("%q is not a valid container type", container)
  1576  		}
  1577  	}
  1578  	if err = m.updateSupportedContainers(containers); err != nil {
  1579  		return err
  1580  	}
  1581  	return m.markInvalidContainers()
  1582  }
  1583  
  1584  func isSupportedContainer(container instance.ContainerType, supportedContainers []instance.ContainerType) bool {
  1585  	for _, supportedContainer := range supportedContainers {
  1586  		if supportedContainer == container {
  1587  			return true
  1588  		}
  1589  	}
  1590  	return false
  1591  }
  1592  
  1593  // updateSupportedContainers sets the supported containers on this host machine.
  1594  func (m *Machine) updateSupportedContainers(supportedContainers []instance.ContainerType) (err error) {
  1595  	ops := []txn.Op{
  1596  		{
  1597  			C:      machinesC,
  1598  			Id:     m.doc.DocID,
  1599  			Assert: notDeadDoc,
  1600  			Update: bson.D{
  1601  				{"$set", bson.D{
  1602  					{"supportedcontainers", supportedContainers},
  1603  					{"supportedcontainersknown", true},
  1604  				}}},
  1605  		},
  1606  	}
  1607  	if err = m.st.runTransaction(ops); err != nil {
  1608  		err = onAbort(err, ErrDead)
  1609  		logger.Errorf("cannot update supported containers of machine %v: %v", m, err)
  1610  		return err
  1611  	}
  1612  	m.doc.SupportedContainers = supportedContainers
  1613  	m.doc.SupportedContainersKnown = true
  1614  	return nil
  1615  }
  1616  
  1617  // markInvalidContainers sets the status of any container belonging to this machine
  1618  // as being in error if the container type is not supported.
  1619  func (m *Machine) markInvalidContainers() error {
  1620  	currentContainers, err := m.Containers()
  1621  	if err != nil {
  1622  		return err
  1623  	}
  1624  	for _, containerId := range currentContainers {
  1625  		if !isSupportedContainer(ContainerTypeFromId(containerId), m.doc.SupportedContainers) {
  1626  			container, err := m.st.Machine(containerId)
  1627  			if err != nil {
  1628  				logger.Errorf("loading container %v to mark as invalid: %v", containerId, err)
  1629  				continue
  1630  			}
  1631  			// There should never be a circumstance where an unsupported container is started.
  1632  			// Nonetheless, we check and log an error if such a situation arises.
  1633  			statusInfo, err := container.Status()
  1634  			if err != nil {
  1635  				logger.Errorf("finding status of container %v to mark as invalid: %v", containerId, err)
  1636  				continue
  1637  			}
  1638  			if statusInfo.Status == status.StatusPending {
  1639  				containerType := ContainerTypeFromId(containerId)
  1640  				container.SetStatus(
  1641  					status.StatusError, "unsupported container", map[string]interface{}{"type": containerType})
  1642  			} else {
  1643  				logger.Errorf("unsupported container %v has unexpected status %v", containerId, statusInfo.Status)
  1644  			}
  1645  		}
  1646  	}
  1647  	return nil
  1648  }
  1649  
  1650  // SetMachineBlockDevices sets the block devices visible on the machine.
  1651  func (m *Machine) SetMachineBlockDevices(info ...BlockDeviceInfo) error {
  1652  	return setMachineBlockDevices(m.st, m.Id(), info)
  1653  }
  1654  
  1655  // VolumeAttachments returns the machine's volume attachments.
  1656  func (m *Machine) VolumeAttachments() ([]VolumeAttachment, error) {
  1657  	return m.st.MachineVolumeAttachments(m.MachineTag())
  1658  }
  1659  
  1660  // AddAction is part of the ActionReceiver interface.
  1661  func (m *Machine) AddAction(name string, payload map[string]interface{}) (Action, error) {
  1662  	spec, ok := actions.PredefinedActionsSpec[name]
  1663  	if !ok {
  1664  		return nil, errors.Errorf("cannot add action %q to a machine; only predefined actions allowed", name)
  1665  	}
  1666  
  1667  	// Reject bad payloads before attempting to insert defaults.
  1668  	err := spec.ValidateParams(payload)
  1669  	if err != nil {
  1670  		return nil, err
  1671  	}
  1672  	payloadWithDefaults, err := spec.InsertDefaults(payload)
  1673  	if err != nil {
  1674  		return nil, err
  1675  	}
  1676  	return m.st.EnqueueAction(m.Tag(), name, payloadWithDefaults)
  1677  }
  1678  
  1679  // CancelAction is part of the ActionReceiver interface.
  1680  func (m *Machine) CancelAction(action Action) (Action, error) {
  1681  	return action.Finish(ActionResults{Status: ActionCancelled})
  1682  }
  1683  
  1684  // WatchActionNotifications is part of the ActionReceiver interface.
  1685  func (m *Machine) WatchActionNotifications() StringsWatcher {
  1686  	return m.st.watchEnqueuedActionsFilteredBy(m)
  1687  }
  1688  
  1689  // Actions is part of the ActionReceiver interface.
  1690  func (m *Machine) Actions() ([]Action, error) {
  1691  	return m.st.matchingActions(m)
  1692  }
  1693  
  1694  // CompletedActions is part of the ActionReceiver interface.
  1695  func (m *Machine) CompletedActions() ([]Action, error) {
  1696  	return m.st.matchingActionsCompleted(m)
  1697  }
  1698  
  1699  // PendingActions is part of the ActionReceiver interface.
  1700  func (m *Machine) PendingActions() ([]Action, error) {
  1701  	return m.st.matchingActionsPending(m)
  1702  }
  1703  
  1704  // RunningActions is part of the ActionReceiver interface.
  1705  func (m *Machine) RunningActions() ([]Action, error) {
  1706  	return m.st.matchingActionsRunning(m)
  1707  }