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