github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/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  	"sort"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/juju/charm/v12"
    13  	"github.com/juju/collections/set"
    14  	"github.com/juju/errors"
    15  	"github.com/juju/mgo/v3"
    16  	"github.com/juju/mgo/v3/bson"
    17  	"github.com/juju/mgo/v3/txn"
    18  	"github.com/juju/names/v5"
    19  	jujutxn "github.com/juju/txn/v3"
    20  	"github.com/juju/utils/v3"
    21  	"github.com/juju/version/v2"
    22  	"github.com/kr/pretty"
    23  
    24  	"github.com/juju/juju/api"
    25  	"github.com/juju/juju/core/actions"
    26  	"github.com/juju/juju/core/constraints"
    27  	corecontainer "github.com/juju/juju/core/container"
    28  	"github.com/juju/juju/core/instance"
    29  	"github.com/juju/juju/core/model"
    30  	"github.com/juju/juju/core/network"
    31  	"github.com/juju/juju/core/status"
    32  	"github.com/juju/juju/environs/bootstrap"
    33  	"github.com/juju/juju/mongo"
    34  	stateerrors "github.com/juju/juju/state/errors"
    35  	"github.com/juju/juju/tools"
    36  )
    37  
    38  // Machine represents the state of a machine.
    39  type Machine struct {
    40  	st  *State
    41  	doc machineDoc
    42  }
    43  
    44  // MachineJob values define responsibilities that machines may be
    45  // expected to fulfil.
    46  type MachineJob int
    47  
    48  const (
    49  	_ MachineJob = iota
    50  	JobHostUnits
    51  	JobManageModel
    52  )
    53  
    54  var (
    55  	jobNames = map[MachineJob]model.MachineJob{
    56  		JobHostUnits:   model.JobHostUnits,
    57  		JobManageModel: model.JobManageModel,
    58  	}
    59  	jobMigrationValue = map[MachineJob]string{
    60  		JobHostUnits:   "host-units",
    61  		JobManageModel: "api-server",
    62  	}
    63  )
    64  
    65  // ToParams returns the job as model.MachineJob.
    66  func (job MachineJob) ToParams() model.MachineJob {
    67  	if jujuJob, ok := jobNames[job]; ok {
    68  		return jujuJob
    69  	}
    70  	return model.MachineJob(fmt.Sprintf("<unknown job %d>", int(job)))
    71  }
    72  
    73  // paramsJobsFromJobs converts state jobs to juju jobs.
    74  func paramsJobsFromJobs(jobs []MachineJob) []model.MachineJob {
    75  	jujuJobs := make([]model.MachineJob, len(jobs))
    76  	for i, machineJob := range jobs {
    77  		jujuJobs[i] = machineJob.ToParams()
    78  	}
    79  	return jujuJobs
    80  }
    81  
    82  // MigrationValue converts the state job into a useful human readable
    83  // string for model migration.
    84  func (job MachineJob) MigrationValue() string {
    85  	if value, ok := jobMigrationValue[job]; ok {
    86  		return value
    87  	}
    88  	return "unknown"
    89  }
    90  
    91  func (job MachineJob) String() string {
    92  	return string(job.ToParams())
    93  }
    94  
    95  // manualMachinePrefix signals as prefix of Nonce that a machine is
    96  // manually provisioned.
    97  const manualMachinePrefix = "manual:"
    98  
    99  // machineDoc represents the internal state of a machine in MongoDB.
   100  // Note the correspondence with MachineInfo in apiserver/juju.
   101  type machineDoc struct {
   102  	DocID          string `bson:"_id"`
   103  	Id             string `bson:"machineid"`
   104  	ModelUUID      string `bson:"model-uuid"`
   105  	Base           Base   `bson:"base"`
   106  	Nonce          string
   107  	ContainerType  string
   108  	Principals     []string
   109  	Life           Life
   110  	Tools          *tools.Tools `bson:",omitempty"`
   111  	Jobs           []MachineJob
   112  	PasswordHash   string
   113  	Clean          bool
   114  	ForceDestroyed bool `bson:"force-destroyed"`
   115  
   116  	// Volumes contains the names of volumes attached to the machine.
   117  	Volumes []string `bson:"volumes,omitempty"`
   118  	// Filesystems contains the names of filesystems attached to the machine.
   119  	Filesystems []string `bson:"filesystems,omitempty"`
   120  
   121  	// We store 2 different sets of addresses for the machine, obtained
   122  	// from different sources.
   123  	// Addresses is the set of addresses obtained by asking the provider.
   124  	Addresses []address
   125  
   126  	// MachineAddresses is the set of addresses obtained from the machine itself.
   127  	MachineAddresses []address
   128  
   129  	// PreferredPublicAddress is the preferred address to be used for
   130  	// the machine when a public address is requested.
   131  	PreferredPublicAddress address `bson:",omitempty"`
   132  
   133  	// PreferredPrivateAddress is the preferred address to be used for
   134  	// the machine when a private address is requested.
   135  	PreferredPrivateAddress address `bson:",omitempty"`
   136  
   137  	// The SupportedContainers attributes are used to advertise what containers this
   138  	// machine is capable of hosting.
   139  	SupportedContainersKnown bool
   140  	SupportedContainers      []instance.ContainerType `bson:",omitempty"`
   141  	// Placement is the placement directive that should be used when provisioning
   142  	// an instance for the machine.
   143  	Placement string `bson:",omitempty"`
   144  
   145  	// AgentStartedAt records the time when the machine agent started.
   146  	AgentStartedAt time.Time `bson:"agent-started-at,omitempty"`
   147  
   148  	// Hostname records the machine's hostname as reported by the machine agent.
   149  	Hostname string `bson:"hostname,omitempty"`
   150  }
   151  
   152  func newMachine(st *State, doc *machineDoc) *Machine {
   153  	machine := &Machine{
   154  		st:  st,
   155  		doc: *doc,
   156  	}
   157  	return machine
   158  }
   159  
   160  // Id returns the machine id.
   161  func (m *Machine) Id() string {
   162  	return m.doc.Id
   163  }
   164  
   165  // Principals returns the principals for the machine.
   166  func (m *Machine) Principals() []string {
   167  	return m.doc.Principals
   168  }
   169  
   170  // Base returns the os base running on the machine.
   171  func (m *Machine) Base() Base {
   172  	return m.doc.Base
   173  }
   174  
   175  // ContainerType returns the type of container hosting this machine.
   176  func (m *Machine) ContainerType() instance.ContainerType {
   177  	return instance.ContainerType(m.doc.ContainerType)
   178  }
   179  
   180  // ModelUUID returns the unique identifier
   181  // for the model that this machine is in.
   182  func (m *Machine) ModelUUID() string {
   183  	return m.doc.ModelUUID
   184  }
   185  
   186  // ForceDestroyed returns whether the destruction of a dying/dead
   187  // machine was forced. It's always false for a machine that's alive.
   188  func (m *Machine) ForceDestroyed() bool {
   189  	return m.doc.ForceDestroyed
   190  }
   191  
   192  func (m *Machine) forceDestroyedOps() []txn.Op {
   193  	return []txn.Op{{
   194  		C:      machinesC,
   195  		Id:     m.doc.DocID,
   196  		Assert: txn.DocExists,
   197  		Update: bson.D{{"$set", bson.D{{"force-destroyed", true}}}},
   198  	}}
   199  }
   200  
   201  // machineGlobalKey returns the global database key for the identified machine.
   202  func machineGlobalKey(id string) string {
   203  	return "m#" + id
   204  }
   205  
   206  // machineGlobalInstanceKey returns the global database key for the identified
   207  // machine's instance.
   208  func machineGlobalInstanceKey(id string) string {
   209  	return machineGlobalKey(id) + "#instance"
   210  }
   211  
   212  // globalInstanceKey returns the global database key for the machine's instance.
   213  func (m *Machine) globalInstanceKey() string {
   214  	return machineGlobalInstanceKey(m.doc.Id)
   215  }
   216  
   217  // machineGlobalModificationKey returns the global database key for the
   218  // identified machine's modification changes.
   219  func machineGlobalModificationKey(id string) string {
   220  	return machineGlobalKey(id) + "#modification"
   221  }
   222  
   223  // globalModificationKey returns the global database key for the machine's
   224  // modification changes.
   225  func (m *Machine) globalModificationKey() string {
   226  	return machineGlobalModificationKey(m.doc.Id)
   227  }
   228  
   229  // globalKey returns the global database key for the machine.
   230  func (m *Machine) globalKey() string {
   231  	return machineGlobalKey(m.doc.Id)
   232  }
   233  
   234  // instanceData holds attributes relevant to a provisioned machine.
   235  type instanceData struct {
   236  	DocID          string      `bson:"_id"`
   237  	MachineId      string      `bson:"machineid"`
   238  	InstanceId     instance.Id `bson:"instanceid"`
   239  	DisplayName    string      `bson:"display-name"`
   240  	ModelUUID      string      `bson:"model-uuid"`
   241  	Arch           *string     `bson:"arch,omitempty"`
   242  	Mem            *uint64     `bson:"mem,omitempty"`
   243  	RootDisk       *uint64     `bson:"rootdisk,omitempty"`
   244  	RootDiskSource *string     `bson:"rootdisksource,omitempty"`
   245  	CpuCores       *uint64     `bson:"cpucores,omitempty"`
   246  	CpuPower       *uint64     `bson:"cpupower,omitempty"`
   247  	Tags           *[]string   `bson:"tags,omitempty"`
   248  	AvailZone      *string     `bson:"availzone,omitempty"`
   249  	VirtType       *string     `bson:"virt-type,omitempty"`
   250  
   251  	// KeepInstance is set to true if, on machine removal from Juju,
   252  	// the cloud instance should be retained.
   253  	KeepInstance bool `bson:"keep-instance,omitempty"`
   254  
   255  	// CharmProfiles contains the names of LXD profiles used by this machine.
   256  	// Profiles would have been defined in the charm deployed to this machine.
   257  	CharmProfiles []string `bson:"charm-profiles,omitempty"`
   258  }
   259  
   260  func hardwareCharacteristics(instData instanceData) *instance.HardwareCharacteristics {
   261  	return &instance.HardwareCharacteristics{
   262  		Arch:             instData.Arch,
   263  		Mem:              instData.Mem,
   264  		RootDisk:         instData.RootDisk,
   265  		RootDiskSource:   instData.RootDiskSource,
   266  		CpuCores:         instData.CpuCores,
   267  		CpuPower:         instData.CpuPower,
   268  		Tags:             instData.Tags,
   269  		AvailabilityZone: instData.AvailZone,
   270  		VirtType:         instData.VirtType,
   271  	}
   272  }
   273  
   274  // TODO(wallyworld): move this method to a service.
   275  func (m *Machine) HardwareCharacteristics() (*instance.HardwareCharacteristics, error) {
   276  	instData, err := getInstanceData(m.st, m.Id())
   277  	if err != nil {
   278  		return nil, err
   279  	}
   280  	return hardwareCharacteristics(instData), nil
   281  }
   282  
   283  func getInstanceData(st *State, id string) (instanceData, error) {
   284  	instanceDataCollection, closer := st.db().GetCollection(instanceDataC)
   285  	defer closer()
   286  
   287  	var instData instanceData
   288  	err := instanceDataCollection.FindId(id).One(&instData)
   289  	if err == mgo.ErrNotFound {
   290  		return instanceData{}, errors.NotFoundf("instance data for machine %v", id)
   291  	}
   292  	if err != nil {
   293  		return instanceData{}, fmt.Errorf("cannot get instance data for machine %v: %v", id, err)
   294  	}
   295  	return instData, nil
   296  }
   297  
   298  // removeInstanceDataOp returns the operation needed to remove the
   299  // instance data document associated with the given globalKey.
   300  func removeInstanceDataOp(globalKey string) txn.Op {
   301  	return txn.Op{
   302  		C:      instanceDataC,
   303  		Id:     globalKey,
   304  		Remove: true,
   305  	}
   306  }
   307  
   308  // AllInstanceData retrieves all instance data in the model
   309  // and provides a way to query hardware characteristics and
   310  // charm profiles by machine.
   311  func (m *Model) AllInstanceData() (*ModelInstanceData, error) {
   312  	coll, closer := m.st.db().GetCollection(instanceDataC)
   313  	defer closer()
   314  
   315  	var docs []instanceData
   316  	err := coll.Find(nil).All(&docs)
   317  	if err != nil {
   318  		return nil, errors.Annotate(err, "cannot get all instance data for model")
   319  	}
   320  	all := &ModelInstanceData{
   321  		data: make(map[string]instanceData),
   322  	}
   323  	for _, doc := range docs {
   324  		all.data[doc.MachineId] = doc
   325  	}
   326  	return all, nil
   327  }
   328  
   329  // ModelInstanceData represents all the instance data for a model
   330  // keyed on machine ID.
   331  type ModelInstanceData struct {
   332  	data map[string]instanceData
   333  }
   334  
   335  // HardwareCharacteristics returns the hardware characteristics of the
   336  // machine. If it isn't found in the map, a nil is returned.
   337  func (d *ModelInstanceData) HardwareCharacteristics(machineID string) *instance.HardwareCharacteristics {
   338  	instData, found := d.data[machineID]
   339  	if !found {
   340  		return nil
   341  	}
   342  	return hardwareCharacteristics(instData)
   343  }
   344  
   345  // CharmProfiles returns the names of the profiles that are defined for
   346  // the machine. If the machine isn't found in the map, a nil is returned.
   347  func (d *ModelInstanceData) CharmProfiles(machineID string) []string {
   348  	instData, found := d.data[machineID]
   349  	if !found {
   350  		return nil
   351  	}
   352  	return instData.CharmProfiles
   353  }
   354  
   355  // InstanceNames returns both the provider instance id and the user
   356  // friendly name. If the machine isn't found, empty strings are returned.
   357  func (d *ModelInstanceData) InstanceNames(machineID string) (instance.Id, string) {
   358  	instData, found := d.data[machineID]
   359  	if !found {
   360  		return "", ""
   361  	}
   362  	return instData.InstanceId, instData.DisplayName
   363  }
   364  
   365  // Tag returns a tag identifying the machine. The String method provides a
   366  // string representation that is safe to use as a file name. The returned name
   367  // will be different from other Tag values returned by any other entities
   368  // from the same state.
   369  func (m *Machine) Tag() names.Tag {
   370  	return m.MachineTag()
   371  }
   372  
   373  // MachineTag returns the more specific MachineTag type as opposed
   374  // to the more generic Tag type.
   375  func (m *Machine) MachineTag() names.MachineTag {
   376  	return names.NewMachineTag(m.Id())
   377  }
   378  
   379  // Life returns whether the machine is Alive, Dying or Dead.
   380  func (m *Machine) Life() Life {
   381  	return m.doc.Life
   382  }
   383  
   384  // Jobs returns the responsibilities that must be fulfilled by m's agent.
   385  func (m *Machine) Jobs() []MachineJob {
   386  	return m.doc.Jobs
   387  }
   388  
   389  // SetKeepInstance sets whether the cloud machine instance
   390  // will be retained when the machine is removed from Juju.
   391  // This is only relevant if an instance exists.
   392  func (m *Machine) SetKeepInstance(keepInstance bool) error {
   393  	ops := []txn.Op{{
   394  		C:      instanceDataC,
   395  		Id:     m.doc.DocID,
   396  		Assert: txn.DocExists,
   397  		Update: bson.D{{"$set", bson.D{{"keep-instance", keepInstance}}}},
   398  	}}
   399  	if err := m.st.db().RunTransaction(ops); err != nil {
   400  		// If instance doc doesn't exist, that's ok; there's nothing to keep,
   401  		// but that's not an error we care about.
   402  		return errors.Annotatef(onAbort(err, nil), "cannot set KeepInstance on machine %v", m)
   403  	}
   404  	return nil
   405  }
   406  
   407  // KeepInstance reports whether a machine, when removed from
   408  // Juju, will cause the corresponding cloud instance to be stopped.
   409  func (m *Machine) KeepInstance() (bool, error) {
   410  	instData, err := getInstanceData(m.st, m.Id())
   411  	if err != nil {
   412  		return false, err
   413  	}
   414  	return instData.KeepInstance, nil
   415  }
   416  
   417  // CharmProfiles returns the names of any LXD profiles used by the machine,
   418  // which were defined in the charm deployed to that machine.
   419  func (m *Machine) CharmProfiles() ([]string, error) {
   420  	instData, err := getInstanceData(m.st, m.Id())
   421  	if errors.IsNotFound(err) {
   422  		err = errors.NotProvisionedf("machine %v", m.Id())
   423  	}
   424  	if err != nil {
   425  		return nil, err
   426  	}
   427  	return instData.CharmProfiles, nil
   428  }
   429  
   430  // SetCharmProfiles sets the names of the charm profiles used on a machine
   431  // in its instanceData.
   432  func (m *Machine) SetCharmProfiles(profiles []string) error {
   433  	if len(profiles) == 0 {
   434  		return nil
   435  	}
   436  	buildTxn := func(attempt int) ([]txn.Op, error) {
   437  		if attempt > 0 {
   438  			if err := m.Refresh(); err != nil {
   439  				return nil, errors.Trace(err)
   440  			}
   441  		}
   442  		// Exit early if the Machine profiles doesn't need to change.
   443  		mProfiles, err := m.CharmProfiles()
   444  		if err != nil {
   445  			return nil, errors.Trace(err)
   446  		}
   447  		mProfilesSet := set.NewStrings(mProfiles...)
   448  		if mProfilesSet.Union(set.NewStrings(profiles...)).Size() == mProfilesSet.Size() {
   449  			return nil, jujutxn.ErrNoOperations
   450  		}
   451  
   452  		ops := []txn.Op{{
   453  			C:      instanceDataC,
   454  			Id:     m.doc.DocID,
   455  			Assert: txn.DocExists,
   456  			Update: bson.D{{"$set", bson.D{{"charm-profiles", profiles}}}},
   457  		}}
   458  
   459  		return ops, nil
   460  	}
   461  	err := m.st.db().Run(buildTxn)
   462  	return errors.Annotatef(err, "cannot update profiles for %q to %s", m, strings.Join(profiles, ", "))
   463  }
   464  
   465  // IsManager returns true if the machine has JobManageModel.
   466  func (m *Machine) IsManager() bool {
   467  	return isController(&m.doc)
   468  }
   469  
   470  // IsManual returns true if the machine was manually provisioned.
   471  func (m *Machine) IsManual() (bool, error) {
   472  	// To avoid unnecessary db lookups, a little of the
   473  	// logic from isManualMachine() below is duplicated here
   474  	// so we can exit early if possible.
   475  	if strings.HasPrefix(m.doc.Nonce, manualMachinePrefix) {
   476  		return true, nil
   477  	}
   478  	if m.doc.Id != "0" {
   479  		return false, nil
   480  	}
   481  	modelSettings, err := readSettings(m.st.db(), settingsC, modelGlobalKey)
   482  	if err != nil {
   483  		return false, errors.Trace(err)
   484  	}
   485  	providerRaw, _ := modelSettings.Get("type")
   486  	providerType, _ := providerRaw.(string)
   487  	return isManualMachine(m.doc.Id, m.doc.Nonce, providerType), nil
   488  }
   489  
   490  func isManualMachine(id, nonce, providerType string) bool {
   491  	// Apart from the bootstrap machine, manually provisioned
   492  	// machines have a nonce prefixed with "manual:". This is
   493  	// unique to manual provisioning.
   494  	if strings.HasPrefix(nonce, manualMachinePrefix) {
   495  		return true
   496  	}
   497  	// The bootstrap machine uses BootstrapNonce, so in that
   498  	// case we need to check if its provider type is "manual".
   499  	// We also check for "null", which is an alias for manual.
   500  	return id == "0" && (providerType == "null" || providerType == "manual")
   501  }
   502  
   503  // AgentTools returns the tools that the agent is currently running.
   504  // It returns an error that satisfies errors.IsNotFound if the tools
   505  // have not yet been set.
   506  func (m *Machine) AgentTools() (*tools.Tools, error) {
   507  	if m.doc.Tools == nil {
   508  		return nil, errors.NotFoundf("agent binaries for machine %v", m)
   509  	}
   510  	tools := *m.doc.Tools
   511  	return &tools, nil
   512  }
   513  
   514  // checkVersionValidity checks whether the given version is suitable
   515  // for passing to SetAgentVersion.
   516  func checkVersionValidity(v version.Binary) error {
   517  	if v.Release == "" || v.Arch == "" {
   518  		return fmt.Errorf("empty series or arch")
   519  	}
   520  	return nil
   521  }
   522  
   523  // SetAgentVersion sets the version of juju that the agent is
   524  // currently running.
   525  func (m *Machine) SetAgentVersion(v version.Binary) (err error) {
   526  	defer errors.DeferredAnnotatef(&err, "cannot set agent version for machine %v", m)
   527  	ops, tools, err := m.setAgentVersionOps(v)
   528  	if err != nil {
   529  		return errors.Trace(err)
   530  	}
   531  	// A "raw" transaction is needed here because this function gets
   532  	// called before database migrations have run so we don't
   533  	// necessarily want the model UUID added to the id.
   534  	if err := m.st.runRawTransaction(ops); err != nil {
   535  		return onAbort(err, stateerrors.ErrDead)
   536  	}
   537  	m.doc.Tools = tools
   538  	return nil
   539  }
   540  
   541  func (m *Machine) setAgentVersionOps(v version.Binary) ([]txn.Op, *tools.Tools, error) {
   542  	if err := checkVersionValidity(v); err != nil {
   543  		return nil, nil, err
   544  	}
   545  	tools := &tools.Tools{Version: v}
   546  	ops := []txn.Op{{
   547  		C:      machinesC,
   548  		Id:     m.doc.DocID,
   549  		Assert: notDeadDoc,
   550  		Update: bson.D{{"$set", bson.D{{"tools", tools}}}},
   551  	}}
   552  	return ops, tools, nil
   553  }
   554  
   555  // SetMongoPassword sets the password the agent responsible for the machine
   556  // should use to communicate with the controllers.  Previous passwords
   557  // are invalidated.
   558  func (m *Machine) SetMongoPassword(password string) error {
   559  	if !m.IsManager() {
   560  		return errors.NotSupportedf("setting mongo password for non-controller machine %v", m)
   561  	}
   562  	return mongo.SetAdminMongoPassword(m.st.session, m.Tag().String(), password)
   563  }
   564  
   565  // SetPassword sets the password for the machine's agent.
   566  func (m *Machine) SetPassword(password string) error {
   567  	if len(password) < utils.MinAgentPasswordLength {
   568  		return errors.Errorf("password is only %d bytes long, and is not a valid Agent password", len(password))
   569  	}
   570  	passwordHash := utils.AgentPasswordHash(password)
   571  	op := m.UpdateOperation()
   572  	op.PasswordHash = &passwordHash
   573  	if err := m.st.ApplyOperation(op); err != nil {
   574  		return errors.Trace(err)
   575  	}
   576  	m.doc.PasswordHash = passwordHash
   577  	return nil
   578  }
   579  
   580  func (m *Machine) setPasswordHashOps(passwordHash string) ([]txn.Op, error) {
   581  	if m.doc.Life == Dead {
   582  		return nil, stateerrors.ErrDead
   583  	}
   584  	ops := []txn.Op{{
   585  		C:      machinesC,
   586  		Id:     m.doc.DocID,
   587  		Assert: notDeadDoc,
   588  		Update: bson.D{{"$set", bson.D{{"passwordhash", passwordHash}}}},
   589  	}}
   590  	return ops, nil
   591  }
   592  
   593  // PasswordValid returns whether the given password is valid
   594  // for the given machine.
   595  func (m *Machine) PasswordValid(password string) bool {
   596  	agentHash := utils.AgentPasswordHash(password)
   597  	return agentHash == m.doc.PasswordHash
   598  }
   599  
   600  // Destroy sets the machine lifecycle to Dying if it is Alive. It does
   601  // nothing otherwise. Destroy will fail if the machine has principal
   602  // units assigned, or if the machine has JobManageModel.
   603  // If the machine has assigned units, Destroy will return
   604  // a HasAssignedUnitsError.  If the machine has containers, Destroy
   605  // will return HasContainersError.
   606  func (m *Machine) Destroy() error {
   607  	if m.IsManager() && len(m.doc.Principals) > 0 {
   608  		return errors.Trace(m.destroyControllerWithPrincipals())
   609  	}
   610  	return errors.Trace(m.advanceLifecycle(Dying, false, false, 0))
   611  }
   612  
   613  // destroyControllerWithPrincipals is called if the controller has
   614  // principal units and they are juju- system charms, then gracefully
   615  // remove them before destroying the machine.
   616  func (m *Machine) destroyControllerWithPrincipals() error {
   617  	units, err := m.Units()
   618  	if err != nil {
   619  		return errors.Trace(err)
   620  	}
   621  	unitsMap := make(map[string]*Unit)
   622  	for _, unit := range units {
   623  		unitsMap[unit.String()] = unit
   624  	}
   625  	var evacuablePrincipals []string
   626  	for _, principalUnit := range m.doc.Principals {
   627  		unit, ok := unitsMap[principalUnit]
   628  		if !ok {
   629  			continue
   630  		}
   631  		curlStr := unit.CharmURL()
   632  		if curlStr == nil {
   633  			continue
   634  		}
   635  		curl, err := charm.ParseURL(*curlStr)
   636  		if err != nil {
   637  			return errors.Trace(err)
   638  		}
   639  		if curl != nil && strings.HasPrefix(curl.Name, "juju-") {
   640  			evacuablePrincipals = append(evacuablePrincipals, principalUnit)
   641  		}
   642  	}
   643  	if len(m.doc.Principals) != len(evacuablePrincipals) {
   644  		return stateerrors.NewHasAssignedUnitsError(m.doc.Id, m.doc.Principals)
   645  	}
   646  	ops := []txn.Op{
   647  		{
   648  			C:  machinesC,
   649  			Id: m.doc.DocID,
   650  			Assert: bson.D{
   651  				{"life", Alive},
   652  				advanceLifecycleUnitAsserts(evacuablePrincipals),
   653  			},
   654  			// To prevent race conditions, we remove the ability for new
   655  			// units to be deployed to the machine.
   656  			Update: bson.D{{"$pull", bson.D{{"jobs", JobHostUnits}}}},
   657  		},
   658  		newCleanupOp(cleanupEvacuateMachine, m.doc.Id),
   659  	}
   660  	if err := m.st.db().RunTransaction(ops); err != nil {
   661  		return errors.Annotatef(err, "failed to run transaction: %s", pretty.Sprint(ops))
   662  	}
   663  	for i, v := range m.doc.Jobs {
   664  		if v == JobHostUnits {
   665  			m.doc.Jobs = append(m.doc.Jobs[:i], m.doc.Jobs[i+1:]...)
   666  			break
   667  		}
   668  	}
   669  	err = m.SetStatus(status.StatusInfo{
   670  		Status:  status.Stopped,
   671  		Message: fmt.Sprintf("waiting on dying units %s", strings.Join(evacuablePrincipals, ", ")),
   672  	})
   673  	if err != nil {
   674  		return errors.Trace(err)
   675  	}
   676  	return nil
   677  }
   678  
   679  // DestroyWithContainers sets the machine lifecycle to Dying if it is Alive.
   680  // It does nothing otherwise. DestroyWithContainers will fail if the machine
   681  // has principal units assigned, or if the machine has JobManageModel. If the
   682  // machine has assigned units, DestroyWithContainers will return a
   683  // HasAssignedUnitsError.  The machine is allowed to have containers.  Use with
   684  // caution.  Intended for model tear down.
   685  func (m *Machine) DestroyWithContainers() error {
   686  	return m.advanceLifecycle(Dying, false, true, 0)
   687  }
   688  
   689  // ForceDestroy queues the machine for complete removal, including the
   690  // destruction of all units and containers on the machine.
   691  func (m *Machine) ForceDestroy(maxWait time.Duration) error {
   692  	ops, err := m.forceDestroyOps(maxWait)
   693  	if err != nil {
   694  		return errors.Trace(err)
   695  	}
   696  	if err := m.st.db().RunTransaction(ops); err != txn.ErrAborted {
   697  		return errors.Annotatef(err, "failed to run transaction: %s", pretty.Sprint(ops))
   698  	}
   699  	return nil
   700  }
   701  
   702  func (m *Machine) forceDestroyOps(maxWait time.Duration) ([]txn.Op, error) {
   703  	if m.IsManager() {
   704  		controllerIds, err := m.st.ControllerIds()
   705  		if err != nil {
   706  			return nil, errors.Annotatef(err, "reading controller info")
   707  		}
   708  		if len(controllerIds) <= 1 {
   709  			return nil, errors.Errorf("controller %s is the only controller", m.Id())
   710  		}
   711  		// We set the machine to Dying if it isn't already dead.
   712  		var machineOp txn.Op
   713  		if m.Life() < Dead {
   714  			// Make sure we don't want the vote, and we are queued to be Dying.
   715  			// Since we are force deleting, life assert should be current machine's life.
   716  			machineOp = txn.Op{
   717  				C:      machinesC,
   718  				Id:     m.doc.DocID,
   719  				Assert: bson.D{{"life", bson.D{{"$in", []Life{Alive, Dying}}}}},
   720  				Update: bson.D{{"$set", bson.D{{"life", Dying}}}},
   721  			}
   722  		}
   723  		controllerOp := txn.Op{
   724  			C:      controllersC,
   725  			Id:     modelGlobalKey,
   726  			Assert: bson.D{{"controller-ids", controllerIds}},
   727  		}
   728  		// Note that ForceDestroy does *not* cleanup the replicaset, so it might cause problems.
   729  		// However, we're letting the user handle times when the machine agent isn't running, etc.
   730  		// We may need to update the peergrouper for this.
   731  		return []txn.Op{
   732  			machineOp,
   733  			controllerOp,
   734  			setControllerWantsVoteOp(m.st, m.Id(), false),
   735  			newCleanupOp(cleanupForceDestroyedMachine, m.doc.Id, maxWait),
   736  		}, nil
   737  	} else {
   738  		// Make sure the machine doesn't become a manager while we're destroying it
   739  		return []txn.Op{{
   740  			C:      machinesC,
   741  			Id:     m.doc.DocID,
   742  			Assert: bson.D{{"jobs", bson.D{{"$nin", []MachineJob{JobManageModel}}}}},
   743  		}, newCleanupOp(cleanupForceDestroyedMachine, m.doc.Id, maxWait),
   744  		}, nil
   745  	}
   746  }
   747  
   748  // EnsureDead sets the machine lifecycle to Dead if it is Alive or Dying.
   749  // It does nothing otherwise. EnsureDead will fail if the machine has
   750  // principal units assigned, or if the machine has JobManageModel.
   751  // If the machine has assigned units, EnsureDead will return
   752  // a HasAssignedUnitsError.
   753  func (m *Machine) EnsureDead() error {
   754  	return m.advanceLifecycle(Dead, false, false, 0)
   755  }
   756  
   757  // Containers returns the container ids belonging to a parent machine.
   758  // TODO(wallyworld): move this method to a service
   759  func (m *Machine) Containers() ([]string, error) {
   760  	containerRefs, closer := m.st.db().GetCollection(containerRefsC)
   761  	defer closer()
   762  
   763  	var mc machineContainers
   764  	err := containerRefs.FindId(m.doc.DocID).One(&mc)
   765  	if err == nil {
   766  		return mc.Children, nil
   767  	}
   768  	if err == mgo.ErrNotFound {
   769  		return nil, errors.NotFoundf("container info for machine %v", m.Id())
   770  	}
   771  	return nil, err
   772  }
   773  
   774  // ParentId returns the Id of the host machine if this machine is a container.
   775  func (m *Machine) ParentId() (string, bool) {
   776  	parentId := corecontainer.ParentId(m.Id())
   777  	return parentId, parentId != ""
   778  }
   779  
   780  // IsContainer returns true if the machine is a container.
   781  func (m *Machine) IsContainer() bool {
   782  	_, isContainer := m.ParentId()
   783  	return isContainer
   784  }
   785  
   786  // advanceLifecycle ensures that the machine's lifecycle is no earlier
   787  // than the supplied value. If the machine already has that lifecycle
   788  // value, or a later one, no changes will be made to remote state. If
   789  // the machine has any responsibilities that preclude a valid change in
   790  // lifecycle, it will return an error. dyingAllowContainers indicates
   791  // whether the machine can have containers when moving to the dying state.
   792  // Not allowed for moving to dead.
   793  func (original *Machine) advanceLifecycle(life Life, force, dyingAllowContainers bool, maxWait time.Duration) (err error) {
   794  	logger.Debugf("%s.advanceLifecycle(%s, %t, %t)", original.Id(), life, force, dyingAllowContainers)
   795  
   796  	if life == Dead && dyingAllowContainers {
   797  		return errors.BadRequestf("life cannot be Dead if dyingAllowContainers true.")
   798  	}
   799  
   800  	// A machine can be set to dying with containers, but cannot have any when
   801  	// advanced to dead.
   802  	if !dyingAllowContainers && life == Dying {
   803  		if err := original.advanceLifecycleIfNoContainers(); err != nil {
   804  			return err
   805  		}
   806  	}
   807  
   808  	locked, err := original.IsLockedForSeriesUpgrade()
   809  	if err != nil {
   810  		return errors.Annotatef(err, "reading machine %s upgrade-series lock", original.Id())
   811  	}
   812  	if locked {
   813  		return errors.Errorf("machine %s is locked for series upgrade", original.Id())
   814  	}
   815  
   816  	m := original
   817  	defer func() {
   818  		if err == nil {
   819  			// The machine's lifecycle is known to have advanced; it may be
   820  			// known to have already advanced further than requested, in
   821  			// which case we set the latest known valid value.
   822  			if m == nil {
   823  				life = Dead
   824  			} else if m.doc.Life > life {
   825  				life = m.doc.Life
   826  			}
   827  			original.doc.Life = life
   828  		}
   829  	}()
   830  
   831  	ops := m.advanceLifecyleInitialOps(life)
   832  
   833  	// multiple attempts: one with original data, one with refreshed data, and a final
   834  	// one intended to determine the cause of failure of the preceding attempt.
   835  	buildTxn := func(attempt int) ([]txn.Op, error) {
   836  		var asserts bson.D
   837  		// Grab a fresh copy of the machine data.
   838  		// We don't write to original, because the expectation is that state-
   839  		// changing methods only set the requested change on the receiver; a case
   840  		// could perhaps be made that this is not a helpful convention in the
   841  		// context of the new state API, but we maintain consistency in the
   842  		// face of uncertainty.
   843  		if m, err = m.st.Machine(m.doc.Id); errors.IsNotFound(err) {
   844  			return nil, jujutxn.ErrNoOperations
   845  		} else if err != nil {
   846  			return nil, err
   847  		}
   848  		node, err := m.st.ControllerNode(m.doc.Id)
   849  		if err != nil && !errors.IsNotFound(err) {
   850  			return nil, err
   851  		}
   852  		hasVote := err == nil && node.HasVote()
   853  
   854  		// Check that the life change is sane, and collect the assertions
   855  		// necessary to determine that it remains so.
   856  		switch life {
   857  		case Dying:
   858  			if m.doc.Life != Alive {
   859  				return nil, jujutxn.ErrNoOperations
   860  			}
   861  			// Manager nodes are allowed to go to dying even when they have
   862  			// the vote, as that is used as the signal that they should lose
   863  			// their vote.
   864  			asserts = append(asserts, isAliveDoc...)
   865  		case Dead:
   866  			if m.doc.Life == Dead {
   867  				return nil, jujutxn.ErrNoOperations
   868  			}
   869  			if hasVote || m.IsManager() {
   870  				return nil, stateerrors.NewIsControllerMemberError(m.Id(), hasVote)
   871  			}
   872  			asserts = append(asserts, bson.DocElem{
   873  				Name: "jobs", Value: bson.D{{Name: "$nin", Value: []MachineJob{JobManageModel}}}})
   874  			asserts = append(asserts, notDeadDoc...)
   875  			ops = append(ops, controllerAdvanceLifecyleVoteOp())
   876  		default:
   877  			panic(fmt.Errorf("cannot advance lifecycle to %v", life))
   878  		}
   879  
   880  		// Check that the machine does not have any responsibilities that
   881  		// prevent a lifecycle change.
   882  		// If there are no alive units left on the machine, or all the applications are dying,
   883  		// then the machine may be soon destroyed by a cleanup worker.
   884  		// In that case, we don't want to return any error about not being able to
   885  		// destroy a machine with units as it will be a lie.
   886  		if life == Dying {
   887  			canDie := true
   888  			if isController(&m.doc) || hasVote {
   889  				// If we're responsible for managing the model, make sure we ask to drop our vote
   890  				ops[0].Update = bson.D{
   891  					{"$set", bson.D{{"life", life}}},
   892  				}
   893  				controllerOp, err := m.controllerIDsOp()
   894  				if err != nil {
   895  					return nil, errors.Trace(err)
   896  				}
   897  				ops = append(ops, controllerOp)
   898  				ops = append(ops, setControllerWantsVoteOp(m.st, m.doc.Id, false))
   899  			}
   900  
   901  			var principalUnitNames []string
   902  			for _, principalUnit := range m.doc.Principals {
   903  				principalUnitNames = append(principalUnitNames, principalUnit)
   904  				canDie, err = m.assessCanDieUnit(principalUnit)
   905  				if err != nil {
   906  					return nil, errors.Trace(err)
   907  				}
   908  				if !canDie {
   909  					break
   910  				}
   911  			}
   912  
   913  			if canDie && !dyingAllowContainers {
   914  				err := m.advanceLifecycleIfNoContainers()
   915  				if errors.Is(err, stateerrors.HasContainersError) {
   916  					canDie = false
   917  				} else if err != nil {
   918  					return nil, err
   919  				}
   920  				ops = append(ops, m.noContainersOp())
   921  			}
   922  
   923  			cleanupOp := newCleanupOp(cleanupDyingMachine, m.doc.Id, force, maxWait)
   924  			ops = append(ops, cleanupOp)
   925  
   926  			if canDie {
   927  				ops[0].Assert = append(asserts, advanceLifecycleUnitAsserts(principalUnitNames))
   928  				txnLogger.Debugf("txn moving machine %q to %s", m.Id(), life)
   929  				return ops, nil
   930  			}
   931  		}
   932  
   933  		if len(m.doc.Principals) > 0 {
   934  			return nil, stateerrors.NewHasAssignedUnitsError(m.doc.Id, m.doc.Principals)
   935  		}
   936  		asserts = append(asserts, noUnitAsserts())
   937  
   938  		if life == Dead {
   939  			// A machine may not become Dead until it has no
   940  			// containers.
   941  			if err := m.advanceLifecycleIfNoContainers(); err != nil {
   942  				return nil, err
   943  			}
   944  			ops = append(ops, m.noContainersOp())
   945  			if isController(&m.doc) {
   946  				return nil, errors.Errorf("machine %s is still responsible for being a controller", m.Id())
   947  			}
   948  			// A machine may not become Dead until it has no more
   949  			// attachments to detachable storage.
   950  			storageAsserts, err := m.assertNoPersistentStorage()
   951  			if err != nil {
   952  				return nil, errors.Trace(err)
   953  			}
   954  			asserts = append(asserts, storageAsserts...)
   955  		}
   956  
   957  		// Add the additional asserts needed for this transaction.
   958  		ops[0].Assert = asserts
   959  		return ops, nil
   960  	}
   961  
   962  	if err = m.st.db().Run(buildTxn); err == jujutxn.ErrExcessiveContention {
   963  		err = errors.Annotatef(err, "machine %s cannot advance lifecycle", m)
   964  	}
   965  	return err
   966  }
   967  
   968  func (m *Machine) advanceLifecyleInitialOps(life Life) []txn.Op {
   969  	return []txn.Op{
   970  		{
   971  			C:      machinesC,
   972  			Id:     m.doc.DocID,
   973  			Update: bson.D{{"$set", bson.D{{"life", life}}}},
   974  		},
   975  		{
   976  			C:      machineUpgradeSeriesLocksC,
   977  			Id:     m.doc.Id,
   978  			Assert: txn.DocMissing,
   979  		},
   980  	}
   981  }
   982  
   983  func controllerAdvanceLifecyleVoteOp() txn.Op {
   984  	return txn.Op{
   985  		C:  controllersC,
   986  		Id: modelGlobalKey,
   987  		Assert: bson.D{
   988  			{"has-vote", bson.M{"$ne": true}},
   989  			{"wants-vote", bson.M{"$ne": true}},
   990  		},
   991  	}
   992  }
   993  
   994  // controllerIDsOp returns an Op to assert that the machine's
   995  // controllerIDs do not change.
   996  func (m *Machine) controllerIDsOp() (txn.Op, error) {
   997  	controllerIds, err := m.st.ControllerIds()
   998  	if err != nil {
   999  		return txn.Op{}, errors.Annotatef(err, "reading controller info")
  1000  	}
  1001  	if len(controllerIds) <= 1 {
  1002  		return txn.Op{}, errors.Errorf("controller %s is the only controller", m.Id())
  1003  	}
  1004  	return txn.Op{
  1005  		C:      controllersC,
  1006  		Id:     modelGlobalKey,
  1007  		Assert: bson.D{{"controller-ids", controllerIds}},
  1008  	}, nil
  1009  }
  1010  
  1011  // noContainersOp returns an Op to assert that the machine
  1012  // has no containers.
  1013  func (m *Machine) noContainersOp() txn.Op {
  1014  	return txn.Op{
  1015  		C:  containerRefsC,
  1016  		Id: m.doc.DocID,
  1017  		Assert: bson.D{{"$or", []bson.D{
  1018  			{{"children", bson.D{{"$size", 0}}}},
  1019  			{{"children", bson.D{{"$exists", false}}}},
  1020  		}}},
  1021  	}
  1022  }
  1023  
  1024  // assessCanDieUnit returns true if the machine can die, based on
  1025  // evaluating the provided unit.
  1026  func (m *Machine) assessCanDieUnit(principalUnit string) (bool, error) {
  1027  	canDie := true
  1028  	u, err := m.st.Unit(principalUnit)
  1029  	if err != nil {
  1030  		return false, errors.Annotatef(err, "reading machine %s principal unit %v", m, m.doc.Principals[0])
  1031  	}
  1032  	app, err := u.Application()
  1033  	if err != nil {
  1034  		return false, errors.Annotatef(err, "reading machine %s principal unit application %v", m, u.doc.Application)
  1035  	}
  1036  	if u.Life() == Alive && app.Life() == Alive {
  1037  		canDie = false
  1038  	}
  1039  	return canDie, nil
  1040  }
  1041  
  1042  // noUnitAsserts returns bson DocElem which assert that there are
  1043  // no units for the machine.
  1044  func noUnitAsserts() bson.DocElem {
  1045  	return bson.DocElem{
  1046  		Name: "$or", Value: []bson.D{
  1047  			{{"principals", bson.D{{"$size", 0}}}},
  1048  			{{"principals", bson.D{{"$exists", false}}}},
  1049  		},
  1050  	}
  1051  }
  1052  
  1053  // advanceLifecycleUnitAsserts returns bson DocElem which assert that there are
  1054  // no units for the machine, or that the list of units has not changed.
  1055  func advanceLifecycleUnitAsserts(principalUnitNames []string) bson.DocElem {
  1056  	return bson.DocElem{
  1057  		Name: "$or", Value: []bson.D{
  1058  			{{Name: "principals", Value: principalUnitNames}},
  1059  			{{Name: "principals", Value: bson.D{{"$size", 0}}}},
  1060  			{{Name: "principals", Value: bson.D{{"$exists", false}}}},
  1061  		},
  1062  	}
  1063  }
  1064  
  1065  // advanceLifecycleIfNoContainers determines if the machine has
  1066  // containers, if so, returns the appropriate error.
  1067  func (m *Machine) advanceLifecycleIfNoContainers() error {
  1068  	containers, err := m.Containers()
  1069  	if err != nil {
  1070  		return errors.Annotatef(err, "reading machine %s containers", m)
  1071  	}
  1072  
  1073  	if len(containers) > 0 {
  1074  		return stateerrors.NewHasContainersError(m.doc.Id, containers)
  1075  	}
  1076  	return nil
  1077  }
  1078  
  1079  // assertNoPersistentStorage ensures that there are no persistent volumes or
  1080  // filesystems attached to the machine, and returns any mgo/txn assertions
  1081  // required to ensure that remains true.
  1082  func (m *Machine) assertNoPersistentStorage() (bson.D, error) {
  1083  	attachments := names.NewSet()
  1084  	for _, v := range m.doc.Volumes {
  1085  		tag := names.NewVolumeTag(v)
  1086  		detachable, err := isDetachableVolumeTag(m.st.db(), tag)
  1087  		if err != nil {
  1088  			return nil, errors.Trace(err)
  1089  		}
  1090  		if detachable {
  1091  			attachments.Add(tag)
  1092  		}
  1093  	}
  1094  	for _, f := range m.doc.Filesystems {
  1095  		tag := names.NewFilesystemTag(f)
  1096  		detachable, err := isDetachableFilesystemTag(m.st.db(), tag)
  1097  		if err != nil {
  1098  			return nil, errors.Trace(err)
  1099  		}
  1100  		if detachable {
  1101  			attachments.Add(tag)
  1102  		}
  1103  	}
  1104  	if len(attachments) > 0 {
  1105  		return nil, stateerrors.NewHasAttachmentsError(m.doc.Id, attachments.SortedValues())
  1106  	}
  1107  	if m.doc.Life == Dying {
  1108  		return nil, nil
  1109  	}
  1110  	// A Dying machine cannot have attachments added to it,
  1111  	// but if we're advancing from Alive to Dead then we
  1112  	// must ensure no concurrent attachments are made.
  1113  	noNewVolumes := bson.DocElem{
  1114  		Name: "volumes", Value: bson.D{{
  1115  			"$not", bson.D{{
  1116  				"$elemMatch", bson.D{{
  1117  					"$nin", m.doc.Volumes,
  1118  				}},
  1119  			}},
  1120  		}},
  1121  		// There are no volumes that are not in
  1122  		// the set of volumes we previously knew
  1123  		// about => the current set of volumes
  1124  		// is a subset of the previously known set.
  1125  	}
  1126  	noNewFilesystems := bson.DocElem{
  1127  		Name: "filesystems", Value: bson.D{{
  1128  			"$not", bson.D{{
  1129  				"$elemMatch", bson.D{{
  1130  					"$nin", m.doc.Filesystems,
  1131  				}},
  1132  			}},
  1133  		}},
  1134  	}
  1135  	return bson.D{noNewVolumes, noNewFilesystems}, nil
  1136  }
  1137  
  1138  func (m *Machine) removePortsOps() ([]txn.Op, error) {
  1139  	if m.doc.Life != Dead {
  1140  		return nil, errors.Errorf("machine is not dead")
  1141  	}
  1142  	machRanges, err := m.OpenedPortRanges()
  1143  	if err != nil {
  1144  		return nil, err
  1145  	}
  1146  
  1147  	mpr := machRanges.(*machinePortRanges)
  1148  	if !mpr.Persisted() {
  1149  		return nil, nil
  1150  	}
  1151  	return mpr.removeOps(), nil
  1152  }
  1153  
  1154  func (m *Machine) removeOps() ([]txn.Op, error) {
  1155  	if m.doc.Life != Dead {
  1156  		return nil, fmt.Errorf("machine is not dead")
  1157  	}
  1158  	ops := []txn.Op{
  1159  		{
  1160  			C:      machinesC,
  1161  			Id:     m.doc.DocID,
  1162  			Assert: txn.DocExists,
  1163  			Remove: true,
  1164  		},
  1165  		{
  1166  			C:      machinesC,
  1167  			Id:     m.doc.DocID,
  1168  			Assert: isDeadDoc,
  1169  		},
  1170  		removeStatusOp(m.st, m.globalKey()),
  1171  		removeStatusOp(m.st, m.globalInstanceKey()),
  1172  		removeStatusOp(m.st, m.globalModificationKey()),
  1173  		removeConstraintsOp(m.globalKey()),
  1174  		annotationRemoveOp(m.st, m.globalKey()),
  1175  		removeRebootDocOp(m.st, m.globalKey()),
  1176  		removeMachineBlockDevicesOp(m.Id()),
  1177  		removeModelMachineRefOp(m.st, m.Id()),
  1178  		removeSSHHostKeyOp(m.globalKey()),
  1179  		removeInstanceDataOp(m.doc.DocID),
  1180  	}
  1181  	linkLayerDevicesOps, err := m.removeAllLinkLayerDevicesOps()
  1182  	if err != nil {
  1183  		return nil, errors.Trace(err)
  1184  	}
  1185  	devicesAddressesOps, err := m.removeAllAddressesOps()
  1186  	if err != nil {
  1187  		return nil, errors.Trace(err)
  1188  	}
  1189  	portsOps, err := m.removePortsOps()
  1190  	if err != nil {
  1191  		return nil, errors.Trace(err)
  1192  	}
  1193  
  1194  	sb, err := NewStorageBackend(m.st)
  1195  	if err != nil {
  1196  		return nil, errors.Trace(err)
  1197  	}
  1198  	filesystemOps, err := sb.removeMachineFilesystemsOps(m)
  1199  	if err != nil {
  1200  		return nil, errors.Trace(err)
  1201  	}
  1202  	volumeOps, err := sb.removeMachineVolumesOps(m)
  1203  	if err != nil {
  1204  		return nil, errors.Trace(err)
  1205  	}
  1206  
  1207  	ops = append(ops, removeControllerNodeOp(m.st, m.Id()))
  1208  	ops = append(ops, linkLayerDevicesOps...)
  1209  	ops = append(ops, devicesAddressesOps...)
  1210  	ops = append(ops, portsOps...)
  1211  	ops = append(ops, removeContainerRefOps(m.st, m.Id())...)
  1212  	ops = append(ops, filesystemOps...)
  1213  	ops = append(ops, volumeOps...)
  1214  	return ops, nil
  1215  }
  1216  
  1217  // Remove removes the machine from state. It will fail if the machine
  1218  // is not Dead.
  1219  func (m *Machine) Remove() (err error) {
  1220  	defer errors.DeferredAnnotatef(&err, "cannot remove machine %s", m.doc.Id)
  1221  	logger.Tracef("removing machine %q", m.Id())
  1222  	// Local variable so we can re-get the machine without disrupting
  1223  	// the caller.
  1224  	machine := m
  1225  	buildTxn := func(attempt int) ([]txn.Op, error) {
  1226  		if attempt != 0 {
  1227  			machine, err = machine.st.Machine(machine.Id())
  1228  			if errors.IsNotFound(err) {
  1229  				// The machine's gone away, that's fine.
  1230  				return nil, jujutxn.ErrNoOperations
  1231  			}
  1232  			if err != nil {
  1233  				return nil, errors.Trace(err)
  1234  			}
  1235  		}
  1236  		ops, err := machine.removeOps()
  1237  		if err != nil {
  1238  			return nil, errors.Trace(err)
  1239  		}
  1240  		return ops, nil
  1241  	}
  1242  	return m.st.db().Run(buildTxn)
  1243  }
  1244  
  1245  // Refresh refreshes the contents of the machine from the underlying
  1246  // state. It returns an error that satisfies errors.IsNotFound if the
  1247  // machine has been removed.
  1248  func (m *Machine) Refresh() error {
  1249  	mdoc, err := m.st.getMachineDoc(m.Id())
  1250  	if err != nil {
  1251  		if errors.IsNotFound(err) {
  1252  			return err
  1253  		}
  1254  		return errors.Annotatef(err, "cannot refresh machine %v", m)
  1255  	}
  1256  	m.doc = *mdoc
  1257  	return nil
  1258  }
  1259  
  1260  // InstanceId returns the provider specific instance id for this
  1261  // machine, or a NotProvisionedError, if not set.
  1262  func (m *Machine) InstanceId() (instance.Id, error) {
  1263  	instId, _, err := m.InstanceNames()
  1264  	return instId, err
  1265  }
  1266  
  1267  // InstanceNames returns both the provider's instance id and a user-friendly
  1268  // display name. The display name is intended used for human input and
  1269  // is ignored internally.
  1270  func (m *Machine) InstanceNames() (instance.Id, string, error) {
  1271  	instData, err := getInstanceData(m.st, m.Id())
  1272  	if errors.IsNotFound(err) {
  1273  		err = errors.NotProvisionedf("machine %v", m.Id())
  1274  	}
  1275  	if err != nil {
  1276  		return "", "", err
  1277  	}
  1278  	return instData.InstanceId, instData.DisplayName, nil
  1279  }
  1280  
  1281  // InstanceStatus returns the provider specific instance status for this machine,
  1282  // or a NotProvisionedError if instance is not yet provisioned.
  1283  func (m *Machine) InstanceStatus() (status.StatusInfo, error) {
  1284  	machineStatus, err := getStatus(m.st.db(), m.globalInstanceKey(), "instance")
  1285  	if err != nil {
  1286  		logger.Warningf("error when retrieving instance status for machine: %s, %v", m.Id(), err)
  1287  		return status.StatusInfo{}, err
  1288  	}
  1289  	return machineStatus, nil
  1290  }
  1291  
  1292  // SetInstanceStatus sets the provider specific instance status for a machine.
  1293  func (m *Machine) SetInstanceStatus(sInfo status.StatusInfo) (err error) {
  1294  	return setStatus(m.st.db(), setStatusParams{
  1295  		badge:     "instance",
  1296  		globalKey: m.globalInstanceKey(),
  1297  		status:    sInfo.Status,
  1298  		message:   sInfo.Message,
  1299  		rawData:   sInfo.Data,
  1300  		updated:   timeOrNow(sInfo.Since, m.st.clock()),
  1301  	})
  1302  }
  1303  
  1304  // InstanceStatusHistory returns a slice of at most filter.Size StatusInfo items
  1305  // or items as old as filter.Date or items newer than now - filter.Delta time
  1306  // representing past statuses for this machine instance.
  1307  // Instance represents the provider underlying [v]hardware or container where
  1308  // this juju machine is deployed.
  1309  func (m *Machine) InstanceStatusHistory(filter status.StatusHistoryFilter) ([]status.StatusInfo, error) {
  1310  	args := &statusHistoryArgs{
  1311  		db:        m.st.db(),
  1312  		globalKey: m.globalInstanceKey(),
  1313  		filter:    filter,
  1314  		clock:     m.st.clock(),
  1315  	}
  1316  	return statusHistory(args)
  1317  }
  1318  
  1319  // ModificationStatus returns the provider specific modification status for
  1320  // this machine or NotProvisionedError if instance is not yet provisioned.
  1321  func (m *Machine) ModificationStatus() (status.StatusInfo, error) {
  1322  	machineStatus, err := getStatus(m.st.db(), m.globalModificationKey(), "modification")
  1323  	if err != nil {
  1324  		logger.Warningf("error when retrieving instance status for machine: %s, %v", m.Id(), err)
  1325  		return status.StatusInfo{}, err
  1326  	}
  1327  	return machineStatus, nil
  1328  }
  1329  
  1330  // SetModificationStatus sets the provider specific modification status
  1331  // for a machine. Allowing the propagation of status messages to the
  1332  // operator.
  1333  func (m *Machine) SetModificationStatus(sInfo status.StatusInfo) (err error) {
  1334  	return setStatus(m.st.db(), setStatusParams{
  1335  		badge:     "modification",
  1336  		globalKey: m.globalModificationKey(),
  1337  		status:    sInfo.Status,
  1338  		message:   sInfo.Message,
  1339  		rawData:   sInfo.Data,
  1340  		updated:   timeOrNow(sInfo.Since, m.st.clock()),
  1341  	})
  1342  }
  1343  
  1344  // AvailabilityZone returns the provider-specific instance availability
  1345  // zone in which the machine was provisioned.
  1346  func (m *Machine) AvailabilityZone() (string, error) {
  1347  	instData, err := getInstanceData(m.st, m.Id())
  1348  	if errors.IsNotFound(err) {
  1349  		return "", errors.Trace(errors.NotProvisionedf("machine %v", m.Id()))
  1350  	}
  1351  	if err != nil {
  1352  		return "", errors.Trace(err)
  1353  	}
  1354  	var zone string
  1355  	if instData.AvailZone != nil {
  1356  		zone = *instData.AvailZone
  1357  	}
  1358  	return zone, nil
  1359  }
  1360  
  1361  // ApplicationNames returns the names of applications
  1362  // represented by units running on the machine.
  1363  func (m *Machine) ApplicationNames() ([]string, error) {
  1364  	units, err := m.Units()
  1365  	if err != nil {
  1366  		return nil, errors.Trace(err)
  1367  	}
  1368  	apps := set.NewStrings()
  1369  	for _, unit := range units {
  1370  		apps.Add(unit.ApplicationName())
  1371  	}
  1372  	return apps.SortedValues(), nil
  1373  }
  1374  
  1375  // Units returns all the units that have been assigned to the machine.
  1376  func (m *Machine) Units() (units []*Unit, err error) {
  1377  	defer errors.DeferredAnnotatef(&err, "cannot get units assigned to machine %v", m)
  1378  	unitsCollection, closer := m.st.db().GetCollection(unitsC)
  1379  	defer closer()
  1380  
  1381  	pudocs := []unitDoc{}
  1382  	err = unitsCollection.Find(bson.D{{"machineid", m.doc.Id}}).All(&pudocs)
  1383  	if err != nil {
  1384  		return nil, err
  1385  	}
  1386  	model, err := m.st.Model()
  1387  	if err != nil {
  1388  		return nil, errors.Trace(err)
  1389  	}
  1390  	for _, pudoc := range pudocs {
  1391  		units = append(units, newUnit(m.st, model.Type(), &pudoc))
  1392  	}
  1393  	return units, nil
  1394  }
  1395  
  1396  // SetProvisioned stores the machine's provider-specific details in the
  1397  // database. These details are used to infer that the machine has
  1398  // been provisioned.
  1399  //
  1400  // When provisioning an instance, a nonce should be created and passed
  1401  // when starting it, before adding the machine to the state. This means
  1402  // that if the provisioner crashes (or its connection to the state is
  1403  // lost) after starting the instance, we can be sure that only a single
  1404  // instance will be able to act for that machine.
  1405  //
  1406  // Once set, the instance id cannot be changed. A non-empty instance id
  1407  // will be detected as a provisioned machine.
  1408  func (m *Machine) SetProvisioned(
  1409  	id instance.Id,
  1410  	displayName string,
  1411  	nonce string,
  1412  	characteristics *instance.HardwareCharacteristics,
  1413  ) (err error) {
  1414  	defer errors.DeferredAnnotatef(&err, "cannot set instance data for machine %q", m)
  1415  
  1416  	if id == "" || nonce == "" {
  1417  		return fmt.Errorf("instance id and nonce cannot be empty")
  1418  	}
  1419  
  1420  	coll, closer := m.st.db().GetCollection(instanceDataC)
  1421  	defer closer()
  1422  	count, err := coll.Find(bson.D{{"instanceid", id}}).Count()
  1423  	if err != nil {
  1424  		return errors.Trace(err)
  1425  	}
  1426  	if count > 0 {
  1427  		logger.Warningf("duplicate instance id %q already saved", id)
  1428  	}
  1429  
  1430  	if characteristics == nil {
  1431  		characteristics = &instance.HardwareCharacteristics{}
  1432  	}
  1433  	instData := &instanceData{
  1434  		DocID:          m.doc.DocID,
  1435  		MachineId:      m.doc.Id,
  1436  		InstanceId:     id,
  1437  		DisplayName:    displayName,
  1438  		ModelUUID:      m.doc.ModelUUID,
  1439  		Arch:           characteristics.Arch,
  1440  		Mem:            characteristics.Mem,
  1441  		RootDisk:       characteristics.RootDisk,
  1442  		RootDiskSource: characteristics.RootDiskSource,
  1443  		CpuCores:       characteristics.CpuCores,
  1444  		CpuPower:       characteristics.CpuPower,
  1445  		Tags:           characteristics.Tags,
  1446  		AvailZone:      characteristics.AvailabilityZone,
  1447  		VirtType:       characteristics.VirtType,
  1448  	}
  1449  
  1450  	ops := []txn.Op{
  1451  		{
  1452  			C:      machinesC,
  1453  			Id:     m.doc.DocID,
  1454  			Assert: append(isAliveDoc, bson.DocElem{Name: "nonce", Value: ""}),
  1455  			Update: bson.D{{"$set", bson.D{{"nonce", nonce}}}},
  1456  		}, {
  1457  			C:      instanceDataC,
  1458  			Id:     m.doc.DocID,
  1459  			Assert: txn.DocMissing,
  1460  			Insert: instData,
  1461  		},
  1462  	}
  1463  
  1464  	if err = m.st.db().RunTransaction(ops); err == nil {
  1465  		m.doc.Nonce = nonce
  1466  		return nil
  1467  	} else if err != txn.ErrAborted {
  1468  		return err
  1469  	} else if alive, err := isAlive(m.st, machinesC, m.doc.DocID); err != nil {
  1470  		return err
  1471  	} else if !alive {
  1472  		return machineNotAliveErr
  1473  	}
  1474  	return fmt.Errorf("already set")
  1475  }
  1476  
  1477  // SetInstanceInfo is used to provision a machine and in one step sets its
  1478  // instance ID, nonce, hardware characteristics, add link-layer devices and set
  1479  // their addresses as needed.  After, set charm profiles if needed.
  1480  func (m *Machine) SetInstanceInfo(
  1481  	id instance.Id, displayName string, nonce string, characteristics *instance.HardwareCharacteristics,
  1482  	devicesArgs []LinkLayerDeviceArgs, devicesAddrs []LinkLayerDeviceAddress,
  1483  	volumes map[names.VolumeTag]VolumeInfo,
  1484  	volumeAttachments map[names.VolumeTag]VolumeAttachmentInfo,
  1485  	charmProfiles []string,
  1486  ) error {
  1487  	logger.Tracef(
  1488  		"setting instance info: machine %v, deviceAddrs: %#v, devicesArgs: %#v",
  1489  		m.Id(), devicesAddrs, devicesArgs)
  1490  
  1491  	sb, err := NewStorageBackend(m.st)
  1492  	if err != nil {
  1493  		return errors.Trace(err)
  1494  	}
  1495  
  1496  	// Record volumes and volume attachments, and set the initial
  1497  	// status: attached or attaching.
  1498  	if err := setProvisionedVolumeInfo(sb, volumes); err != nil {
  1499  		return errors.Trace(err)
  1500  	}
  1501  	if err := setMachineVolumeAttachmentInfo(sb, m.Id(), volumeAttachments); err != nil {
  1502  		return errors.Trace(err)
  1503  	}
  1504  	volumeStatus := make(map[names.VolumeTag]status.Status)
  1505  	for tag := range volumes {
  1506  		volumeStatus[tag] = status.Attaching
  1507  	}
  1508  	for tag := range volumeAttachments {
  1509  		volumeStatus[tag] = status.Attached
  1510  	}
  1511  	for tag, volStatus := range volumeStatus {
  1512  		vol, err := sb.Volume(tag)
  1513  		if err != nil {
  1514  			return errors.Trace(err)
  1515  		}
  1516  		if err := vol.SetStatus(status.StatusInfo{
  1517  			Status: volStatus,
  1518  		}); err != nil {
  1519  			return errors.Annotatef(
  1520  				err, "setting status of %s", names.ReadableString(tag),
  1521  			)
  1522  		}
  1523  	}
  1524  
  1525  	if err := m.SetProvisioned(id, displayName, nonce, characteristics); err != nil {
  1526  		return errors.Trace(err)
  1527  	}
  1528  	return m.SetCharmProfiles(charmProfiles)
  1529  }
  1530  
  1531  // Addresses returns any hostnames and ips associated with a machine,
  1532  // determined both by the machine itself, and by asking the provider.
  1533  //
  1534  // The addresses returned by the provider shadow any of the addresses
  1535  // that the machine reported with the same address value.
  1536  // Provider-reported addresses always come before machine-reported
  1537  // addresses. Duplicates are removed.
  1538  func (m *Machine) Addresses() (addresses network.SpaceAddresses) {
  1539  	return network.MergedAddresses(networkAddresses(m.doc.MachineAddresses), networkAddresses(m.doc.Addresses))
  1540  }
  1541  
  1542  func containsAddress(addresses []address, address address) bool {
  1543  	for _, addr := range addresses {
  1544  		if addr.Value == address.Value {
  1545  			return true
  1546  		}
  1547  	}
  1548  	return false
  1549  }
  1550  
  1551  // PublicAddress returns a public address for the machine. If no address is
  1552  // available it returns an error that satisfies network.IsNoAddressError().
  1553  func (m *Machine) PublicAddress() (network.SpaceAddress, error) {
  1554  	publicAddress := m.doc.PreferredPublicAddress.networkAddress()
  1555  	var err error
  1556  	if publicAddress.Value == "" {
  1557  		err = network.NoAddressError("public")
  1558  	}
  1559  	return publicAddress, err
  1560  }
  1561  
  1562  // maybeGetNewAddress determines if the current address is the most appropriate
  1563  // match, and if not it selects the best from the slice of all available
  1564  // addresses. It returns the new address and a bool indicating if a different
  1565  // one was picked.
  1566  func maybeGetNewAddress(
  1567  	addr address,
  1568  	providerAddresses,
  1569  	machineAddresses []address,
  1570  	getAddr func([]address) network.SpaceAddress,
  1571  	checkScope func(address) bool,
  1572  ) (address, bool) {
  1573  	// For picking the best address, try provider addresses first.
  1574  	var newAddr address
  1575  	netAddr := getAddr(providerAddresses)
  1576  	if netAddr.Value == "" {
  1577  		netAddr = getAddr(machineAddresses)
  1578  		newAddr = fromNetworkAddress(netAddr, network.OriginMachine)
  1579  	} else {
  1580  		newAddr = fromNetworkAddress(netAddr, network.OriginProvider)
  1581  	}
  1582  	// The order of these checks is important. If the stored address is
  1583  	// empty we *always* want to check for a new address so we do that
  1584  	// first. If the stored address is unavailable we also *must* check for
  1585  	// a new address so we do that next. If the original is a machine
  1586  	// address and a provider address is available we want to switch to
  1587  	// that. Finally we check to see if a better match on scope from the
  1588  	// same origin is available.
  1589  	if addr.Value == "" {
  1590  		return newAddr, newAddr.Value != ""
  1591  	}
  1592  	if !containsAddress(providerAddresses, addr) && !containsAddress(machineAddresses, addr) {
  1593  		return newAddr, true
  1594  	}
  1595  	if network.Origin(addr.Origin) != network.OriginProvider &&
  1596  		network.Origin(newAddr.Origin) == network.OriginProvider {
  1597  		return newAddr, true
  1598  	}
  1599  	if !checkScope(addr) {
  1600  		// If addr.Origin is machine and newAddr.Origin is provider we will
  1601  		// have already caught that, and for the inverse we don't want to
  1602  		// replace the address.
  1603  		if addr.Origin == newAddr.Origin {
  1604  			return newAddr, checkScope(newAddr)
  1605  		}
  1606  	}
  1607  	return addr, false
  1608  }
  1609  
  1610  // PrivateAddress returns a private address for the machine. If no address is
  1611  // available it returns an error that satisfies network.IsNoAddressError().
  1612  func (m *Machine) PrivateAddress() (network.SpaceAddress, error) {
  1613  	privateAddress := m.doc.PreferredPrivateAddress.networkAddress()
  1614  	var err error
  1615  	if privateAddress.Value == "" {
  1616  		err = network.NoAddressError("private")
  1617  	}
  1618  	return privateAddress, err
  1619  }
  1620  
  1621  func (m *Machine) setPreferredAddressOps(addr address, isPublic bool) []txn.Op {
  1622  	fieldName := "preferredprivateaddress"
  1623  	current := m.doc.PreferredPrivateAddress
  1624  	if isPublic {
  1625  		fieldName = "preferredpublicaddress"
  1626  		current = m.doc.PreferredPublicAddress
  1627  	}
  1628  	// Assert that the field is either missing (never been set) or is
  1629  	// unchanged from its previous value.
  1630  
  1631  	// Since using a struct in the assert also asserts ordering, and we know that mgo
  1632  	// can change the ordering, we assert on the dotted values, effectively checking each
  1633  	// of the attributes of the address.
  1634  	currentD := []bson.D{
  1635  		{{fieldName + ".value", current.Value}},
  1636  		{{fieldName + ".addresstype", current.AddressType}},
  1637  	}
  1638  	// Since scope, origin, and space have omitempty, we don't add them if they are empty.
  1639  	if current.Scope != "" {
  1640  		currentD = append(currentD, bson.D{{fieldName + ".networkscope", current.Scope}})
  1641  	}
  1642  	if current.Origin != "" {
  1643  		currentD = append(currentD, bson.D{{fieldName + ".origin", current.Origin}})
  1644  	}
  1645  	if current.SpaceID != "" {
  1646  		currentD = append(currentD, bson.D{{fieldName + ".spaceid", current.SpaceID}})
  1647  	}
  1648  
  1649  	assert := bson.D{{"$or", []bson.D{
  1650  		{{"$and", currentD}},
  1651  		{{fieldName, nil}}}}}
  1652  
  1653  	ops := []txn.Op{{
  1654  		C:      machinesC,
  1655  		Id:     m.doc.DocID,
  1656  		Update: bson.D{{"$set", bson.D{{fieldName, addr}}}},
  1657  		Assert: assert,
  1658  	}}
  1659  	logger.Tracef("setting preferred address to %v (isPublic %#v)", addr, isPublic)
  1660  	return ops
  1661  }
  1662  
  1663  func (m *Machine) setPublicAddressOps(providerAddresses []address, machineAddresses []address) ([]txn.Op, *address) {
  1664  	publicAddress := m.doc.PreferredPublicAddress
  1665  	logger.Tracef(
  1666  		"machine %v: current public address: %#v \nprovider addresses: %#v \nmachine addresses: %#v",
  1667  		m.Id(), publicAddress, providerAddresses, machineAddresses)
  1668  
  1669  	// Always prefer an exact match if available.
  1670  	checkScope := func(addr address) bool {
  1671  		return network.ExactScopeMatch(addr.networkAddress(), network.ScopePublic)
  1672  	}
  1673  	// Without an exact match, prefer a fallback match.
  1674  	getAddr := func(addresses []address) network.SpaceAddress {
  1675  		addr, _ := networkAddresses(addresses).OneMatchingScope(network.ScopeMatchPublic)
  1676  		return addr
  1677  	}
  1678  
  1679  	newAddr, changed := maybeGetNewAddress(publicAddress, providerAddresses, machineAddresses, getAddr, checkScope)
  1680  	if !changed {
  1681  		// No change, so no ops.
  1682  		return []txn.Op{}, nil
  1683  	}
  1684  
  1685  	ops := m.setPreferredAddressOps(newAddr, true)
  1686  	return ops, &newAddr
  1687  }
  1688  
  1689  func (m *Machine) setPrivateAddressOps(providerAddresses []address, machineAddresses []address) ([]txn.Op, *address) {
  1690  	privateAddress := m.doc.PreferredPrivateAddress
  1691  	// Always prefer an exact match if available.
  1692  	checkScope := func(addr address) bool {
  1693  		return network.ExactScopeMatch(
  1694  			addr.networkAddress(), network.ScopeMachineLocal, network.ScopeCloudLocal, network.ScopeFanLocal)
  1695  	}
  1696  	// Without an exact match, prefer a fallback match.
  1697  	getAddr := func(addresses []address) network.SpaceAddress {
  1698  		addr, _ := networkAddresses(addresses).OneMatchingScope(network.ScopeMatchCloudLocal)
  1699  		return addr
  1700  	}
  1701  
  1702  	newAddr, changed := maybeGetNewAddress(privateAddress, providerAddresses, machineAddresses, getAddr, checkScope)
  1703  	if !changed {
  1704  		// No change, so no ops.
  1705  		return []txn.Op{}, nil
  1706  	}
  1707  	ops := m.setPreferredAddressOps(newAddr, false)
  1708  	return ops, &newAddr
  1709  }
  1710  
  1711  // SetProviderAddresses records any addresses related to the machine, sourced
  1712  // by asking the provider.
  1713  func (m *Machine) SetProviderAddresses(addresses ...network.SpaceAddress) error {
  1714  	err := m.setAddresses(nil, &addresses)
  1715  	return errors.Annotatef(err, "cannot set addresses of machine %v", m)
  1716  }
  1717  
  1718  // ProviderAddresses returns any hostnames and ips associated with a machine,
  1719  // as determined by asking the provider.
  1720  func (m *Machine) ProviderAddresses() (addresses network.SpaceAddresses) {
  1721  	for _, address := range m.doc.Addresses {
  1722  		addresses = append(addresses, address.networkAddress())
  1723  	}
  1724  	return
  1725  }
  1726  
  1727  // MachineAddresses returns any hostnames and ips associated with a machine,
  1728  // determined by asking the machine itself.
  1729  func (m *Machine) MachineAddresses() (addresses network.SpaceAddresses) {
  1730  	for _, address := range m.doc.MachineAddresses {
  1731  		addresses = append(addresses, address.networkAddress())
  1732  	}
  1733  	return
  1734  }
  1735  
  1736  // SetMachineAddresses records any addresses related to the machine, sourced
  1737  // by asking the machine.
  1738  func (m *Machine) SetMachineAddresses(addresses ...network.SpaceAddress) error {
  1739  	err := m.setAddresses(&addresses, nil)
  1740  	return errors.Annotatef(err, "cannot set machine addresses of machine %v", m)
  1741  }
  1742  
  1743  // setAddresses updates the machine's addresses (either Addresses or
  1744  // MachineAddresses, depending on the field argument). Changes are
  1745  // only predicated on the machine not being Dead; concurrent address
  1746  // changes are ignored.
  1747  func (m *Machine) setAddresses(machineAddresses, providerAddresses *[]network.SpaceAddress) error {
  1748  	var (
  1749  		machineStateAddresses, providerStateAddresses []address
  1750  		newPrivate, newPublic                         *address
  1751  		err                                           error
  1752  	)
  1753  	machine := m
  1754  	buildTxn := func(attempt int) ([]txn.Op, error) {
  1755  		if attempt != 0 {
  1756  			if machine, err = machine.st.Machine(machine.doc.Id); err != nil {
  1757  				return nil, err
  1758  			}
  1759  		}
  1760  		var ops []txn.Op
  1761  		ops, machineStateAddresses, providerStateAddresses, newPrivate, newPublic, err = machine.setAddressesOps(
  1762  			machineAddresses, providerAddresses,
  1763  		)
  1764  		if err != nil {
  1765  			return nil, err
  1766  		}
  1767  		return ops, nil
  1768  	}
  1769  	if err := m.st.db().Run(buildTxn); err != nil {
  1770  		return errors.Trace(err)
  1771  	}
  1772  
  1773  	m.doc.MachineAddresses = machineStateAddresses
  1774  	m.doc.Addresses = providerStateAddresses
  1775  	if newPrivate != nil {
  1776  		oldPrivate := m.doc.PreferredPrivateAddress.networkAddress()
  1777  		m.doc.PreferredPrivateAddress = *newPrivate
  1778  		logger.Infof(
  1779  			"machine %q preferred private address changed from %q to %q",
  1780  			m.Id(), oldPrivate, newPrivate.networkAddress(),
  1781  		)
  1782  	}
  1783  	if newPublic != nil {
  1784  		oldPublic := m.doc.PreferredPublicAddress.networkAddress()
  1785  		m.doc.PreferredPublicAddress = *newPublic
  1786  		logger.Infof(
  1787  			"machine %q preferred public address changed from %q to %q",
  1788  			m.Id(), oldPublic, newPublic.networkAddress(),
  1789  		)
  1790  		if isController(&m.doc) {
  1791  			if err := m.st.maybeUpdateControllerCharm(m.doc.PreferredPublicAddress.Value); err != nil {
  1792  				return errors.Trace(err)
  1793  			}
  1794  		}
  1795  	}
  1796  	return nil
  1797  }
  1798  
  1799  func (st *State) maybeUpdateControllerCharm(publicAddr string) error {
  1800  	controllerApp, err := st.Application(bootstrap.ControllerApplicationName)
  1801  	if errors.IsNotFound(err) {
  1802  		return nil
  1803  	}
  1804  	if err != nil {
  1805  		return errors.Trace(err)
  1806  	}
  1807  	controllerCfg, err := st.ControllerConfig()
  1808  	if err != nil {
  1809  		return errors.Trace(err)
  1810  	}
  1811  	return controllerApp.UpdateCharmConfig(model.GenerationMaster, charm.Settings{
  1812  		"controller-url": api.ControllerAPIURL(publicAddr, controllerCfg.APIPort()),
  1813  	})
  1814  }
  1815  
  1816  func (m *Machine) setAddressesOps(
  1817  	machineAddresses, providerAddresses *[]network.SpaceAddress,
  1818  ) (_ []txn.Op, machineStateAddresses, providerStateAddresses []address, newPrivate, newPublic *address, _ error) {
  1819  
  1820  	if m.doc.Life == Dead {
  1821  		return nil, nil, nil, nil, nil, stateerrors.ErrDead
  1822  	}
  1823  
  1824  	fromNetwork := func(in network.SpaceAddresses, origin network.Origin) []address {
  1825  		sorted := make(network.SpaceAddresses, len(in))
  1826  		copy(sorted, in)
  1827  		sort.Sort(sorted)
  1828  		return fromNetworkAddresses(sorted, origin)
  1829  	}
  1830  
  1831  	var set bson.D
  1832  	machineStateAddresses = m.doc.MachineAddresses
  1833  	providerStateAddresses = m.doc.Addresses
  1834  	if machineAddresses != nil {
  1835  		machineStateAddresses = fromNetwork(*machineAddresses, network.OriginMachine)
  1836  		set = append(set, bson.DocElem{Name: "machineaddresses", Value: machineStateAddresses})
  1837  	}
  1838  	if providerAddresses != nil {
  1839  		providerStateAddresses = fromNetwork(*providerAddresses, network.OriginProvider)
  1840  		set = append(set, bson.DocElem{Name: "addresses", Value: providerStateAddresses})
  1841  	}
  1842  
  1843  	ops := []txn.Op{{
  1844  		C:      machinesC,
  1845  		Id:     m.doc.DocID,
  1846  		Assert: notDeadDoc,
  1847  		Update: bson.D{{"$set", set}},
  1848  	}}
  1849  
  1850  	setPrivateAddressOps, newPrivate := m.setPrivateAddressOps(providerStateAddresses, machineStateAddresses)
  1851  	setPublicAddressOps, newPublic := m.setPublicAddressOps(providerStateAddresses, machineStateAddresses)
  1852  	ops = append(ops, setPrivateAddressOps...)
  1853  	ops = append(ops, setPublicAddressOps...)
  1854  	return ops, machineStateAddresses, providerStateAddresses, newPrivate, newPublic, nil
  1855  }
  1856  
  1857  // CheckProvisioned returns true if the machine was provisioned with the given nonce.
  1858  func (m *Machine) CheckProvisioned(nonce string) bool {
  1859  	return nonce == m.doc.Nonce && nonce != ""
  1860  }
  1861  
  1862  // String returns a unique description of this machine.
  1863  func (m *Machine) String() string {
  1864  	return m.doc.Id
  1865  }
  1866  
  1867  // Placement returns the machine's Placement structure that should be used when
  1868  // provisioning an instance for the machine.
  1869  func (m *Machine) Placement() string {
  1870  	return m.doc.Placement
  1871  }
  1872  
  1873  // Constraints returns the exact constraints that should apply when provisioning
  1874  // an instance for the machine.
  1875  func (m *Machine) Constraints() (constraints.Value, error) {
  1876  	return readConstraints(m.st, m.globalKey())
  1877  }
  1878  
  1879  // SetConstraints sets the exact constraints to apply when provisioning an
  1880  // instance for the machine. It will fail if the machine is Dead, or if it
  1881  // is already provisioned.
  1882  func (m *Machine) SetConstraints(cons constraints.Value) (err error) {
  1883  	op := m.UpdateOperation()
  1884  	op.Constraints = &cons
  1885  	return m.st.ApplyOperation(op)
  1886  }
  1887  
  1888  func (m *Machine) setConstraintsOps(cons constraints.Value) ([]txn.Op, error) {
  1889  	unsupported, err := m.st.validateConstraints(cons)
  1890  	if len(unsupported) > 0 {
  1891  		logger.Warningf(
  1892  			"setting constraints on machine %q: unsupported constraints: %v",
  1893  			m.Id(), strings.Join(unsupported, ","),
  1894  		)
  1895  	} else if err != nil {
  1896  		return nil, err
  1897  	}
  1898  
  1899  	if m.doc.Life != Alive {
  1900  		return nil, machineNotAliveErr
  1901  	}
  1902  	if _, err := m.InstanceId(); err == nil {
  1903  		return nil, fmt.Errorf("machine is already provisioned")
  1904  	} else if !errors.IsNotProvisioned(err) {
  1905  		return nil, err
  1906  	}
  1907  
  1908  	notSetYet := bson.D{{"nonce", ""}}
  1909  	ops := []txn.Op{{
  1910  		C:      machinesC,
  1911  		Id:     m.doc.DocID,
  1912  		Assert: append(isAliveDoc, notSetYet...),
  1913  	}}
  1914  	mcons, err := m.st.resolveMachineConstraints(cons)
  1915  	if err != nil {
  1916  		return nil, err
  1917  	}
  1918  	ops = append(ops, setConstraintsOp(m.globalKey(), mcons))
  1919  	return ops, nil
  1920  }
  1921  
  1922  // Status returns the status of the machine.
  1923  func (m *Machine) Status() (status.StatusInfo, error) {
  1924  	mStatus, err := getStatus(m.st.db(), m.globalKey(), "machine")
  1925  	if err != nil {
  1926  		return mStatus, err
  1927  	}
  1928  	return mStatus, nil
  1929  }
  1930  
  1931  // SetStatus sets the status of the machine.
  1932  func (m *Machine) SetStatus(statusInfo status.StatusInfo) error {
  1933  	switch statusInfo.Status {
  1934  	case status.Started, status.Stopped:
  1935  	case status.Error:
  1936  		if statusInfo.Message == "" {
  1937  			return errors.Errorf("cannot set status %q without info", statusInfo.Status)
  1938  		}
  1939  	case status.Pending:
  1940  		// If a machine is not yet provisioned, we allow its status
  1941  		// to be set back to pending (when a retry is to occur).
  1942  		_, err := m.InstanceId()
  1943  		allowPending := errors.IsNotProvisioned(err)
  1944  		if allowPending {
  1945  			break
  1946  		}
  1947  		fallthrough
  1948  	case status.Down:
  1949  		return errors.Errorf("cannot set status %q", statusInfo.Status)
  1950  	default:
  1951  		return errors.Errorf("cannot set invalid status %q", statusInfo.Status)
  1952  	}
  1953  	return setStatus(m.st.db(), setStatusParams{
  1954  		badge:     "machine",
  1955  		globalKey: m.globalKey(),
  1956  		status:    statusInfo.Status,
  1957  		message:   statusInfo.Message,
  1958  		rawData:   statusInfo.Data,
  1959  		updated:   timeOrNow(statusInfo.Since, m.st.clock()),
  1960  	})
  1961  }
  1962  
  1963  // StatusHistory returns a slice of at most filter.Size StatusInfo items
  1964  // or items as old as filter.Date or items newer than now - filter.Delta time
  1965  // representing past statuses for this machine.
  1966  func (m *Machine) StatusHistory(filter status.StatusHistoryFilter) ([]status.StatusInfo, error) {
  1967  	args := &statusHistoryArgs{
  1968  		db:        m.st.db(),
  1969  		globalKey: m.globalKey(),
  1970  		filter:    filter,
  1971  		clock:     m.st.clock(),
  1972  	}
  1973  	return statusHistory(args)
  1974  }
  1975  
  1976  // Clean returns true if the machine does not have any deployed units or containers.
  1977  func (m *Machine) Clean() bool {
  1978  	return m.doc.Clean
  1979  }
  1980  
  1981  // SupportedContainers returns any containers this machine is capable of hosting, and a bool
  1982  // indicating if the supported containers have been determined or not.
  1983  func (m *Machine) SupportedContainers() ([]instance.ContainerType, bool) {
  1984  	return m.doc.SupportedContainers, m.doc.SupportedContainersKnown
  1985  }
  1986  
  1987  // SupportsNoContainers records the fact that this machine doesn't support any containers.
  1988  func (m *Machine) SupportsNoContainers() (err error) {
  1989  	if err = m.updateSupportedContainers([]instance.ContainerType{}); err != nil {
  1990  		return err
  1991  	}
  1992  	return m.markInvalidContainers()
  1993  }
  1994  
  1995  // SetSupportedContainers sets the list of containers supported by this machine.
  1996  func (m *Machine) SetSupportedContainers(containers []instance.ContainerType) (err error) {
  1997  	if len(containers) == 0 {
  1998  		return fmt.Errorf("at least one valid container type is required")
  1999  	}
  2000  	for _, container := range containers {
  2001  		if container == instance.NONE {
  2002  			return fmt.Errorf("%q is not a valid container type", container)
  2003  		}
  2004  	}
  2005  	if err = m.updateSupportedContainers(containers); err != nil {
  2006  		return err
  2007  	}
  2008  	return m.markInvalidContainers()
  2009  }
  2010  
  2011  func isSupportedContainer(container instance.ContainerType, supportedContainers []instance.ContainerType) bool {
  2012  	for _, supportedContainer := range supportedContainers {
  2013  		if supportedContainer == container {
  2014  			return true
  2015  		}
  2016  	}
  2017  	return false
  2018  }
  2019  
  2020  // updateSupportedContainers sets the supported containers on this host machine.
  2021  func (m *Machine) updateSupportedContainers(supportedContainers []instance.ContainerType) (err error) {
  2022  	if m.doc.SupportedContainersKnown {
  2023  		if len(m.doc.SupportedContainers) == len(supportedContainers) {
  2024  			equal := true
  2025  			types := make(map[instance.ContainerType]struct{}, len(m.doc.SupportedContainers))
  2026  			for _, v := range m.doc.SupportedContainers {
  2027  				types[v] = struct{}{}
  2028  			}
  2029  			for _, v := range supportedContainers {
  2030  				if _, ok := types[v]; !ok {
  2031  					equal = false
  2032  					break
  2033  				}
  2034  			}
  2035  			if equal {
  2036  				return nil
  2037  			}
  2038  		}
  2039  	}
  2040  	ops := []txn.Op{
  2041  		{
  2042  			C:      machinesC,
  2043  			Id:     m.doc.DocID,
  2044  			Assert: notDeadDoc,
  2045  			Update: bson.D{
  2046  				{"$set", bson.D{
  2047  					{"supportedcontainers", supportedContainers},
  2048  					{"supportedcontainersknown", true},
  2049  				}}},
  2050  		},
  2051  	}
  2052  	if err = m.st.db().RunTransaction(ops); err != nil {
  2053  		err = onAbort(err, stateerrors.ErrDead)
  2054  		logger.Errorf("cannot update supported containers of machine %v: %v", m, err)
  2055  		return err
  2056  	}
  2057  	m.doc.SupportedContainers = supportedContainers
  2058  	m.doc.SupportedContainersKnown = true
  2059  	return nil
  2060  }
  2061  
  2062  // markInvalidContainers sets the status of any container belonging to this machine
  2063  // as being in error if the container type is not supported.
  2064  func (m *Machine) markInvalidContainers() error {
  2065  	currentContainers, err := m.Containers()
  2066  	if err != nil {
  2067  		return err
  2068  	}
  2069  	for _, containerId := range currentContainers {
  2070  		if !isSupportedContainer(corecontainer.ContainerTypeFromId(containerId), m.doc.SupportedContainers) {
  2071  			container, err := m.st.Machine(containerId)
  2072  			if err != nil {
  2073  				logger.Errorf("loading container %v to mark as invalid: %v", containerId, err)
  2074  				continue
  2075  			}
  2076  			// There should never be a circumstance where an unsupported container is started.
  2077  			// Nonetheless, we check and log an error if such a situation arises.
  2078  			statusInfo, err := container.Status()
  2079  			if err != nil {
  2080  				logger.Errorf("finding status of container %v to mark as invalid: %v", containerId, err)
  2081  				continue
  2082  			}
  2083  			if statusInfo.Status == status.Pending {
  2084  				containerType := corecontainer.ContainerTypeFromId(containerId)
  2085  				now := m.st.clock().Now()
  2086  				s := status.StatusInfo{
  2087  					Status:  status.Error,
  2088  					Message: "unsupported container",
  2089  					Data:    map[string]interface{}{"type": containerType},
  2090  					Since:   &now,
  2091  				}
  2092  				_ = container.SetStatus(s)
  2093  			} else {
  2094  				logger.Errorf("unsupported container %v has unexpected status %v", containerId, statusInfo.Status)
  2095  			}
  2096  		}
  2097  	}
  2098  	return nil
  2099  }
  2100  
  2101  // SetMachineBlockDevices sets the block devices visible on the machine.
  2102  func (m *Machine) SetMachineBlockDevices(info ...BlockDeviceInfo) error {
  2103  	return setMachineBlockDevices(m.st, m.Id(), info)
  2104  }
  2105  
  2106  // VolumeAttachments returns the machine's volume attachments.
  2107  func (m *Machine) VolumeAttachments() ([]VolumeAttachment, error) {
  2108  	sb, err := NewStorageBackend(m.st)
  2109  	if err != nil {
  2110  		return nil, errors.Trace(err)
  2111  	}
  2112  	return sb.MachineVolumeAttachments(m.MachineTag())
  2113  }
  2114  
  2115  // PrepareActionPayload returns the payload to use in creating an action for this machine.
  2116  // Note that the use of spec.InsertDefaults mutates payload.
  2117  func (m *Machine) PrepareActionPayload(name string, payload map[string]interface{}, parallel *bool, executionGroup *string) (map[string]interface{}, bool, string, error) {
  2118  	if len(name) == 0 {
  2119  		return nil, false, "", errors.New("no action name given")
  2120  	}
  2121  
  2122  	spec, ok := actions.PredefinedActionsSpec[name]
  2123  	if !ok {
  2124  		return nil, false, "", errors.Errorf("cannot add action %q to a machine; only predefined actions allowed", name)
  2125  	}
  2126  
  2127  	// Reject bad payloads before attempting to insert defaults.
  2128  	err := spec.ValidateParams(payload)
  2129  	if err != nil {
  2130  		return nil, false, "", errors.Trace(err)
  2131  	}
  2132  	payloadWithDefaults, err := spec.InsertDefaults(payload)
  2133  	if err != nil {
  2134  		return nil, false, "", errors.Trace(err)
  2135  	}
  2136  
  2137  	runParallel := spec.Parallel
  2138  	if parallel != nil {
  2139  		runParallel = *parallel
  2140  	}
  2141  	runExecutionGroup := spec.ExecutionGroup
  2142  	if executionGroup != nil {
  2143  		runExecutionGroup = *executionGroup
  2144  	}
  2145  
  2146  	return payloadWithDefaults, runParallel, runExecutionGroup, nil
  2147  }
  2148  
  2149  // CancelAction is part of the ActionReceiver interface.
  2150  func (m *Machine) CancelAction(action Action) (Action, error) {
  2151  	return action.Finish(ActionResults{Status: ActionCancelled})
  2152  }
  2153  
  2154  // WatchActionNotifications is part of the ActionReceiver interface.
  2155  func (m *Machine) WatchActionNotifications() StringsWatcher {
  2156  	return m.st.watchActionNotificationsFilteredBy(m)
  2157  }
  2158  
  2159  // WatchPendingActionNotifications is part of the ActionReceiver interface.
  2160  func (m *Machine) WatchPendingActionNotifications() StringsWatcher {
  2161  	return m.st.watchEnqueuedActionsFilteredBy(m)
  2162  }
  2163  
  2164  // Actions is part of the ActionReceiver interface.
  2165  func (m *Machine) Actions() ([]Action, error) {
  2166  	return m.st.matchingActions(m)
  2167  }
  2168  
  2169  // CompletedActions is part of the ActionReceiver interface.
  2170  func (m *Machine) CompletedActions() ([]Action, error) {
  2171  	return m.st.matchingActionsCompleted(m)
  2172  }
  2173  
  2174  // PendingActions is part of the ActionReceiver interface.
  2175  func (m *Machine) PendingActions() ([]Action, error) {
  2176  	return m.st.matchingActionsPending(m)
  2177  }
  2178  
  2179  // RunningActions is part of the ActionReceiver interface.
  2180  func (m *Machine) RunningActions() ([]Action, error) {
  2181  	return m.st.matchingActionsRunning(m)
  2182  }
  2183  
  2184  // UpdateMachineSeries updates the base for the Machine.
  2185  func (m *Machine) UpdateMachineSeries(base Base) error {
  2186  	buildTxn := func(attempt int) ([]txn.Op, error) {
  2187  		if attempt > 0 {
  2188  			if err := m.Refresh(); err != nil {
  2189  				return nil, errors.Trace(err)
  2190  			}
  2191  		}
  2192  		// Exit early if the Machine base doesn't need to change.
  2193  		if m.Base().String() == base.String() {
  2194  			return nil, jujutxn.ErrNoOperations
  2195  		}
  2196  
  2197  		units, err := m.Units()
  2198  		if err != nil {
  2199  			return nil, errors.Trace(err)
  2200  		}
  2201  
  2202  		ops := []txn.Op{{
  2203  			C:      machinesC,
  2204  			Id:     m.doc.DocID,
  2205  			Assert: bson.D{{"life", Alive}, {"principals", m.Principals()}},
  2206  			Update: bson.D{{"$set", bson.D{{"base", base}}}},
  2207  		}}
  2208  		for _, unit := range units {
  2209  			ops = append(ops, txn.Op{
  2210  				C:  unitsC,
  2211  				Id: unit.doc.DocID,
  2212  				Assert: bson.D{{"life", Alive},
  2213  					{"charmurl", unit.CharmURL()},
  2214  					{"subordinates", unit.SubordinateNames()}},
  2215  				Update: bson.D{{"$set",
  2216  					bson.D{{"base", base}}}},
  2217  			})
  2218  		}
  2219  
  2220  		return ops, nil
  2221  	}
  2222  	err := m.st.db().Run(buildTxn)
  2223  	return errors.Annotatef(err, "updating series for machine %q", m)
  2224  }
  2225  
  2226  // RecordAgentStartInformation updates the host name (if non-empty) reported
  2227  // by the machine agent and sets the agent start time to the current time.
  2228  func (m *Machine) RecordAgentStartInformation(hostname string) error {
  2229  	now := m.st.clock().Now()
  2230  	update := bson.D{
  2231  		{"agent-started-at", now},
  2232  	}
  2233  
  2234  	if hostname != "" {
  2235  		update = append(update, bson.DocElem{"hostname", hostname})
  2236  	}
  2237  
  2238  	ops := []txn.Op{{
  2239  		C:      machinesC,
  2240  		Id:     m.doc.DocID,
  2241  		Assert: notDeadDoc,
  2242  		Update: bson.D{{"$set", update}},
  2243  	}}
  2244  
  2245  	if err := m.st.db().RunTransaction(ops); err != nil {
  2246  		// If instance doc doesn't exist, that's ok; there's nothing to keep,
  2247  		// but that's not an error we care about.
  2248  		return errors.Annotatef(onAbort(err, nil), "cannot update agent hostname/start time for machine %q", m)
  2249  	}
  2250  	m.doc.AgentStartedAt = now
  2251  	if hostname != "" {
  2252  		m.doc.Hostname = hostname
  2253  	}
  2254  	return nil
  2255  }
  2256  
  2257  // AgentStartTime returns the last recorded timestamp when the machine agent
  2258  // was started.
  2259  func (m *Machine) AgentStartTime() time.Time {
  2260  	return m.doc.AgentStartedAt
  2261  }
  2262  
  2263  // Hostname returns the hostname reported by the machine agent.
  2264  func (m *Machine) Hostname() string {
  2265  	return m.doc.Hostname
  2266  }
  2267  
  2268  // AssertAliveOp returns an assert-only transaction operation
  2269  // that ensures the machine is alive.
  2270  func (m *Machine) AssertAliveOp() txn.Op {
  2271  	return txn.Op{
  2272  		C:      machinesC,
  2273  		Id:     m.doc.DocID,
  2274  		Assert: isAliveDoc,
  2275  	}
  2276  }
  2277  
  2278  // assertMachineNotDeadOp returns an assert-only transaction operation that
  2279  // ensures the machine is not dead.
  2280  func assertMachineNotDeadOp(st *State, machineID string) txn.Op {
  2281  	return txn.Op{
  2282  		C:      machinesC,
  2283  		Id:     st.docID(machineID),
  2284  		Assert: notDeadDoc,
  2285  	}
  2286  }
  2287  
  2288  // UpdateOperation returns a model operation that will update the machine.
  2289  func (m *Machine) UpdateOperation() *UpdateMachineOperation {
  2290  	return &UpdateMachineOperation{m: &Machine{st: m.st, doc: m.doc}}
  2291  }
  2292  
  2293  // UpdateMachineOperation is a model operation for updating a machine.
  2294  type UpdateMachineOperation struct {
  2295  	// m holds the machine to update.
  2296  	m *Machine
  2297  
  2298  	AgentVersion      *version.Binary
  2299  	Constraints       *constraints.Value
  2300  	MachineAddresses  *[]network.SpaceAddress
  2301  	ProviderAddresses *[]network.SpaceAddress
  2302  	PasswordHash      *string
  2303  }
  2304  
  2305  // Build is part of the ModelOperation interface.
  2306  func (op *UpdateMachineOperation) Build(attempt int) ([]txn.Op, error) {
  2307  	if attempt > 0 {
  2308  		if err := op.m.Refresh(); err != nil {
  2309  			return nil, err
  2310  		}
  2311  	}
  2312  
  2313  	var allOps []txn.Op
  2314  
  2315  	if op.AgentVersion != nil {
  2316  		ops, _, err := op.m.setAgentVersionOps(*op.AgentVersion)
  2317  		if err != nil {
  2318  			return nil, errors.Annotate(err, "cannot set agent version")
  2319  		}
  2320  		allOps = append(allOps, ops...)
  2321  	}
  2322  
  2323  	if op.Constraints != nil {
  2324  		ops, err := op.m.setConstraintsOps(*op.Constraints)
  2325  		if err != nil {
  2326  			return nil, errors.Annotate(err, "cannot set constraints")
  2327  		}
  2328  		allOps = append(allOps, ops...)
  2329  	}
  2330  
  2331  	if op.MachineAddresses != nil || op.ProviderAddresses != nil {
  2332  		ops, _, _, _, _, err := op.m.setAddressesOps(op.MachineAddresses, op.ProviderAddresses)
  2333  		if err != nil {
  2334  			return nil, errors.Annotate(err, "cannot set addresses")
  2335  		}
  2336  		allOps = append(allOps, ops...)
  2337  	}
  2338  
  2339  	if op.PasswordHash != nil {
  2340  		ops, err := op.m.setPasswordHashOps(*op.PasswordHash)
  2341  		if err != nil {
  2342  			return nil, errors.Annotate(err, "cannot set password")
  2343  		}
  2344  		allOps = append(allOps, ops...)
  2345  	}
  2346  
  2347  	return allOps, nil
  2348  }
  2349  
  2350  // Done is part of the ModelOperation interface.
  2351  func (op *UpdateMachineOperation) Done(err error) error {
  2352  	return errors.Annotatef(err, "updating machine %q", op.m)
  2353  }
  2354  
  2355  func (st *State) GetManualMachineArches() (set.Strings, error) {
  2356  	instanceDataCollection, closer := st.db().GetCollection(instanceDataC)
  2357  	defer closer()
  2358  
  2359  	var archDocs []struct {
  2360  		Arch string `bson:"arch"`
  2361  	}
  2362  
  2363  	err := instanceDataCollection.Find(bson.M{
  2364  		"instanceid": bson.M{
  2365  			"$regex": "^" + manualMachinePrefix,
  2366  		},
  2367  	}).Select(bson.M{"arch": 1}).All(&archDocs)
  2368  	if err != nil {
  2369  		return nil, fmt.Errorf("cannot get the set of architectures for manual machines: %v", err)
  2370  	}
  2371  
  2372  	archSet := set.NewStrings()
  2373  	for _, archDoc := range archDocs {
  2374  		archSet.Add(archDoc.Arch)
  2375  	}
  2376  	return archSet, nil
  2377  }