github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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  	"math/rand"
     9  	"net"
    10  
    11  	"github.com/juju/errors"
    12  	"github.com/juju/utils/set"
    13  	"gopkg.in/mgo.v2"
    14  	"gopkg.in/mgo.v2/bson"
    15  	"gopkg.in/mgo.v2/txn"
    16  
    17  	"github.com/juju/juju/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  	linkLayerDevices, closer := m.st.getCollection(linkLayerDevicesC)
    25  	defer closer()
    26  
    27  	linkLayerDeviceDocID := m.linkLayerDeviceDocIDFromName(name)
    28  	deviceAsString := m.deviceAsStringFromName(name)
    29  
    30  	var doc linkLayerDeviceDoc
    31  	err := linkLayerDevices.FindId(linkLayerDeviceDocID).One(&doc)
    32  	if err == mgo.ErrNotFound {
    33  		return nil, errors.NotFoundf("%s", deviceAsString)
    34  	} else if err != nil {
    35  		return nil, errors.Annotatef(err, "cannot get %s", deviceAsString)
    36  	}
    37  	return newLinkLayerDevice(m.st, doc), nil
    38  }
    39  
    40  func (m *Machine) linkLayerDeviceDocIDFromName(deviceName string) string {
    41  	return m.st.docID(m.linkLayerDeviceGlobalKeyFromName(deviceName))
    42  }
    43  
    44  func (m *Machine) linkLayerDeviceGlobalKeyFromName(deviceName string) string {
    45  	return linkLayerDeviceGlobalKey(m.doc.Id, deviceName)
    46  }
    47  
    48  func (m *Machine) deviceAsStringFromName(deviceName string) string {
    49  	return fmt.Sprintf("device %q on machine %q", deviceName, m.doc.Id)
    50  }
    51  
    52  // AllLinkLayerDevices returns all exiting link-layer devices of the machine.
    53  func (m *Machine) AllLinkLayerDevices() ([]*LinkLayerDevice, error) {
    54  	var allDevices []*LinkLayerDevice
    55  	callbackFunc := func(resultDoc *linkLayerDeviceDoc) {
    56  		allDevices = append(allDevices, newLinkLayerDevice(m.st, *resultDoc))
    57  	}
    58  
    59  	if err := m.forEachLinkLayerDeviceDoc(nil, callbackFunc); err != nil {
    60  		return nil, errors.Trace(err)
    61  	}
    62  	return allDevices, nil
    63  }
    64  
    65  func (m *Machine) forEachLinkLayerDeviceDoc(docFieldsToSelect bson.D, callbackFunc func(resultDoc *linkLayerDeviceDoc)) error {
    66  	linkLayerDevices, closer := m.st.getCollection(linkLayerDevicesC)
    67  	defer closer()
    68  
    69  	query := linkLayerDevices.Find(bson.D{{"machine-id", m.doc.Id}})
    70  	if docFieldsToSelect != nil {
    71  		query = query.Select(docFieldsToSelect)
    72  	}
    73  	iter := query.Iter()
    74  
    75  	var resultDoc linkLayerDeviceDoc
    76  	for iter.Next(&resultDoc) {
    77  		callbackFunc(&resultDoc)
    78  	}
    79  
    80  	return errors.Trace(iter.Close())
    81  }
    82  
    83  // RemoveAllLinkLayerDevices removes all existing link-layer devices of the
    84  // machine in a single transaction. No error is returned when some or all of the
    85  // devices were already removed.
    86  func (m *Machine) RemoveAllLinkLayerDevices() error {
    87  	ops, err := m.removeAllLinkLayerDevicesOps()
    88  	if err != nil {
    89  		return errors.Trace(err)
    90  	}
    91  
    92  	return m.st.runTransaction(ops)
    93  }
    94  
    95  func (m *Machine) removeAllLinkLayerDevicesOps() ([]txn.Op, error) {
    96  	var ops []txn.Op
    97  	callbackFunc := func(resultDoc *linkLayerDeviceDoc) {
    98  		removeOps := removeLinkLayerDeviceUnconditionallyOps(resultDoc.DocID)
    99  		ops = append(ops, removeOps...)
   100  	}
   101  
   102  	selectDocIDOnly := bson.D{{"_id", 1}}
   103  	if err := m.forEachLinkLayerDeviceDoc(selectDocIDOnly, callbackFunc); err != nil {
   104  		return nil, errors.Trace(err)
   105  	}
   106  
   107  	return ops, nil
   108  }
   109  
   110  // LinkLayerDeviceArgs contains the arguments accepted by Machine.SetLinkLayerDevices().
   111  type LinkLayerDeviceArgs struct {
   112  	// Name is the name of the device as it appears on the machine.
   113  	Name string
   114  
   115  	// MTU is the maximum transmission unit the device can handle.
   116  	MTU uint
   117  
   118  	// ProviderID is a provider-specific ID of the device. Empty when not
   119  	// supported by the provider. Cannot be cleared once set.
   120  	ProviderID network.Id
   121  
   122  	// Type is the type of the underlying link-layer device.
   123  	Type LinkLayerDeviceType
   124  
   125  	// MACAddress is the media access control address for the device.
   126  	MACAddress string
   127  
   128  	// IsAutoStart is true if the device should be activated on boot.
   129  	IsAutoStart bool
   130  
   131  	// IsUp is true when the device is up (enabled).
   132  	IsUp bool
   133  
   134  	// ParentName is the name of the parent device, which may be empty. If set,
   135  	// it needs to be an existing device on the same machine, unless the current
   136  	// device is inside a container, in which case ParentName can be a global
   137  	// key of a BridgeDevice on the host machine of the container. Traffic
   138  	// originating from a device egresses from its parent device.
   139  	ParentName string
   140  }
   141  
   142  // SetLinkLayerDevices sets link-layer devices on the machine, adding or
   143  // updating existing devices as needed, in a single transaction. ProviderID
   144  // field can be empty if not supported by the provider, but when set must be
   145  // unique within the model, and cannot be unset once set. Errors are returned in
   146  // the following cases:
   147  // - Machine is no longer alive or is missing;
   148  // - Model no longer alive;
   149  // - errors.NotValidError, when any of the fields in args contain invalid values;
   150  // - ErrProviderIDNotUnique, when one or more specified ProviderIDs are not unique;
   151  // Setting new parent devices must be done in a separate call than setting their
   152  // children on the same machine.
   153  func (m *Machine) SetLinkLayerDevices(devicesArgs ...LinkLayerDeviceArgs) (err error) {
   154  	defer errors.DeferredAnnotatef(&err, "cannot set link-layer devices to machine %q", m.doc.Id)
   155  
   156  	if len(devicesArgs) == 0 {
   157  		logger.Warningf("no device addresses to set")
   158  		return nil
   159  	}
   160  
   161  	buildTxn := func(attempt int) ([]txn.Op, error) {
   162  		existingProviderIDs, err := m.st.allProviderIDsForModelLinkLayerDevices()
   163  		if err != nil {
   164  			return nil, errors.Trace(err)
   165  		}
   166  		newDocs, err := m.prepareToSetLinkLayerDevices(devicesArgs, existingProviderIDs)
   167  		if err != nil {
   168  			return nil, errors.Trace(err)
   169  		}
   170  
   171  		if attempt > 0 {
   172  			if err := checkModelActive(m.st); err != nil {
   173  				return nil, errors.Trace(err)
   174  			}
   175  			if err := m.isStillAlive(); err != nil {
   176  				return nil, errors.Trace(err)
   177  			}
   178  		}
   179  
   180  		ops := []txn.Op{
   181  			assertModelActiveOp(m.st.ModelUUID()),
   182  			m.assertAliveOp(),
   183  		}
   184  
   185  		setDevicesOps, err := m.setDevicesFromDocsOps(newDocs)
   186  		if err != nil {
   187  			return nil, errors.Trace(err)
   188  		}
   189  		return append(ops, setDevicesOps...), nil
   190  	}
   191  	if err := m.st.run(buildTxn); err != nil {
   192  		return errors.Trace(err)
   193  	}
   194  	return nil
   195  }
   196  
   197  func (st *State) allProviderIDsForModelLinkLayerDevices() (set.Strings, error) {
   198  	return st.allProviderIDsForModelCollection(linkLayerDevicesC, "link-layer devices")
   199  }
   200  
   201  func (st *State) allProviderIDsForModelCollection(collectionName, entityLabelPlural string) (_ set.Strings, err error) {
   202  	defer errors.DeferredAnnotatef(&err, "cannot get ProviderIDs for all %s", entityLabelPlural)
   203  
   204  	entities, closer := st.getCollection(collectionName)
   205  	defer closer()
   206  
   207  	allProviderIDs := set.NewStrings()
   208  	var doc struct {
   209  		ProviderID string `bson:"providerid"`
   210  	}
   211  
   212  	pattern := fmt.Sprintf("^%s:.+$", st.ModelUUID())
   213  	modelProviderIDs := bson.D{{"providerid", bson.D{{"$regex", pattern}}}}
   214  	onlyProviderIDField := bson.D{{"providerid", 1}}
   215  
   216  	iter := entities.Find(modelProviderIDs).Select(onlyProviderIDField).Iter()
   217  	for iter.Next(&doc) {
   218  		localProviderID := st.localID(doc.ProviderID)
   219  		allProviderIDs.Add(localProviderID)
   220  	}
   221  	if err := iter.Close(); err != nil {
   222  		return nil, errors.Trace(err)
   223  	}
   224  	return allProviderIDs, nil
   225  }
   226  
   227  func (m *Machine) prepareToSetLinkLayerDevices(devicesArgs []LinkLayerDeviceArgs, existingProviderIDs set.Strings) ([]linkLayerDeviceDoc, error) {
   228  	var pendingDocs []linkLayerDeviceDoc
   229  	pendingNames := set.NewStrings()
   230  	allProviderIDs := set.NewStrings(existingProviderIDs.Values()...)
   231  
   232  	for _, args := range devicesArgs {
   233  		newDoc, err := m.prepareOneSetLinkLayerDeviceArgs(&args, pendingNames, allProviderIDs)
   234  		if err != nil {
   235  			return nil, errors.Trace(err)
   236  		}
   237  		pendingNames.Add(args.Name)
   238  		pendingDocs = append(pendingDocs, *newDoc)
   239  		if args.ProviderID != "" {
   240  			allProviderIDs.Add(string(args.ProviderID))
   241  		}
   242  	}
   243  	return pendingDocs, nil
   244  }
   245  
   246  func (m *Machine) prepareOneSetLinkLayerDeviceArgs(args *LinkLayerDeviceArgs, pendingNames, allProviderIDs set.Strings) (_ *linkLayerDeviceDoc, err error) {
   247  	defer errors.DeferredAnnotatef(&err, "invalid device %q", args.Name)
   248  
   249  	if err := m.validateSetLinkLayerDeviceArgs(args); err != nil {
   250  		return nil, errors.Trace(err)
   251  	}
   252  
   253  	if pendingNames.Contains(args.Name) {
   254  		return nil, errors.NewNotValid(nil, "Name specified more than once")
   255  	}
   256  
   257  	if allProviderIDs.Contains(string(args.ProviderID)) {
   258  		return nil, NewProviderIDNotUniqueError(args.ProviderID)
   259  	}
   260  
   261  	return m.newLinkLayerDeviceDocFromArgs(args), nil
   262  }
   263  
   264  func (m *Machine) validateSetLinkLayerDeviceArgs(args *LinkLayerDeviceArgs) error {
   265  	if args.Name == "" {
   266  		return errors.NotValidf("empty Name")
   267  	}
   268  	if !IsValidLinkLayerDeviceName(args.Name) {
   269  		logger.Warningf(
   270  			"link-layer device %q on machine %q has invalid name (using anyway)",
   271  			args.Name, m.Id(),
   272  		)
   273  	}
   274  
   275  	if args.ParentName != "" {
   276  		if err := m.validateLinkLayerDeviceParent(args); err != nil {
   277  			return errors.Trace(err)
   278  		}
   279  	}
   280  
   281  	if !IsValidLinkLayerDeviceType(string(args.Type)) {
   282  		return errors.NotValidf("Type %q", args.Type)
   283  	}
   284  
   285  	if args.MACAddress != "" {
   286  		if _, err := net.ParseMAC(args.MACAddress); err != nil {
   287  			return errors.NotValidf("MACAddress %q", args.MACAddress)
   288  		}
   289  	}
   290  	return nil
   291  }
   292  
   293  func (m *Machine) validateLinkLayerDeviceParent(args *LinkLayerDeviceArgs) error {
   294  	hostMachineID, parentDeviceName, err := parseLinkLayerDeviceParentNameAsGlobalKey(args.ParentName)
   295  	if err != nil {
   296  		return errors.Trace(err)
   297  	} else if hostMachineID == "" {
   298  		// Not a global key, so validate as usual.
   299  		if err := m.validateParentDeviceNameWhenNotAGlobalKey(args); errors.IsNotFound(err) {
   300  			return errors.NewNotValid(err, "ParentName not valid")
   301  		} else if err != nil {
   302  			return errors.Trace(err)
   303  		}
   304  		return nil
   305  	}
   306  	ourParentMachineID, hasParent := m.ParentId()
   307  	if !hasParent {
   308  		// Using global key for ParentName not allowed for non-container machine
   309  		// devices.
   310  		return errors.NotValidf("ParentName %q for non-container machine %q", args.ParentName, m.Id())
   311  	}
   312  	if hostMachineID != ourParentMachineID {
   313  		// ParentName as global key only allowed when the key's machine ID is
   314  		// the container's host machine.
   315  		return errors.NotValidf("ParentName %q on non-host machine %q", args.ParentName, hostMachineID)
   316  	}
   317  
   318  	err = m.verifyHostMachineParentDeviceExistsAndIsABridgeDevice(hostMachineID, parentDeviceName)
   319  	return errors.Trace(err)
   320  }
   321  
   322  func parseLinkLayerDeviceParentNameAsGlobalKey(parentName string) (hostMachineID, parentDeviceName string, err error) {
   323  	hostMachineID, parentDeviceName, canBeGlobalKey := parseLinkLayerDeviceGlobalKey(parentName)
   324  	if !canBeGlobalKey {
   325  		return "", "", nil
   326  	} else if hostMachineID == "" {
   327  		return "", "", errors.NotValidf("ParentName %q format", parentName)
   328  	}
   329  	return hostMachineID, parentDeviceName, nil
   330  }
   331  
   332  func (m *Machine) verifyHostMachineParentDeviceExistsAndIsABridgeDevice(hostMachineID, parentDeviceName string) error {
   333  	hostMachine, err := m.st.Machine(hostMachineID)
   334  	if errors.IsNotFound(err) || err == nil && hostMachine.Life() != Alive {
   335  		return errors.Errorf("host machine %q of parent device %q not found or not alive", hostMachineID, parentDeviceName)
   336  	} else if err != nil {
   337  		return errors.Trace(err)
   338  	}
   339  
   340  	parentDevice, err := hostMachine.LinkLayerDevice(parentDeviceName)
   341  	if errors.IsNotFound(err) {
   342  		return errors.NotFoundf("parent device %q on host machine %q", parentDeviceName, hostMachineID)
   343  	} else if err != nil {
   344  		return errors.Trace(err)
   345  	}
   346  
   347  	if parentDevice.Type() != BridgeDevice {
   348  		errorMessage := fmt.Sprintf(
   349  			"parent device %q on host machine %q must be of type %q, not type %q",
   350  			parentDeviceName, hostMachineID, BridgeDevice, parentDevice.Type(),
   351  		)
   352  		return errors.NewNotValid(nil, errorMessage)
   353  	}
   354  	return nil
   355  }
   356  
   357  func (m *Machine) validateParentDeviceNameWhenNotAGlobalKey(args *LinkLayerDeviceArgs) error {
   358  	if !IsValidLinkLayerDeviceName(args.ParentName) {
   359  		logger.Warningf(
   360  			"parent link-layer device %q on machine %q has invalid name (using anyway)",
   361  			args.ParentName, m.Id(),
   362  		)
   363  	}
   364  	if args.Name == args.ParentName {
   365  		return errors.NewNotValid(nil, "Name and ParentName must be different")
   366  	}
   367  	if err := m.verifyParentDeviceExists(args.ParentName); err != nil {
   368  		return errors.Trace(err)
   369  	}
   370  	return nil
   371  }
   372  
   373  func (m *Machine) verifyParentDeviceExists(parentName string) error {
   374  	if _, err := m.LinkLayerDevice(parentName); err != nil {
   375  		return errors.Trace(err)
   376  	}
   377  	return nil
   378  }
   379  
   380  func (m *Machine) newLinkLayerDeviceDocFromArgs(args *LinkLayerDeviceArgs) *linkLayerDeviceDoc {
   381  	linkLayerDeviceDocID := m.linkLayerDeviceDocIDFromName(args.Name)
   382  
   383  	providerID := string(args.ProviderID)
   384  	if providerID != "" {
   385  		providerID = m.st.docID(providerID)
   386  	}
   387  
   388  	modelUUID := m.st.ModelUUID()
   389  
   390  	return &linkLayerDeviceDoc{
   391  		DocID:       linkLayerDeviceDocID,
   392  		Name:        args.Name,
   393  		ModelUUID:   modelUUID,
   394  		MTU:         args.MTU,
   395  		ProviderID:  providerID,
   396  		MachineID:   m.doc.Id,
   397  		Type:        args.Type,
   398  		MACAddress:  args.MACAddress,
   399  		IsAutoStart: args.IsAutoStart,
   400  		IsUp:        args.IsUp,
   401  		ParentName:  args.ParentName,
   402  	}
   403  }
   404  
   405  func (m *Machine) isStillAlive() error {
   406  	if machineAlive, err := isAlive(m.st, machinesC, m.doc.Id); err != nil {
   407  		return errors.Trace(err)
   408  	} else if !machineAlive {
   409  		return errors.Errorf("machine not found or not alive")
   410  	}
   411  	return nil
   412  }
   413  
   414  func (m *Machine) assertAliveOp() txn.Op {
   415  	return txn.Op{
   416  		C:      machinesC,
   417  		Id:     m.doc.Id,
   418  		Assert: isAliveDoc,
   419  	}
   420  }
   421  
   422  func (m *Machine) setDevicesFromDocsOps(newDocs []linkLayerDeviceDoc) ([]txn.Op, error) {
   423  	devices, closer := m.st.getCollection(linkLayerDevicesC)
   424  	defer closer()
   425  
   426  	var ops []txn.Op
   427  	for _, newDoc := range newDocs {
   428  		var existingDoc linkLayerDeviceDoc
   429  		if err := devices.FindId(newDoc.DocID).One(&existingDoc); err == mgo.ErrNotFound {
   430  			// Device does not exist yet - insert it.
   431  			insertOps, err := m.insertLinkLayerDeviceOps(&newDoc)
   432  			if err != nil {
   433  				return nil, errors.Trace(err)
   434  			}
   435  			ops = append(ops, insertOps...)
   436  		} else if err == nil {
   437  			// Device already exists - update what's possible.
   438  			updateOps, err := m.updateLinkLayerDeviceOps(&existingDoc, &newDoc)
   439  			if err != nil {
   440  				return nil, errors.Trace(err)
   441  			}
   442  			ops = append(ops, updateOps...)
   443  		} else {
   444  			return nil, errors.Trace(err)
   445  		}
   446  	}
   447  	return ops, nil
   448  }
   449  
   450  func (m *Machine) insertLinkLayerDeviceOps(newDoc *linkLayerDeviceDoc) ([]txn.Op, error) {
   451  	modelUUID, linkLayerDeviceDocID := newDoc.ModelUUID, newDoc.DocID
   452  
   453  	var ops []txn.Op
   454  	if newDoc.ParentName != "" {
   455  		newParentDocID, err := m.parentDocIDFromDeviceDoc(newDoc)
   456  		if err != nil {
   457  			return nil, errors.Trace(err)
   458  		}
   459  		if newParentDocID != "" {
   460  			ops = append(ops, assertLinkLayerDeviceExistsOp(newParentDocID))
   461  			ops = append(ops, incrementDeviceNumChildrenOp(newParentDocID))
   462  		}
   463  	}
   464  	return append(ops,
   465  		insertLinkLayerDeviceDocOp(newDoc),
   466  		insertLinkLayerDevicesRefsOp(modelUUID, linkLayerDeviceDocID),
   467  	), nil
   468  }
   469  
   470  func (m *Machine) parentDocIDFromDeviceDoc(doc *linkLayerDeviceDoc) (string, error) {
   471  	hostMachineID, parentName, err := parseLinkLayerDeviceParentNameAsGlobalKey(doc.ParentName)
   472  	if err != nil {
   473  		return "", errors.Trace(err)
   474  	}
   475  	if parentName == "" {
   476  		// doc.ParentName is not a global key, but on the same machine.
   477  		return m.linkLayerDeviceDocIDFromName(doc.ParentName), nil
   478  	}
   479  	// doc.ParentName is a global key, on a different host machine.
   480  	return m.st.docID(linkLayerDeviceGlobalKey(hostMachineID, parentName)), nil
   481  }
   482  
   483  func (m *Machine) updateLinkLayerDeviceOps(existingDoc, newDoc *linkLayerDeviceDoc) (ops []txn.Op, err error) {
   484  	var newParentDocID string
   485  	if newDoc.ParentName != "" {
   486  		newParentDocID, err = m.parentDocIDFromDeviceDoc(newDoc)
   487  		if err != nil {
   488  			return nil, errors.Trace(err)
   489  		}
   490  	}
   491  	var existingParentDocID string
   492  	if existingDoc.ParentName != "" {
   493  		existingParentDocID, err = m.parentDocIDFromDeviceDoc(existingDoc)
   494  		if err != nil {
   495  			return nil, errors.Trace(err)
   496  		}
   497  	}
   498  
   499  	if newParentDocID != "" && existingParentDocID != "" && newParentDocID != existingParentDocID {
   500  		ops = append(ops,
   501  			assertLinkLayerDeviceExistsOp(newParentDocID),
   502  			incrementDeviceNumChildrenOp(newParentDocID),
   503  			assertLinkLayerDeviceExistsOp(existingParentDocID),
   504  			decrementDeviceNumChildrenOp(existingParentDocID),
   505  		)
   506  	} else if newParentDocID != "" && existingParentDocID == "" {
   507  		ops = append(ops, assertLinkLayerDeviceExistsOp(newParentDocID))
   508  		ops = append(ops, incrementDeviceNumChildrenOp(newParentDocID))
   509  	} else if newParentDocID == "" && existingParentDocID != "" {
   510  		ops = append(ops, assertLinkLayerDeviceExistsOp(existingParentDocID))
   511  		ops = append(ops, decrementDeviceNumChildrenOp(existingParentDocID))
   512  	}
   513  	return append(ops, updateLinkLayerDeviceDocOp(existingDoc, newDoc)), nil
   514  }
   515  
   516  // LinkLayerDeviceAddress contains an IP address assigned to a link-layer
   517  // device.
   518  type LinkLayerDeviceAddress struct {
   519  	// DeviceName is the name of the link-layer device that has this address.
   520  	DeviceName string
   521  
   522  	// ConfigMethod is the method used to configure this address.
   523  	ConfigMethod AddressConfigMethod
   524  
   525  	// ProviderID is the provider-specific ID of the address. Empty when not
   526  	// supported. Cannot be changed once set to non-empty.
   527  	ProviderID network.Id
   528  
   529  	// CIDRAddress is the IP address assigned to the device, in CIDR format
   530  	// (e.g. 10.20.30.5/24 or fc00:1234::/64).
   531  	CIDRAddress string
   532  
   533  	// DNSServers contains a list of DNS nameservers to use, which can be empty.
   534  	DNSServers []string
   535  
   536  	// DNSSearchDomains contains a list of DNS domain names to qualify
   537  	// hostnames, and can be empty.
   538  	DNSSearchDomains []string
   539  
   540  	// GatewayAddress is the address of the gateway to use, which can be empty.
   541  	GatewayAddress string
   542  }
   543  
   544  // SetDevicesAddresses sets the addresses of all devices in devicesAddresses,
   545  // adding new or updating existing assignments as needed, in a single
   546  // transaction. ProviderID field can be empty if not supported by the provider,
   547  // but when set must be unique within the model. Errors are returned in the
   548  // following cases:
   549  // - Machine is no longer alive or is missing;
   550  // - Subnet inferred from any CIDRAddress field in args is known but no longer
   551  //   alive (no error reported if the CIDRAddress does not match a known subnet);
   552  // - Model no longer alive;
   553  // - errors.NotValidError, when any of the fields in args contain invalid values;
   554  // - errors.NotFoundError, when any DeviceName in args refers to unknown device;
   555  // - ErrProviderIDNotUnique, when one or more specified ProviderIDs are not unique.
   556  func (m *Machine) SetDevicesAddresses(devicesAddresses ...LinkLayerDeviceAddress) (err error) {
   557  	defer errors.DeferredAnnotatef(&err, "cannot set link-layer device addresses of machine %q", m.doc.Id)
   558  
   559  	if len(devicesAddresses) == 0 {
   560  		logger.Warningf("no device addresses to set")
   561  		return nil
   562  	}
   563  
   564  	buildTxn := func(attempt int) ([]txn.Op, error) {
   565  		existingProviderIDs, err := m.st.allProviderIDsForModelIPAddresses()
   566  		if err != nil {
   567  			return nil, errors.Trace(err)
   568  		}
   569  		newDocs, err := m.prepareToSetDevicesAddresses(devicesAddresses, existingProviderIDs)
   570  		if err != nil {
   571  			return nil, errors.Trace(err)
   572  		}
   573  
   574  		if attempt > 0 {
   575  			if err := checkModelActive(m.st); err != nil {
   576  				return nil, errors.Trace(err)
   577  			}
   578  			if err := m.isStillAlive(); err != nil {
   579  				return nil, errors.Trace(err)
   580  			}
   581  		}
   582  
   583  		ops := []txn.Op{
   584  			assertModelActiveOp(m.st.ModelUUID()),
   585  			m.assertAliveOp(),
   586  		}
   587  
   588  		setAddressesOps, err := m.setDevicesAddressesFromDocsOps(newDocs)
   589  		if err != nil {
   590  			return nil, errors.Trace(err)
   591  		}
   592  		return append(ops, setAddressesOps...), nil
   593  	}
   594  	if err := m.st.run(buildTxn); err != nil {
   595  		return errors.Trace(err)
   596  	}
   597  	return nil
   598  }
   599  
   600  func (st *State) allProviderIDsForModelIPAddresses() (set.Strings, error) {
   601  	return st.allProviderIDsForModelCollection(ipAddressesC, "IP addresses")
   602  }
   603  
   604  func (m *Machine) prepareToSetDevicesAddresses(devicesAddresses []LinkLayerDeviceAddress, existingProviderIDs set.Strings) ([]ipAddressDoc, error) {
   605  	var pendingDocs []ipAddressDoc
   606  	allProviderIDs := set.NewStrings(existingProviderIDs.Values()...)
   607  
   608  	for _, args := range devicesAddresses {
   609  		newDoc, err := m.prepareOneSetDevicesAddresses(&args, allProviderIDs)
   610  		if err != nil {
   611  			return nil, errors.Trace(err)
   612  		}
   613  		pendingDocs = append(pendingDocs, *newDoc)
   614  		if args.ProviderID != "" {
   615  			allProviderIDs.Add(string(args.ProviderID))
   616  		}
   617  	}
   618  	return pendingDocs, nil
   619  }
   620  
   621  func (m *Machine) prepareOneSetDevicesAddresses(args *LinkLayerDeviceAddress, allProviderIDs set.Strings) (_ *ipAddressDoc, err error) {
   622  	defer errors.DeferredAnnotatef(&err, "invalid address %q", args.CIDRAddress)
   623  
   624  	if err := m.validateSetDevicesAddressesArgs(args); err != nil {
   625  		return nil, errors.Trace(err)
   626  	}
   627  
   628  	if allProviderIDs.Contains(string(args.ProviderID)) {
   629  		return nil, NewProviderIDNotUniqueError(args.ProviderID)
   630  	}
   631  
   632  	return m.newIPAddressDocFromArgs(args)
   633  }
   634  
   635  func (m *Machine) validateSetDevicesAddressesArgs(args *LinkLayerDeviceAddress) error {
   636  	if args.CIDRAddress == "" {
   637  		return errors.NotValidf("empty CIDRAddress")
   638  	}
   639  	if _, _, err := net.ParseCIDR(args.CIDRAddress); err != nil {
   640  		return errors.NewNotValid(err, "CIDRAddress")
   641  	}
   642  
   643  	if args.DeviceName == "" {
   644  		return errors.NotValidf("empty DeviceName")
   645  	}
   646  	if !IsValidLinkLayerDeviceName(args.DeviceName) {
   647  		logger.Warningf(
   648  			"address %q on machine %q has invalid device name %q (using anyway)",
   649  			args.CIDRAddress, m.Id(), args.DeviceName,
   650  		)
   651  	}
   652  	if err := m.verifyDeviceAlreadyExists(args.DeviceName); err != nil {
   653  		return errors.Trace(err)
   654  	}
   655  
   656  	if !IsValidAddressConfigMethod(string(args.ConfigMethod)) {
   657  		return errors.NotValidf("ConfigMethod %q", args.ConfigMethod)
   658  	}
   659  
   660  	if args.GatewayAddress != "" {
   661  		if ip := net.ParseIP(args.GatewayAddress); ip == nil {
   662  			return errors.NotValidf("GatewayAddress %q", args.GatewayAddress)
   663  		}
   664  	}
   665  
   666  	return nil
   667  }
   668  
   669  func (m *Machine) verifyDeviceAlreadyExists(deviceName string) error {
   670  	if _, err := m.LinkLayerDevice(deviceName); errors.IsNotFound(err) {
   671  		return errors.NotFoundf("DeviceName %q on machine %q", deviceName, m.Id())
   672  	} else if err != nil {
   673  		return errors.Trace(err)
   674  	}
   675  	return nil
   676  }
   677  
   678  func (m *Machine) newIPAddressDocFromArgs(args *LinkLayerDeviceAddress) (*ipAddressDoc, error) {
   679  	ip, ipNet, err := net.ParseCIDR(args.CIDRAddress)
   680  	if err != nil {
   681  		// We already validated CIDRAddress earlier, so this cannot happen in
   682  		// practice, but we handle it anyway.
   683  		return nil, errors.Trace(err)
   684  	}
   685  	addressValue := ip.String()
   686  	subnetCIDR := ipNet.String()
   687  	subnet, err := m.st.Subnet(subnetCIDR)
   688  	if errors.IsNotFound(err) {
   689  		logger.Infof(
   690  			"address %q on machine %q uses unknown or machine-local subnet %q",
   691  			addressValue, m.Id(), subnetCIDR,
   692  		)
   693  	} else if err != nil {
   694  		return nil, errors.Trace(err)
   695  	} else if err := m.verifySubnetAlive(subnet); err != nil {
   696  		return nil, errors.Trace(err)
   697  	}
   698  
   699  	globalKey := ipAddressGlobalKey(m.doc.Id, args.DeviceName, addressValue)
   700  	ipAddressDocID := m.st.docID(globalKey)
   701  
   702  	providerID := string(args.ProviderID)
   703  	if providerID != "" {
   704  		providerID = m.st.docID(providerID)
   705  	}
   706  	modelUUID := m.st.ModelUUID()
   707  
   708  	newDoc := &ipAddressDoc{
   709  		DocID:            ipAddressDocID,
   710  		ModelUUID:        modelUUID,
   711  		ProviderID:       providerID,
   712  		DeviceName:       args.DeviceName,
   713  		MachineID:        m.doc.Id,
   714  		SubnetCIDR:       subnetCIDR,
   715  		ConfigMethod:     args.ConfigMethod,
   716  		Value:            addressValue,
   717  		DNSServers:       args.DNSServers,
   718  		DNSSearchDomains: args.DNSSearchDomains,
   719  		GatewayAddress:   args.GatewayAddress,
   720  	}
   721  	return newDoc, nil
   722  }
   723  
   724  func (m *Machine) verifySubnetAlive(subnet *Subnet) error {
   725  	if subnet.Life() != Alive {
   726  		return errors.Errorf("subnet %q is not alive", subnet.CIDR())
   727  	}
   728  	return nil
   729  }
   730  
   731  func (m *Machine) setDevicesAddressesFromDocsOps(newDocs []ipAddressDoc) ([]txn.Op, error) {
   732  	addresses, closer := m.st.getCollection(ipAddressesC)
   733  	defer closer()
   734  
   735  	var ops []txn.Op
   736  
   737  	for _, newDoc := range newDocs {
   738  		deviceDocID := m.linkLayerDeviceDocIDFromName(newDoc.DeviceName)
   739  		ops = append(ops, assertLinkLayerDeviceExistsOp(deviceDocID))
   740  
   741  		var existingDoc ipAddressDoc
   742  		err := addresses.FindId(newDoc.DocID).One(&existingDoc)
   743  		if err == mgo.ErrNotFound {
   744  			// Address does not exist yet - insert it.
   745  			ops = append(ops, insertIPAddressDocOp(&newDoc))
   746  		} else if err == nil {
   747  			// Address already exists - update what's possible.
   748  			ops = append(ops, updateIPAddressDocOp(&existingDoc, &newDoc))
   749  		} else {
   750  			return nil, errors.Trace(err)
   751  		}
   752  
   753  		ops, err = m.maybeAssertSubnetAliveOps(&newDoc, ops)
   754  		if err != nil {
   755  			return nil, errors.Trace(err)
   756  		}
   757  	}
   758  	return ops, nil
   759  }
   760  
   761  func (m *Machine) maybeAssertSubnetAliveOps(newDoc *ipAddressDoc, opsSoFar []txn.Op) ([]txn.Op, error) {
   762  	subnet, err := m.st.Subnet(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(newDoc.SubnetCIDR),
   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.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  // AllAddresses returns the all addresses assigned to all devices of the
   799  // machine.
   800  func (m *Machine) AllAddresses() ([]*Address, error) {
   801  	var allAddresses []*Address
   802  	callbackFunc := func(resultDoc *ipAddressDoc) {
   803  		allAddresses = append(allAddresses, newIPAddress(m.st, *resultDoc))
   804  	}
   805  
   806  	findQuery := findAddressesQuery(m.doc.Id, "")
   807  	if err := m.st.forEachIPAddressDoc(findQuery, nil, callbackFunc); err != nil {
   808  		return nil, errors.Trace(err)
   809  	}
   810  	return allAddresses, nil
   811  }
   812  
   813  // SetParentLinkLayerDevicesBeforeTheirChildren splits the given devicesArgs
   814  // into multiple sets of args and calls SetLinkLayerDevices() for each set, such
   815  // that child devices are set only after their parents.
   816  func (m *Machine) SetParentLinkLayerDevicesBeforeTheirChildren(devicesArgs []LinkLayerDeviceArgs) error {
   817  	seenNames := set.NewStrings("") // sentinel for empty ParentName.
   818  	for {
   819  		argsToSet := []LinkLayerDeviceArgs{}
   820  		for _, args := range devicesArgs {
   821  			if seenNames.Contains(args.Name) {
   822  				// Already added earlier.
   823  				continue
   824  			}
   825  			if seenNames.Contains(args.ParentName) {
   826  				argsToSet = append(argsToSet, args)
   827  			}
   828  		}
   829  		if len(argsToSet) == 0 {
   830  			// We're done.
   831  			break
   832  		}
   833  		logger.Debugf("setting link-layer devices %+v", argsToSet)
   834  		if err := m.SetLinkLayerDevices(argsToSet...); IsProviderIDNotUniqueError(err) {
   835  			// FIXME: Make updating devices with unchanged ProviderID idempotent.
   836  			for i, args := range argsToSet {
   837  				args.ProviderID = ""
   838  				argsToSet[i] = args
   839  			}
   840  			if err := m.SetLinkLayerDevices(argsToSet...); err != nil {
   841  				return errors.Trace(err)
   842  			}
   843  		} else if err != nil {
   844  			return errors.Trace(err)
   845  		}
   846  		for _, args := range argsToSet {
   847  			seenNames.Add(args.Name)
   848  		}
   849  	}
   850  	return nil
   851  }
   852  
   853  // SetDevicesAddressesIdempotently calls SetDevicesAddresses() and if it fails
   854  // with ErrProviderIDNotUnique, retries the call with all ProviderID fields in
   855  // devicesAddresses set to empty.
   856  func (m *Machine) SetDevicesAddressesIdempotently(devicesAddresses []LinkLayerDeviceAddress) error {
   857  	if err := m.SetDevicesAddresses(devicesAddresses...); IsProviderIDNotUniqueError(err) {
   858  		// FIXME: Make updating addresses with unchanged ProviderID idempotent.
   859  		for i, args := range devicesAddresses {
   860  			args.ProviderID = ""
   861  			devicesAddresses[i] = args
   862  		}
   863  		if err := m.SetDevicesAddresses(devicesAddresses...); err != nil {
   864  			return errors.Trace(err)
   865  		}
   866  	} else if err != nil {
   867  		return errors.Trace(err)
   868  	}
   869  	return nil
   870  }
   871  
   872  // SetContainerLinkLayerDevices sets the link-layer devices of the given
   873  // containerMachine, setting each device linked to the corresponding
   874  // BridgeDevice of the host machine m.
   875  func (m *Machine) SetContainerLinkLayerDevices(containerMachine *Machine) error {
   876  	allDevices, err := m.AllLinkLayerDevices()
   877  	if err != nil {
   878  		return errors.Annotate(err, "cannot get host machine devices")
   879  	}
   880  	logger.Debugf("using host machine %q devices: %+v", m.Id(), allDevices)
   881  
   882  	var containerDevicesArgs []LinkLayerDeviceArgs
   883  	for _, hostDevice := range allDevices {
   884  		if hostDevice.Type() == BridgeDevice {
   885  			containerDeviceName := fmt.Sprintf("eth%d", len(containerDevicesArgs))
   886  			generatedMAC := generateMACAddress()
   887  			args := LinkLayerDeviceArgs{
   888  				Name:        containerDeviceName,
   889  				Type:        EthernetDevice,
   890  				MACAddress:  generatedMAC,
   891  				MTU:         hostDevice.MTU(),
   892  				IsUp:        true,
   893  				IsAutoStart: true,
   894  				ParentName:  hostDevice.globalKey(),
   895  			}
   896  			containerDevicesArgs = append(containerDevicesArgs, args)
   897  		}
   898  	}
   899  	logger.Debugf("prepared container %q network config: %+v", containerMachine.Id(), containerDevicesArgs)
   900  
   901  	if err := containerMachine.SetLinkLayerDevices(containerDevicesArgs...); err != nil {
   902  		return errors.Trace(err)
   903  	}
   904  
   905  	logger.Debugf("container %q network config set", containerMachine.Id())
   906  	return nil
   907  }
   908  
   909  // MACAddressTemplate is used to generate a unique MAC address for a
   910  // container. Every '%x' is replaced by a random hexadecimal digit,
   911  // while the rest is kept as-is.
   912  const macAddressTemplate = "00:16:3e:%02x:%02x:%02x"
   913  
   914  // generateMACAddress creates a random MAC address within the space defined by
   915  // macAddressTemplate above.
   916  //
   917  // TODO(dimitern): We should make a best effort to ensure the MAC address we
   918  // generate is unique at least within the current environment.
   919  func generateMACAddress() string {
   920  	digits := make([]interface{}, 3)
   921  	for i := range digits {
   922  		digits[i] = rand.Intn(256)
   923  	}
   924  	return fmt.Sprintf(macAddressTemplate, digits...)
   925  }