github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/machine_linklayerdevices.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state
     5  
     6  import (
     7  	"fmt"
     8  	"net"
     9  
    10  	"github.com/juju/collections/set"
    11  	"github.com/juju/errors"
    12  	"github.com/juju/mgo/v3"
    13  	"github.com/juju/mgo/v3/bson"
    14  	"github.com/juju/mgo/v3/txn"
    15  	jujutxn "github.com/juju/txn/v3"
    16  
    17  	corenetwork "github.com/juju/juju/core/network"
    18  )
    19  
    20  // LinkLayerDevice returns the link-layer device matching the given name. An
    21  // error satisfying errors.IsNotFound() is returned when no such device exists
    22  // on the machine.
    23  func (m *Machine) LinkLayerDevice(name string) (*LinkLayerDevice, error) {
    24  	devID := linkLayerDeviceDocIDFromName(m.st, m.doc.Id, name)
    25  	dev, err := m.st.LinkLayerDevice(devID)
    26  	return dev, errors.Trace(err)
    27  }
    28  
    29  func linkLayerDeviceDocIDFromName(st *State, machineID, deviceName string) string {
    30  	return st.docID(linkLayerDeviceGlobalKey(machineID, deviceName))
    31  }
    32  
    33  // AllLinkLayerDevices returns all exiting link-layer devices of the machine.
    34  func (m *Machine) AllLinkLayerDevices() ([]*LinkLayerDevice, error) {
    35  	var allDevices []*LinkLayerDevice
    36  	callbackFunc := func(resultDoc *linkLayerDeviceDoc) {
    37  		allDevices = append(allDevices, newLinkLayerDevice(m.st, *resultDoc))
    38  	}
    39  
    40  	if err := m.forEachLinkLayerDeviceDoc(nil, callbackFunc); err != nil {
    41  		return nil, errors.Trace(err)
    42  	}
    43  	return allDevices, nil
    44  }
    45  
    46  func (m *Machine) forEachLinkLayerDeviceDoc(
    47  	docFieldsToSelect bson.D, callbackFunc func(resultDoc *linkLayerDeviceDoc),
    48  ) error {
    49  	linkLayerDevices, closer := m.st.db().GetCollection(linkLayerDevicesC)
    50  	defer closer()
    51  
    52  	query := linkLayerDevices.Find(bson.D{{"machine-id", m.doc.Id}})
    53  	if docFieldsToSelect != nil {
    54  		query = query.Select(docFieldsToSelect)
    55  	}
    56  	iter := query.Iter()
    57  
    58  	var resultDoc linkLayerDeviceDoc
    59  	for iter.Next(&resultDoc) {
    60  		callbackFunc(&resultDoc)
    61  	}
    62  
    63  	return errors.Trace(iter.Close())
    64  }
    65  
    66  // AllProviderInterfaceInfos returns the provider details for all of
    67  // the link layer devices belonging to this machine. These can be used
    68  // to identify the devices when interacting with the provider
    69  // directly (for example, releasing container addresses).
    70  func (m *Machine) AllProviderInterfaceInfos() ([]corenetwork.ProviderInterfaceInfo, error) {
    71  	devices, err := m.AllLinkLayerDevices()
    72  	if err != nil {
    73  		return nil, errors.Trace(err)
    74  	}
    75  	result := make([]corenetwork.ProviderInterfaceInfo, len(devices))
    76  	for i, device := range devices {
    77  		result[i].InterfaceName = device.Name()
    78  		result[i].HardwareAddress = device.MACAddress()
    79  		result[i].ProviderId = device.ProviderID()
    80  	}
    81  	return result, nil
    82  }
    83  
    84  // RemoveAllLinkLayerDevices removes all existing link-layer devices of the
    85  // machine in a single transaction. No error is returned when some or all of the
    86  // devices were already removed.
    87  func (m *Machine) RemoveAllLinkLayerDevices() error {
    88  	ops, err := m.removeAllLinkLayerDevicesOps()
    89  	if err != nil {
    90  		return errors.Trace(err)
    91  	}
    92  	if len(ops) == 0 {
    93  		return nil
    94  	}
    95  	return m.st.db().RunTransaction(ops)
    96  }
    97  
    98  func (m *Machine) removeAllLinkLayerDevicesOps() ([]txn.Op, error) {
    99  	var ops []txn.Op
   100  	callbackFunc := func(resultDoc *linkLayerDeviceDoc) {
   101  		removeOps := removeLinkLayerDeviceUnconditionallyOps(resultDoc.DocID)
   102  		ops = append(ops, removeOps...)
   103  		if resultDoc.ProviderID != "" {
   104  			providerId := corenetwork.Id(resultDoc.ProviderID)
   105  			op := m.st.networkEntityGlobalKeyRemoveOp("linklayerdevice", providerId)
   106  			ops = append(ops, op)
   107  		}
   108  	}
   109  
   110  	if err := m.forEachLinkLayerDeviceDoc(nil, callbackFunc); err != nil {
   111  		return nil, errors.Trace(err)
   112  	}
   113  
   114  	return ops, nil
   115  }
   116  
   117  // LinkLayerDeviceArgs contains the arguments accepted by Machine.SetLinkLayerDevices().
   118  type LinkLayerDeviceArgs struct {
   119  	// Name is the name of the device as it appears on the machine.
   120  	Name string
   121  
   122  	// MTU is the maximum transmission unit the device can handle.
   123  	MTU uint
   124  
   125  	// ProviderID is a provider-specific ID of the device. Empty when not
   126  	// supported by the provider. Cannot be cleared once set.
   127  	ProviderID corenetwork.Id
   128  
   129  	// Type is the type of the underlying link-layer device.
   130  	Type corenetwork.LinkLayerDeviceType
   131  
   132  	// MACAddress is the media access control address for the device.
   133  	MACAddress string
   134  
   135  	// IsAutoStart is true if the device should be activated on boot.
   136  	IsAutoStart bool
   137  
   138  	// IsUp is true when the device is up (enabled).
   139  	IsUp bool
   140  
   141  	// ParentName is the name of the parent device, which may be empty. If set,
   142  	// it needs to be an existing device on the same machine, unless the current
   143  	// device is inside a container, in which case ParentName can be a global
   144  	// key of a BridgeDevice on the host machine of the container. Traffic
   145  	// originating from a device egresses from its parent device.
   146  	ParentName string
   147  
   148  	// If this is device is part of a virtual switch, this field indicates
   149  	// the type of switch (e.g. an OVS bridge ) this port belongs to.
   150  	VirtualPortType corenetwork.VirtualPortType
   151  }
   152  
   153  // AddLinkLayerDeviceOps returns transaction operations for adding the input
   154  // link-layer device and the supplied addresses to the machine.
   155  // TODO (manadart 2020-07-22): This method is currently used only for adding
   156  // machine sourced devices and addresses.
   157  // If it is used in future to set provider devices, the provider ID args must
   158  // be included and the global ID collection must be maintained and verified.
   159  func (m *Machine) AddLinkLayerDeviceOps(
   160  	devArgs LinkLayerDeviceArgs, addrArgs ...LinkLayerDeviceAddress,
   161  ) ([]txn.Op, error) {
   162  	devDoc := m.newLinkLayerDeviceDocFromArgs(&devArgs)
   163  	ops := []txn.Op{insertLinkLayerDeviceDocOp(devDoc)}
   164  	for _, addr := range addrArgs {
   165  		address, subnet, err := addr.addressAndSubnet()
   166  		if err != nil {
   167  			return nil, errors.Trace(err)
   168  		}
   169  
   170  		newDoc := ipAddressDoc{
   171  			DeviceName:       devDoc.Name,
   172  			DocID:            devDoc.DocID + "#ip#" + address,
   173  			ModelUUID:        m.doc.ModelUUID,
   174  			MachineID:        m.doc.Id,
   175  			SubnetCIDR:       subnet,
   176  			ConfigMethod:     addr.ConfigMethod,
   177  			Value:            address,
   178  			DNSServers:       addr.DNSServers,
   179  			DNSSearchDomains: addr.DNSSearchDomains,
   180  			GatewayAddress:   addr.GatewayAddress,
   181  			IsDefaultGateway: addr.IsDefaultGateway,
   182  			Origin:           addr.Origin,
   183  		}
   184  		ops = append(ops, insertIPAddressDocOp(&newDoc))
   185  	}
   186  
   187  	return ops, nil
   188  }
   189  
   190  // SetLinkLayerDevices sets link-layer devices on the machine, adding or
   191  // updating existing devices as needed, in a single transaction. ProviderID
   192  // field can be empty if not supported by the provider, but when set must be
   193  // unique within the model, and cannot be unset once set. Errors are returned in
   194  // the following cases:
   195  // - Machine is no longer alive or is missing;
   196  // - Model no longer alive;
   197  // - errors.NotValidError, when any of the fields in args contain invalid values;
   198  //
   199  // Deprecated: (manadart 2020-10-12) This method is only used by tests and is in
   200  // the process of removal. Do not add new usages of it.
   201  func (m *Machine) SetLinkLayerDevices(devicesArgs ...LinkLayerDeviceArgs) (err error) {
   202  	defer errors.DeferredAnnotatef(&err, "cannot set link-layer devices to machine %q", m.doc.Id)
   203  
   204  	if len(devicesArgs) == 0 {
   205  		logger.Debugf("no device addresses to set")
   206  		return nil
   207  	}
   208  
   209  	buildTxn := func(attempt int) ([]txn.Op, error) {
   210  		newDocs, err := m.prepareToSetLinkLayerDevices(devicesArgs)
   211  		if err != nil {
   212  			return nil, errors.Trace(err)
   213  		}
   214  
   215  		if m.doc.Life != Alive {
   216  			return nil, errors.Errorf("machine %q not alive", m.doc.Id)
   217  		}
   218  		if attempt > 0 {
   219  			allIds, err := m.st.allProviderIDsForLinkLayerDevices()
   220  			if err != nil {
   221  				return nil, errors.Trace(err)
   222  			}
   223  			for _, args := range devicesArgs {
   224  				if allIds.Contains(string(args.ProviderID)) {
   225  					return nil, errors.Annotatef(
   226  						newProviderIDNotUniqueError(args.ProviderID), "invalid device %q", args.Name)
   227  				}
   228  			}
   229  		}
   230  
   231  		setDevicesOps, err := m.setDevicesFromDocsOps(newDocs)
   232  		if err != nil {
   233  			return nil, errors.Trace(err)
   234  		}
   235  		if len(setDevicesOps) == 0 {
   236  			logger.Debugf("no changes to LinkLayerDevices for machine %q", m.Id())
   237  			return nil, jujutxn.ErrNoOperations
   238  		}
   239  		return append([]txn.Op{m.assertAliveOp()}, setDevicesOps...), nil
   240  	}
   241  	if err := m.st.db().Run(buildTxn); err != nil {
   242  		return errors.Trace(err)
   243  	}
   244  	return nil
   245  }
   246  
   247  func (st *State) allProviderIDsForLinkLayerDevices() (set.Strings, error) {
   248  	return st.allProviderIDsForEntity("linklayerdevice")
   249  }
   250  
   251  func (st *State) allProviderIDsForEntity(entityName string) (set.Strings, error) {
   252  	idCollection, closer := st.db().GetCollection(providerIDsC)
   253  	defer closer()
   254  
   255  	allProviderIDs := set.NewStrings()
   256  	var doc struct {
   257  		ID string `bson:"_id"`
   258  	}
   259  
   260  	pattern := fmt.Sprintf("^%s:%s:.+$", st.ModelUUID(), entityName)
   261  	modelProviderIDs := bson.D{{"_id", bson.D{{"$regex", pattern}}}}
   262  	iter := idCollection.Find(modelProviderIDs).Iter()
   263  	for iter.Next(&doc) {
   264  		localProviderID := st.localID(doc.ID)[len(entityName)+1:]
   265  		allProviderIDs.Add(localProviderID)
   266  	}
   267  	if err := iter.Close(); err != nil {
   268  		return nil, errors.Trace(err)
   269  	}
   270  	return allProviderIDs, nil
   271  }
   272  
   273  func (m *Machine) prepareToSetLinkLayerDevices(devicesArgs []LinkLayerDeviceArgs) ([]linkLayerDeviceDoc, error) {
   274  	var pendingDocs []linkLayerDeviceDoc
   275  	pendingNames := set.NewStrings()
   276  
   277  	for _, args := range devicesArgs {
   278  		newDoc, err := m.prepareOneSetLinkLayerDeviceArgs(&args, pendingNames)
   279  		if err != nil {
   280  			return nil, errors.Trace(err)
   281  		}
   282  		pendingNames.Add(args.Name)
   283  		pendingDocs = append(pendingDocs, *newDoc)
   284  	}
   285  	return pendingDocs, nil
   286  }
   287  
   288  func (m *Machine) prepareOneSetLinkLayerDeviceArgs(
   289  	args *LinkLayerDeviceArgs, pendingNames set.Strings,
   290  ) (_ *linkLayerDeviceDoc, err error) {
   291  	defer errors.DeferredAnnotatef(&err, "invalid device %q", args.Name)
   292  
   293  	if pendingNames.Contains(args.Name) {
   294  		return nil, errors.NewNotValid(nil, "Name specified more than once")
   295  	}
   296  
   297  	return m.newLinkLayerDeviceDocFromArgs(args), nil
   298  }
   299  
   300  func parseLinkLayerDeviceParentNameAsGlobalKey(parentName string) (hostMachineID, parentDeviceName string, err error) {
   301  	hostMachineID, parentDeviceName, canBeGlobalKey := parseLinkLayerDeviceGlobalKey(parentName)
   302  	if !canBeGlobalKey {
   303  		return "", "", nil
   304  	} else if hostMachineID == "" {
   305  		return "", "", errors.NotValidf("ParentName %q format", parentName)
   306  	}
   307  	return hostMachineID, parentDeviceName, nil
   308  }
   309  
   310  func (m *Machine) newLinkLayerDeviceDocFromArgs(args *LinkLayerDeviceArgs) *linkLayerDeviceDoc {
   311  	linkLayerDeviceDocID := linkLayerDeviceDocIDFromName(m.st, m.doc.Id, args.Name)
   312  
   313  	providerID := string(args.ProviderID)
   314  	modelUUID := m.st.ModelUUID()
   315  
   316  	return &linkLayerDeviceDoc{
   317  		DocID:           linkLayerDeviceDocID,
   318  		Name:            args.Name,
   319  		ModelUUID:       modelUUID,
   320  		MTU:             args.MTU,
   321  		ProviderID:      providerID,
   322  		MachineID:       m.doc.Id,
   323  		Type:            args.Type,
   324  		MACAddress:      args.MACAddress,
   325  		IsAutoStart:     args.IsAutoStart,
   326  		IsUp:            args.IsUp,
   327  		ParentName:      args.ParentName,
   328  		VirtualPortType: args.VirtualPortType,
   329  	}
   330  }
   331  
   332  func (m *Machine) isStillAlive() error {
   333  	if machineAlive, err := isAlive(m.st, machinesC, m.doc.Id); err != nil {
   334  		return errors.Trace(err)
   335  	} else if !machineAlive {
   336  		return errors.Errorf("machine not found or not alive")
   337  	}
   338  	return nil
   339  }
   340  
   341  func (m *Machine) assertAliveOp() txn.Op {
   342  	return txn.Op{
   343  		C:      machinesC,
   344  		Id:     m.doc.Id,
   345  		Assert: isAliveDoc,
   346  	}
   347  }
   348  
   349  func (m *Machine) setDevicesFromDocsOps(newDocs []linkLayerDeviceDoc) ([]txn.Op, error) {
   350  	devices, closer := m.st.db().GetCollection(linkLayerDevicesC)
   351  	defer closer()
   352  
   353  	var ops []txn.Op
   354  	for _, newDoc := range newDocs {
   355  		var existingDoc linkLayerDeviceDoc
   356  		if err := devices.FindId(newDoc.DocID).One(&existingDoc); err == mgo.ErrNotFound {
   357  			// Device does not exist yet - insert it.
   358  			insertOps, err := m.insertLinkLayerDeviceOps(&newDoc)
   359  			if err != nil {
   360  				return nil, errors.Trace(err)
   361  			}
   362  			ops = append(ops, insertOps...)
   363  		} else if err == nil {
   364  			// Device already exists - update what's possible.
   365  			updateOps, err := m.updateLinkLayerDeviceOps(&existingDoc, &newDoc)
   366  			if err != nil {
   367  				return nil, errors.Trace(err)
   368  			}
   369  			ops = append(ops, updateOps...)
   370  		} else {
   371  			return nil, errors.Trace(err)
   372  		}
   373  	}
   374  	return ops, nil
   375  }
   376  
   377  func (m *Machine) insertLinkLayerDeviceOps(newDoc *linkLayerDeviceDoc) ([]txn.Op, error) {
   378  	var ops []txn.Op
   379  	if newDoc.ProviderID != "" {
   380  		id := corenetwork.Id(newDoc.ProviderID)
   381  		ops = append(ops, m.st.networkEntityGlobalKeyOp("linklayerdevice", id))
   382  	}
   383  	return append(ops, insertLinkLayerDeviceDocOp(newDoc)), nil
   384  }
   385  
   386  func (m *Machine) parentDocIDFromDeviceDoc(doc *linkLayerDeviceDoc) (string, error) {
   387  	hostMachineID, parentName, err := parseLinkLayerDeviceParentNameAsGlobalKey(doc.ParentName)
   388  	if err != nil {
   389  		return "", errors.Trace(err)
   390  	}
   391  	if parentName == "" {
   392  		// doc.ParentName is not a global key, but on the same machine.
   393  		return linkLayerDeviceDocIDFromName(m.st, m.doc.Id, doc.ParentName), nil
   394  	}
   395  	// doc.ParentName is a global key, on a different host machine.
   396  	return m.st.docID(linkLayerDeviceGlobalKey(hostMachineID, parentName)), nil
   397  }
   398  
   399  func (m *Machine) updateLinkLayerDeviceOps(existingDoc, newDoc *linkLayerDeviceDoc) (ops []txn.Op, err error) {
   400  	// None of the ops in this function are assert-only,
   401  	// so callers can know if there are any changes by just checking len(ops).
   402  	var newParentDocID string
   403  	if newDoc.ParentName != "" {
   404  		newParentDocID, err = m.parentDocIDFromDeviceDoc(newDoc)
   405  		if err != nil {
   406  			return nil, errors.Trace(err)
   407  		}
   408  	}
   409  	var existingParentDocID string
   410  	if existingDoc.ParentName != "" {
   411  		existingParentDocID, err = m.parentDocIDFromDeviceDoc(existingDoc)
   412  		if err != nil {
   413  			return nil, errors.Trace(err)
   414  		}
   415  	}
   416  
   417  	if newParentDocID != "" && existingParentDocID != "" && newParentDocID != existingParentDocID {
   418  		ops = append(ops,
   419  			assertLinkLayerDeviceExistsOp(newParentDocID),
   420  			assertLinkLayerDeviceExistsOp(existingParentDocID),
   421  		)
   422  	} else if newParentDocID != "" && existingParentDocID == "" {
   423  		ops = append(ops, assertLinkLayerDeviceExistsOp(newParentDocID))
   424  	} else if newParentDocID == "" && existingParentDocID != "" {
   425  		ops = append(ops, assertLinkLayerDeviceExistsOp(existingParentDocID))
   426  	}
   427  	updateDeviceOp, deviceHasChanges := updateLinkLayerDeviceDocOp(existingDoc, newDoc)
   428  	if deviceHasChanges {
   429  		// we only include the op if it will actually change something
   430  		ops = append(ops, updateDeviceOp)
   431  	}
   432  
   433  	if newDoc.ProviderID != "" {
   434  		if existingDoc.ProviderID != "" && existingDoc.ProviderID != newDoc.ProviderID {
   435  			return nil, errors.Errorf("cannot change ProviderID of link layer device %q", existingDoc.Name)
   436  		}
   437  		if existingDoc.ProviderID != newDoc.ProviderID {
   438  			// Need to insert the new provider id in providerIDsC
   439  			id := corenetwork.Id(newDoc.ProviderID)
   440  			ops = append(ops, m.st.networkEntityGlobalKeyOp("linklayerdevice", id))
   441  		}
   442  	}
   443  	return ops, nil
   444  }
   445  
   446  // LinkLayerDeviceAddress contains an IP address assigned to a link-layer
   447  // device.
   448  type LinkLayerDeviceAddress struct {
   449  	// DeviceName is the name of the link-layer device that has this address.
   450  	DeviceName string
   451  
   452  	// ConfigMethod is the method used to configure this address.
   453  	ConfigMethod corenetwork.AddressConfigType
   454  
   455  	// ProviderID is the provider-specific ID of the address. Empty when not
   456  	// supported. Cannot be changed once set to non-empty.
   457  	ProviderID corenetwork.Id
   458  
   459  	// ProviderNetworkID is the provider-specific network ID of the address.
   460  	// It can be left empty if not supported or known.
   461  	ProviderNetworkID corenetwork.Id
   462  
   463  	// ProviderSubnetID is the provider-specific subnet ID to which the
   464  	// device is attached.
   465  	ProviderSubnetID corenetwork.Id
   466  
   467  	// CIDRAddress is the IP address assigned to the device, in CIDR format
   468  	// (e.g. 10.20.30.5/24 or fc00:1234::/64).
   469  	CIDRAddress string
   470  
   471  	// DNSServers contains a list of DNS nameservers to use, which can be empty.
   472  	DNSServers []string
   473  
   474  	// DNSSearchDomains contains a list of DNS domain names to qualify
   475  	// hostnames, and can be empty.
   476  	DNSSearchDomains []string
   477  
   478  	// GatewayAddress is the address of the gateway to use, which can be empty.
   479  	GatewayAddress string
   480  
   481  	// IsDefaultGateway is set to true if this address on this device is the
   482  	// default gw on a machine.
   483  	IsDefaultGateway bool
   484  
   485  	// Origin represents the authoritative source of the address.
   486  	// it is set using precedence, with "provider" overriding "machine".
   487  	// It is used to determine whether the address is no longer recognised
   488  	// and is safe to remove.
   489  	Origin corenetwork.Origin
   490  
   491  	// IsSecondary if true, indicates that this address is
   492  	// not the primary address associated with the NIC.
   493  	IsSecondary bool
   494  }
   495  
   496  // TODO (manadart 2020-07-21): This is silly. We already received the args
   497  // as an address/subnet pair and validated them when transforming them to
   498  // the CIDRAddress. Now we unpack and validate again.
   499  // When the old link-layer update logic is removed, just pass it all
   500  // through as-is.
   501  // This method can then be removed and previous callers
   502  // then need not include an error return.
   503  func (a *LinkLayerDeviceAddress) addressAndSubnet() (string, string, error) {
   504  	ip, ipNet, err := net.ParseCIDR(a.CIDRAddress)
   505  	if err != nil {
   506  		return "", "", errors.Trace(err)
   507  	}
   508  	return ip.String(), ipNet.String(), nil
   509  }
   510  
   511  // SetDevicesAddresses sets the addresses of all devices in devicesAddresses,
   512  // adding new or updating existing assignments as needed, in a single
   513  // transaction. ProviderID field can be empty if not supported by the provider,
   514  // but when set must be unique within the model. Errors are returned in the
   515  // following cases:
   516  //   - Machine is no longer alive or is missing;
   517  //   - Subnet inferred from any CIDRAddress field in args is known but no longer
   518  //     alive (no error reported if the CIDRAddress does not match a known subnet);
   519  //   - Model no longer alive;
   520  //   - errors.NotValidError, when any of the fields in args contain invalid values;
   521  //   - errors.NotFoundError, when any DeviceName in args refers to unknown device;
   522  //   - ErrProviderIDNotUnique, when one or more specified ProviderIDs are not unique.
   523  //
   524  // Deprecated: (manadart 2021-05-04) This method is only used by tests and is in
   525  // the process of removal. Do not add new usages of it.
   526  func (m *Machine) SetDevicesAddresses(devicesAddresses ...LinkLayerDeviceAddress) (err error) {
   527  	defer errors.DeferredAnnotatef(&err, "cannot set link-layer device addresses of machine %q", m.doc.Id)
   528  	if len(devicesAddresses) == 0 {
   529  		logger.Debugf("no device addresses to set")
   530  		return nil
   531  	}
   532  
   533  	buildTxn := func(attempt int) ([]txn.Op, error) {
   534  		newDocs, err := m.prepareToSetDevicesAddresses(devicesAddresses)
   535  		if err != nil {
   536  			return nil, errors.Trace(err)
   537  		}
   538  
   539  		if m.doc.Life != Alive {
   540  			return nil, errors.Errorf("machine %q not alive", m.doc.Id)
   541  		}
   542  
   543  		setAddressesOps, err := m.setDevicesAddressesFromDocsOps(newDocs)
   544  		if err != nil {
   545  			return nil, errors.Trace(err)
   546  		}
   547  		if len(setAddressesOps) == 0 {
   548  			logger.Debugf("no changes to DevicesAddresses for machine %q", m.Id())
   549  			return nil, jujutxn.ErrNoOperations
   550  		}
   551  		return append([]txn.Op{m.assertAliveOp()}, setAddressesOps...), nil
   552  	}
   553  	if err := m.st.db().Run(buildTxn); err != nil {
   554  		return errors.Trace(err)
   555  	}
   556  	return nil
   557  }
   558  
   559  func (m *Machine) prepareToSetDevicesAddresses(devicesAddresses []LinkLayerDeviceAddress) ([]ipAddressDoc, error) {
   560  	var pendingDocs []ipAddressDoc
   561  	for _, args := range devicesAddresses {
   562  		newDoc, err := m.prepareOneSetDevicesAddresses(&args)
   563  		if err != nil {
   564  			return nil, errors.Trace(err)
   565  		}
   566  		pendingDocs = append(pendingDocs, *newDoc)
   567  	}
   568  	return pendingDocs, nil
   569  }
   570  
   571  func (m *Machine) prepareOneSetDevicesAddresses(args *LinkLayerDeviceAddress) (_ *ipAddressDoc, err error) {
   572  	defer errors.DeferredAnnotatef(&err, "invalid address %q", args.CIDRAddress)
   573  
   574  	if err := m.validateSetDevicesAddressesArgs(args); err != nil {
   575  		return nil, errors.Trace(err)
   576  	}
   577  	return m.newIPAddressDocFromArgs(args)
   578  }
   579  
   580  func (m *Machine) validateSetDevicesAddressesArgs(args *LinkLayerDeviceAddress) error {
   581  	if args.CIDRAddress == "" {
   582  		return errors.NotValidf("empty CIDRAddress")
   583  	}
   584  	if _, _, err := net.ParseCIDR(args.CIDRAddress); err != nil {
   585  		return errors.NewNotValid(err, "CIDRAddress")
   586  	}
   587  
   588  	if args.DeviceName == "" {
   589  		return errors.NotValidf("empty DeviceName")
   590  	}
   591  	if !corenetwork.IsValidLinkLayerDeviceName(args.DeviceName) {
   592  		logger.Warningf(
   593  			"address %q on machine %q has invalid device name %q (using anyway)",
   594  			args.CIDRAddress, m.Id(), args.DeviceName,
   595  		)
   596  	}
   597  	if err := m.verifyDeviceAlreadyExists(args.DeviceName); err != nil {
   598  		return errors.Trace(err)
   599  	}
   600  
   601  	if args.GatewayAddress != "" {
   602  		if ip := net.ParseIP(args.GatewayAddress); ip == nil {
   603  			return errors.NotValidf("GatewayAddress %q", args.GatewayAddress)
   604  		}
   605  	}
   606  
   607  	return nil
   608  }
   609  
   610  func (m *Machine) verifyDeviceAlreadyExists(deviceName string) error {
   611  	if _, err := m.LinkLayerDevice(deviceName); errors.IsNotFound(err) {
   612  		return errors.NotFoundf("DeviceName %q on machine %q", deviceName, m.Id())
   613  	} else if err != nil {
   614  		return errors.Trace(err)
   615  	}
   616  	return nil
   617  }
   618  
   619  func (m *Machine) newIPAddressDocFromArgs(args *LinkLayerDeviceAddress) (*ipAddressDoc, error) {
   620  	ip, ipNet, err := net.ParseCIDR(args.CIDRAddress)
   621  	if err != nil {
   622  		// We already validated CIDRAddress earlier, so this cannot happen in
   623  		// practice, but we handle it anyway.
   624  		return nil, errors.Trace(err)
   625  	}
   626  	addressValue := ip.String()
   627  	subnetCIDR := ipNet.String()
   628  	subnet, err := m.st.SubnetByCIDR(subnetCIDR)
   629  	if errors.IsNotFound(err) {
   630  		logger.Debugf(
   631  			"address %q on machine %q uses unknown or machine-local subnet %q",
   632  			addressValue, m.Id(), subnetCIDR,
   633  		)
   634  	} else if err != nil {
   635  		return nil, errors.Trace(err)
   636  	} else if err := m.verifySubnetAlive(subnet); err != nil {
   637  		return nil, errors.Trace(err)
   638  	}
   639  
   640  	globalKey := ipAddressGlobalKey(m.doc.Id, args.DeviceName, addressValue)
   641  	ipAddressDocID := m.st.docID(globalKey)
   642  
   643  	modelUUID := m.st.ModelUUID()
   644  
   645  	newDoc := &ipAddressDoc{
   646  		DocID:             ipAddressDocID,
   647  		ModelUUID:         modelUUID,
   648  		ProviderID:        args.ProviderID.String(),
   649  		ProviderNetworkID: args.ProviderNetworkID.String(),
   650  		ProviderSubnetID:  args.ProviderSubnetID.String(),
   651  		DeviceName:        args.DeviceName,
   652  		MachineID:         m.doc.Id,
   653  		SubnetCIDR:        subnetCIDR,
   654  		ConfigMethod:      args.ConfigMethod,
   655  		Value:             addressValue,
   656  		DNSServers:        args.DNSServers,
   657  		DNSSearchDomains:  args.DNSSearchDomains,
   658  		GatewayAddress:    args.GatewayAddress,
   659  		IsDefaultGateway:  args.IsDefaultGateway,
   660  		Origin:            args.Origin,
   661  	}
   662  	return newDoc, nil
   663  }
   664  
   665  func (m *Machine) verifySubnetAlive(subnet *Subnet) error {
   666  	if subnet.Life() != Alive {
   667  		return errors.Errorf("subnet %q is not alive", subnet.CIDR())
   668  	}
   669  	return nil
   670  }
   671  
   672  func (m *Machine) setDevicesAddressesFromDocsOps(newDocs []ipAddressDoc) ([]txn.Op, error) {
   673  	addresses, closer := m.st.db().GetCollection(ipAddressesC)
   674  	defer closer()
   675  
   676  	providerIDAddrs := make(map[string]string)
   677  
   678  	var ops []txn.Op
   679  	for _, newDoc := range newDocs {
   680  		var thisDeviceOps []txn.Op
   681  		hasChanges := false
   682  		deviceDocID := linkLayerDeviceDocIDFromName(m.st, m.doc.Id, newDoc.DeviceName)
   683  		thisDeviceOps = append(thisDeviceOps, assertLinkLayerDeviceExistsOp(deviceDocID))
   684  
   685  		var existingDoc ipAddressDoc
   686  		switch err := addresses.FindId(newDoc.DocID).One(&existingDoc); err {
   687  		case mgo.ErrNotFound:
   688  			// Address does not exist yet - insert it.
   689  			hasChanges = true
   690  			thisDeviceOps = append(thisDeviceOps, insertIPAddressDocOp(&newDoc))
   691  
   692  			pIDOps, err := m.maybeAddAddressProviderIDOps(providerIDAddrs, newDoc, "")
   693  			if err != nil {
   694  				return nil, errors.Trace(err)
   695  			}
   696  			thisDeviceOps = append(thisDeviceOps, pIDOps...)
   697  
   698  		case nil:
   699  			// Address already exists - update what's possible.
   700  			var ipOp txn.Op
   701  			ipOp, hasChanges = updateIPAddressDocOp(&existingDoc, &newDoc)
   702  			thisDeviceOps = append(thisDeviceOps, ipOp)
   703  
   704  			pIDOps, err := m.maybeAddAddressProviderIDOps(providerIDAddrs, newDoc, existingDoc.ProviderID)
   705  			if err != nil {
   706  				return nil, errors.Trace(err)
   707  			}
   708  			if len(pIDOps) > 0 {
   709  				hasChanges = true
   710  				thisDeviceOps = append(thisDeviceOps, pIDOps...)
   711  			}
   712  
   713  		default:
   714  			return nil, errors.Trace(err)
   715  		}
   716  
   717  		thisDeviceOps, err := m.maybeAssertSubnetAliveOps(&newDoc, thisDeviceOps)
   718  		if err != nil {
   719  			return nil, errors.Trace(err)
   720  		}
   721  		if hasChanges {
   722  			ops = append(ops, thisDeviceOps...)
   723  		}
   724  	}
   725  	return ops, nil
   726  }
   727  
   728  // maybeAddAddressProviderIDOps ensures that the address provider ID is valid
   729  // and that we only accrue a transaction operation to add the ID if we have
   730  // not already.
   731  func (m *Machine) maybeAddAddressProviderIDOps(
   732  	providerIDAddrs map[string]string, doc ipAddressDoc, oldProviderID string,
   733  ) ([]txn.Op, error) {
   734  	if doc.ProviderID == "" {
   735  		return nil, nil
   736  	}
   737  	if doc.ProviderID == oldProviderID {
   738  		return nil, nil
   739  	}
   740  	if oldProviderID != "" {
   741  		return nil, errors.Errorf("cannot change provider ID of link address %q", doc.Value)
   742  	}
   743  
   744  	// If this provider ID has been added for the same address,
   745  	// it is valid, but do not attempt to add the ID again.
   746  	// If we have different addresses with the same provider ID,
   747  	// return an error.
   748  	addr, ok := providerIDAddrs[doc.ProviderID]
   749  	if ok {
   750  		if addr == doc.Value {
   751  			return nil, nil
   752  		}
   753  		return nil, errors.Annotatef(
   754  			newProviderIDNotUniqueError(corenetwork.Id(doc.ProviderID)), "multiple addresses %q, %q", addr, doc.Value)
   755  	}
   756  
   757  	providerIDAddrs[doc.ProviderID] = doc.Value
   758  	return []txn.Op{m.st.networkEntityGlobalKeyOp("address", corenetwork.Id(doc.ProviderID))}, nil
   759  }
   760  
   761  func (m *Machine) maybeAssertSubnetAliveOps(newDoc *ipAddressDoc, opsSoFar []txn.Op) ([]txn.Op, error) {
   762  	subnet, err := m.st.SubnetByCIDR(newDoc.SubnetCIDR)
   763  	if errors.IsNotFound(err) {
   764  		// Subnet is machine-local, no need to assert whether it's alive.
   765  		return opsSoFar, nil
   766  	} else if err != nil {
   767  		return nil, errors.Trace(err)
   768  	}
   769  	if err := m.verifySubnetAlive(subnet); err != nil {
   770  		return nil, errors.Trace(err)
   771  	}
   772  
   773  	// Subnet exists and is still alive, assert that is stays that way.
   774  	return append(opsSoFar, txn.Op{
   775  		C:      subnetsC,
   776  		Id:     m.st.docID(subnet.ID()),
   777  		Assert: isAliveDoc,
   778  	}), nil
   779  }
   780  
   781  // RemoveAllAddresses removes all assigned addresses to all devices of the
   782  // machine, in a single transaction. No error is returned when some or all of
   783  // the addresses were already removed.
   784  func (m *Machine) RemoveAllAddresses() error {
   785  	ops, err := m.removeAllAddressesOps()
   786  	if err != nil {
   787  		return errors.Trace(err)
   788  	}
   789  
   790  	return m.st.db().RunTransaction(ops)
   791  }
   792  
   793  func (m *Machine) removeAllAddressesOps() ([]txn.Op, error) {
   794  	findQuery := findAddressesQuery(m.doc.Id, "")
   795  	return m.st.removeMatchingIPAddressesDocOps(findQuery)
   796  }
   797  
   798  // AllDeviceAddresses returns all known addresses assigned to
   799  // link-layer devices on the machine.
   800  func (m *Machine) AllDeviceAddresses() ([]*Address, error) {
   801  	var allAddresses []*Address
   802  	callbackFunc := func(doc *ipAddressDoc) {
   803  		allAddresses = append(allAddresses, newIPAddress(m.st, *doc))
   804  	}
   805  
   806  	findQuery := findAddressesQuery(m.doc.Id, "")
   807  	if err := m.st.forEachIPAddressDoc(findQuery, callbackFunc); err != nil {
   808  		return nil, errors.Trace(err)
   809  	}
   810  	return allAddresses, nil
   811  }
   812  
   813  // AllSpaces returns the set of spaceIDs that this machine is
   814  // actively connected to.
   815  // TODO(jam): 2016-12-18 This should evolve to look at the
   816  // LinkLayerDevices directly, instead of using the Addresses
   817  // the devices are in to link back to spaces.
   818  func (m *Machine) AllSpaces() (set.Strings, error) {
   819  	subnets, err := m.st.AllSubnets()
   820  	if err != nil {
   821  		return nil, errors.Annotate(err, "retrieving subnets")
   822  	}
   823  
   824  	spaces := set.NewStrings()
   825  	callback := func(doc *ipAddressDoc) {
   826  		// Don't bother with these. They are not in a space.
   827  		if doc.ConfigMethod == corenetwork.ConfigLoopback || doc.SubnetCIDR == "" {
   828  			return
   829  		}
   830  
   831  		for _, sub := range subnets {
   832  			if sub.CIDR() == doc.SubnetCIDR {
   833  				spaces.Add(sub.spaceID)
   834  				break
   835  			}
   836  		}
   837  	}
   838  	if err := m.st.forEachIPAddressDoc(findAddressesQuery(m.doc.Id, ""), callback); err != nil {
   839  		return nil, errors.Trace(err)
   840  	}
   841  
   842  	return spaces, nil
   843  }