github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/common/networkingcommon/types.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package networkingcommon
     5  
     6  import (
     7  	"net"
     8  
     9  	"github.com/juju/collections/set"
    10  	"github.com/juju/errors"
    11  	"gopkg.in/juju/names.v2"
    12  
    13  	"github.com/juju/juju/apiserver/common"
    14  	"github.com/juju/juju/apiserver/params"
    15  	"github.com/juju/juju/environs"
    16  	"github.com/juju/juju/network"
    17  	providercommon "github.com/juju/juju/provider/common"
    18  	"github.com/juju/juju/state"
    19  )
    20  
    21  // BackingSubnet defines the methods supported by a Subnet entity
    22  // stored persistently.
    23  //
    24  // TODO(dimitern): Once the state backing is implemented, remove this
    25  // and just use *state.Subnet.
    26  type BackingSubnet interface {
    27  	CIDR() string
    28  	VLANTag() int
    29  	ProviderId() network.Id
    30  	ProviderNetworkId() network.Id
    31  	AvailabilityZones() []string
    32  	Status() string
    33  	SpaceName() string
    34  	Life() params.Life
    35  }
    36  
    37  // BackingSubnetInfo describes a single subnet to be added in the
    38  // backing store.
    39  //
    40  // TODO(dimitern): Replace state.SubnetInfo with this and remove
    41  // BackingSubnetInfo, once the rest of state backing methods and the
    42  // following pre-reqs are done:
    43  // * subnetDoc.AvailabilityZone becomes subnetDoc.AvailabilityZones,
    44  //   adding an upgrade step to migrate existing non empty zones on
    45  //   subnet docs. Also change state.Subnet.AvailabilityZone to
    46  // * Subnets need a reference count to calculate Status.
    47  // * ensure EC2 and MAAS providers accept empty IDs as Subnets() args
    48  //   and return all subnets, including the AvailabilityZones (for EC2;
    49  //   empty for MAAS as zones are orthogonal to networks).
    50  type BackingSubnetInfo struct {
    51  	// ProviderId is a provider-specific network id. This may be empty.
    52  	ProviderId network.Id
    53  
    54  	// ProviderNetworkId is the id of the network containing this
    55  	// subnet from the provider's perspective. It can be empty if the
    56  	// provider doesn't support distinct networks.
    57  	ProviderNetworkId network.Id
    58  
    59  	// CIDR of the network, in 123.45.67.89/24 format.
    60  	CIDR string
    61  
    62  	// VLANTag needs to be between 1 and 4094 for VLANs and 0 for normal
    63  	// networks. It's defined by IEEE 802.1Q standard.
    64  	VLANTag int
    65  
    66  	// AvailabilityZones describes which availability zone(s) this
    67  	// subnet is in. It can be empty if the provider does not support
    68  	// availability zones.
    69  	AvailabilityZones []string
    70  
    71  	// SpaceName holds the juju network space this subnet is
    72  	// associated with. Can be empty if not supported.
    73  	SpaceName string
    74  
    75  	// Status holds the status of the subnet. Normally this will be
    76  	// calculated from the reference count and Life of a subnet.
    77  	Status string
    78  
    79  	// Live holds the life of the subnet
    80  	Life params.Life
    81  }
    82  
    83  // BackingSpace defines the methods supported by a Space entity stored
    84  // persistently.
    85  type BackingSpace interface {
    86  	// Name returns the space name.
    87  	Name() string
    88  
    89  	// Subnets returns the subnets in the space
    90  	Subnets() ([]BackingSubnet, error)
    91  
    92  	// ProviderId returns the network ID of the provider
    93  	ProviderId() network.Id
    94  }
    95  
    96  // NetworkBacking defines the methods needed by the API facade to store and
    97  // retrieve information from the underlying persistency layer (state
    98  // DB).
    99  type NetworkBacking interface {
   100  	environs.EnvironConfigGetter
   101  
   102  	// AvailabilityZones returns all cached availability zones (i.e.
   103  	// not from the provider, but in state).
   104  	AvailabilityZones() ([]providercommon.AvailabilityZone, error)
   105  
   106  	// SetAvailabilityZones replaces the cached list of availability
   107  	// zones with the given zones.
   108  	SetAvailabilityZones([]providercommon.AvailabilityZone) error
   109  
   110  	// AddSpace creates a space
   111  	AddSpace(Name string, ProviderId network.Id, Subnets []string, Public bool) error
   112  
   113  	// AllSpaces returns all known Juju network spaces.
   114  	AllSpaces() ([]BackingSpace, error)
   115  
   116  	// AddSubnet creates a backing subnet for an existing subnet.
   117  	AddSubnet(BackingSubnetInfo) (BackingSubnet, error)
   118  
   119  	// AllSubnets returns all backing subnets.
   120  	AllSubnets() ([]BackingSubnet, error)
   121  
   122  	// ModelTag returns the tag of the model this state is associated to.
   123  	ModelTag() names.ModelTag
   124  
   125  	// ReloadSpaces loads spaces from backing environ
   126  	ReloadSpaces(environ environs.Environ) error
   127  }
   128  
   129  func BackingSubnetToParamsSubnet(subnet BackingSubnet) params.Subnet {
   130  	cidr := subnet.CIDR()
   131  	vlantag := subnet.VLANTag()
   132  	providerid := subnet.ProviderId()
   133  	zones := subnet.AvailabilityZones()
   134  	status := subnet.Status()
   135  	var spaceTag names.SpaceTag
   136  	if subnet.SpaceName() != "" {
   137  		spaceTag = names.NewSpaceTag(subnet.SpaceName())
   138  	}
   139  
   140  	return params.Subnet{
   141  		CIDR:       cidr,
   142  		VLANTag:    vlantag,
   143  		ProviderId: string(providerid),
   144  		Zones:      zones,
   145  		Status:     status,
   146  		SpaceTag:   spaceTag.String(),
   147  		Life:       subnet.Life(),
   148  	}
   149  }
   150  
   151  // NetworkConfigFromInterfaceInfo converts a slice of network.InterfaceInfo into
   152  // the equivalent params.NetworkConfig slice.
   153  func NetworkConfigFromInterfaceInfo(interfaceInfos []network.InterfaceInfo) []params.NetworkConfig {
   154  	result := make([]params.NetworkConfig, len(interfaceInfos))
   155  	for i, v := range interfaceInfos {
   156  		var dnsServers []string
   157  		for _, nameserver := range v.DNSServers {
   158  			dnsServers = append(dnsServers, nameserver.Value)
   159  		}
   160  		routes := make([]params.NetworkRoute, len(v.Routes))
   161  		for j, route := range v.Routes {
   162  			routes[j] = params.NetworkRoute{
   163  				DestinationCIDR: route.DestinationCIDR,
   164  				GatewayIP:       route.GatewayIP,
   165  				Metric:          route.Metric,
   166  			}
   167  		}
   168  		result[i] = params.NetworkConfig{
   169  			DeviceIndex:         v.DeviceIndex,
   170  			MACAddress:          v.MACAddress,
   171  			CIDR:                v.CIDR,
   172  			MTU:                 v.MTU,
   173  			ProviderId:          string(v.ProviderId),
   174  			ProviderSubnetId:    string(v.ProviderSubnetId),
   175  			ProviderSpaceId:     string(v.ProviderSpaceId),
   176  			ProviderVLANId:      string(v.ProviderVLANId),
   177  			ProviderAddressId:   string(v.ProviderAddressId),
   178  			VLANTag:             v.VLANTag,
   179  			InterfaceName:       v.InterfaceName,
   180  			ParentInterfaceName: v.ParentInterfaceName,
   181  			InterfaceType:       string(v.InterfaceType),
   182  			Disabled:            v.Disabled,
   183  			NoAutoStart:         v.NoAutoStart,
   184  			ConfigType:          string(v.ConfigType),
   185  			Address:             v.Address.Value,
   186  			DNSServers:          dnsServers,
   187  			DNSSearchDomains:    v.DNSSearchDomains,
   188  			GatewayAddress:      v.GatewayAddress.Value,
   189  			Routes:              routes,
   190  			IsDefaultGateway:    v.IsDefaultGateway,
   191  		}
   192  	}
   193  	return result
   194  }
   195  
   196  // NetworkConfigsToStateArgs splits the given networkConfig into a slice of
   197  // state.LinkLayerDeviceArgs and a slice of state.LinkLayerDeviceAddress. The
   198  // input is expected to come from MergeProviderAndObservedNetworkConfigs and to
   199  // be sorted.
   200  func NetworkConfigsToStateArgs(networkConfig []params.NetworkConfig) (
   201  	[]state.LinkLayerDeviceArgs,
   202  	[]state.LinkLayerDeviceAddress,
   203  ) {
   204  	var devicesArgs []state.LinkLayerDeviceArgs
   205  	var devicesAddrs []state.LinkLayerDeviceAddress
   206  
   207  	logger.Tracef("transforming network config to state args: %+v", networkConfig)
   208  	seenDeviceNames := set.NewStrings()
   209  	for _, netConfig := range networkConfig {
   210  		logger.Tracef("transforming device %q", netConfig.InterfaceName)
   211  		if !seenDeviceNames.Contains(netConfig.InterfaceName) {
   212  			// First time we see this, add it to devicesArgs.
   213  			seenDeviceNames.Add(netConfig.InterfaceName)
   214  			var mtu uint
   215  			if netConfig.MTU >= 0 {
   216  				mtu = uint(netConfig.MTU)
   217  			}
   218  			args := state.LinkLayerDeviceArgs{
   219  				Name:        netConfig.InterfaceName,
   220  				MTU:         mtu,
   221  				ProviderID:  network.Id(netConfig.ProviderId),
   222  				Type:        state.LinkLayerDeviceType(netConfig.InterfaceType),
   223  				MACAddress:  netConfig.MACAddress,
   224  				IsAutoStart: !netConfig.NoAutoStart,
   225  				IsUp:        !netConfig.Disabled,
   226  				ParentName:  netConfig.ParentInterfaceName,
   227  			}
   228  			logger.Tracef("state device args for device: %+v", args)
   229  			devicesArgs = append(devicesArgs, args)
   230  		}
   231  
   232  		if netConfig.CIDR == "" || netConfig.Address == "" {
   233  			logger.Tracef(
   234  				"skipping empty CIDR %q and/or Address %q of %q",
   235  				netConfig.CIDR, netConfig.Address, netConfig.InterfaceName,
   236  			)
   237  			continue
   238  		}
   239  		_, ipNet, err := net.ParseCIDR(netConfig.CIDR)
   240  		if err != nil {
   241  			logger.Warningf("FIXME: ignoring unexpected CIDR format %q: %v", netConfig.CIDR, err)
   242  			continue
   243  		}
   244  		ipAddr := net.ParseIP(netConfig.Address)
   245  		if ipAddr == nil {
   246  			logger.Warningf("FIXME: ignoring unexpected Address format %q", netConfig.Address)
   247  			continue
   248  		}
   249  		ipNet.IP = ipAddr
   250  		cidrAddress := ipNet.String()
   251  
   252  		var derivedConfigMethod state.AddressConfigMethod
   253  		switch method := state.AddressConfigMethod(netConfig.ConfigType); method {
   254  		case state.StaticAddress, state.DynamicAddress,
   255  			state.LoopbackAddress, state.ManualAddress:
   256  			derivedConfigMethod = method
   257  		case "dhcp": // awkward special case
   258  			derivedConfigMethod = state.DynamicAddress
   259  		default:
   260  			derivedConfigMethod = state.StaticAddress
   261  		}
   262  
   263  		addr := state.LinkLayerDeviceAddress{
   264  			DeviceName:       netConfig.InterfaceName,
   265  			ProviderID:       network.Id(netConfig.ProviderAddressId),
   266  			ConfigMethod:     derivedConfigMethod,
   267  			CIDRAddress:      cidrAddress,
   268  			DNSServers:       netConfig.DNSServers,
   269  			DNSSearchDomains: netConfig.DNSSearchDomains,
   270  			GatewayAddress:   netConfig.GatewayAddress,
   271  			IsDefaultGateway: netConfig.IsDefaultGateway,
   272  		}
   273  		logger.Tracef("state address args for device: %+v", addr)
   274  		devicesAddrs = append(devicesAddrs, addr)
   275  	}
   276  	logger.Tracef("seen devices: %+v", seenDeviceNames.SortedValues())
   277  	logger.Tracef("network config transformed to state args:\n%+v\n%+v", devicesArgs, devicesAddrs)
   278  	return devicesArgs, devicesAddrs
   279  }
   280  
   281  // NetworkingEnvironFromModelConfig constructs and returns
   282  // environs.NetworkingEnviron using the given configGetter. Returns an error
   283  // satisfying errors.IsNotSupported() if the model config does not support
   284  // networking features.
   285  func NetworkingEnvironFromModelConfig(configGetter environs.EnvironConfigGetter) (environs.NetworkingEnviron, error) {
   286  	modelConfig, err := configGetter.ModelConfig()
   287  	if err != nil {
   288  		return nil, errors.Annotate(err, "failed to get model config")
   289  	}
   290  	env, err := environs.GetEnviron(configGetter, environs.New)
   291  	if err != nil {
   292  		return nil, errors.Annotate(err, "failed to construct a model from config")
   293  	}
   294  	netEnviron, supported := environs.SupportsNetworking(env)
   295  	if !supported {
   296  		// " not supported" will be appended to the message below.
   297  		return nil, errors.NotSupportedf("model %q networking", modelConfig.Name())
   298  	}
   299  	return netEnviron, nil
   300  }
   301  
   302  // NetworkConfigSource defines the necessary calls to obtain the network
   303  // configuration of a machine.
   304  type NetworkConfigSource interface {
   305  	// SysClassNetPath returns the Linux kernel userspace SYSFS path used by
   306  	// this source. DefaultNetworkConfigSource() uses network.SysClassNetPath.
   307  	SysClassNetPath() string
   308  
   309  	// Interfaces returns information about all network interfaces on the
   310  	// machine as []net.Interface.
   311  	Interfaces() ([]net.Interface, error)
   312  
   313  	// InterfaceAddresses returns information about all addresses assigned to
   314  	// the network interface with the given name.
   315  	InterfaceAddresses(name string) ([]net.Addr, error)
   316  }
   317  
   318  // MergeProviderAndObservedNetworkConfigs returns the effective network configs,
   319  // using observedConfigs as a base and selectively updating it using the
   320  // matching providerConfigs for each interface.
   321  func MergeProviderAndObservedNetworkConfigs(
   322  	providerConfigs, observedConfigs []params.NetworkConfig,
   323  ) []params.NetworkConfig {
   324  
   325  	providerConfigByName := networkConfigsByName(providerConfigs)
   326  	logger.Tracef("known provider config by name: %+v", providerConfigByName)
   327  
   328  	providerConfigByAddress := networkConfigsByAddress(providerConfigs)
   329  	logger.Tracef("known provider config by address: %+v", providerConfigByAddress)
   330  
   331  	var results []params.NetworkConfig
   332  	for _, observed := range observedConfigs {
   333  
   334  		name, ipAddress := observed.InterfaceName, observed.Address
   335  		finalConfig := observed
   336  
   337  		providerConfig, known := providerConfigByName[name]
   338  		if known {
   339  			finalConfig = mergeObservedAndProviderInterfaceConfig(finalConfig, providerConfig)
   340  			logger.Debugf("updated observed interface config for %q with: %+v", name, providerConfig)
   341  		}
   342  
   343  		providerConfig, known = providerConfigByAddress[ipAddress]
   344  		if known {
   345  			finalConfig = mergeObservedAndProviderAddressConfig(finalConfig, providerConfig)
   346  			logger.Debugf("updated observed address config for %q with: %+v", name, providerConfig)
   347  		}
   348  
   349  		results = append(results, finalConfig)
   350  		logger.Debugf("merged config for %q: %+v", name, finalConfig)
   351  	}
   352  
   353  	return results
   354  }
   355  
   356  func networkConfigsByName(input []params.NetworkConfig) map[string]params.NetworkConfig {
   357  	configsByName := make(map[string]params.NetworkConfig, len(input))
   358  	for _, config := range input {
   359  		configsByName[config.InterfaceName] = config
   360  	}
   361  	return configsByName
   362  }
   363  
   364  func networkConfigsByAddress(input []params.NetworkConfig) map[string]params.NetworkConfig {
   365  	configsByAddress := make(map[string]params.NetworkConfig, len(input))
   366  	for _, config := range input {
   367  		configsByAddress[config.Address] = config
   368  	}
   369  	return configsByAddress
   370  }
   371  
   372  func mergeObservedAndProviderInterfaceConfig(observedConfig, providerConfig params.NetworkConfig) params.NetworkConfig {
   373  	logger.Debugf("mergeObservedAndProviderInterfaceConfig %+v %+v", observedConfig, providerConfig)
   374  	finalConfig := observedConfig
   375  
   376  	// The following fields cannot be observed and are only known by the
   377  	// provider.
   378  	finalConfig.ProviderId = providerConfig.ProviderId
   379  	finalConfig.ProviderVLANId = providerConfig.ProviderVLANId
   380  	finalConfig.ProviderSubnetId = providerConfig.ProviderSubnetId
   381  
   382  	// The following few fields are only updated if their observed values are
   383  	// empty.
   384  
   385  	if observedConfig.InterfaceType == "" {
   386  		finalConfig.InterfaceType = providerConfig.InterfaceType
   387  	}
   388  
   389  	if observedConfig.VLANTag == 0 {
   390  		finalConfig.VLANTag = providerConfig.VLANTag
   391  	}
   392  
   393  	if observedConfig.ParentInterfaceName == "" {
   394  		finalConfig.ParentInterfaceName = providerConfig.ParentInterfaceName
   395  	}
   396  	logger.Debugf("mergeObservedAndProviderInterfaceConfig %+v", finalConfig)
   397  
   398  	return finalConfig
   399  }
   400  
   401  func mergeObservedAndProviderAddressConfig(observedConfig, providerConfig params.NetworkConfig) params.NetworkConfig {
   402  	finalConfig := observedConfig
   403  
   404  	// The following fields cannot be observed and are only known by the
   405  	// provider.
   406  	finalConfig.ProviderAddressId = providerConfig.ProviderAddressId
   407  	finalConfig.ProviderSubnetId = providerConfig.ProviderSubnetId
   408  	finalConfig.ProviderSpaceId = providerConfig.ProviderSpaceId
   409  
   410  	// The following few fields are only updated if their observed values are
   411  	// empty.
   412  
   413  	if observedConfig.ProviderVLANId == "" {
   414  		finalConfig.ProviderVLANId = providerConfig.ProviderVLANId
   415  	}
   416  
   417  	if observedConfig.VLANTag == 0 {
   418  		finalConfig.VLANTag = providerConfig.VLANTag
   419  	}
   420  
   421  	if observedConfig.ConfigType == "" {
   422  		finalConfig.ConfigType = providerConfig.ConfigType
   423  	}
   424  
   425  	if observedConfig.CIDR == "" {
   426  		finalConfig.CIDR = providerConfig.CIDR
   427  	}
   428  
   429  	if observedConfig.GatewayAddress == "" {
   430  		finalConfig.GatewayAddress = providerConfig.GatewayAddress
   431  	}
   432  
   433  	if len(observedConfig.DNSServers) == 0 {
   434  		finalConfig.DNSServers = providerConfig.DNSServers
   435  	}
   436  
   437  	if len(observedConfig.DNSSearchDomains) == 0 {
   438  		finalConfig.DNSSearchDomains = providerConfig.DNSSearchDomains
   439  	}
   440  
   441  	return finalConfig
   442  }
   443  
   444  func networkToParamsNetworkInfo(info network.NetworkInfo) params.NetworkInfo {
   445  	addresses := make([]params.InterfaceAddress, len(info.Addresses))
   446  	for i, addr := range info.Addresses {
   447  		addresses[i] = params.InterfaceAddress{
   448  			Address: addr.Address,
   449  			CIDR:    addr.CIDR,
   450  		}
   451  	}
   452  	return params.NetworkInfo{
   453  		MACAddress:    info.MACAddress,
   454  		InterfaceName: info.InterfaceName,
   455  		Addresses:     addresses,
   456  	}
   457  }
   458  
   459  func MachineNetworkInfoResultToNetworkInfoResult(inResult state.MachineNetworkInfoResult) params.NetworkInfoResult {
   460  	if inResult.Error != nil {
   461  		return params.NetworkInfoResult{Error: common.ServerError(inResult.Error)}
   462  	}
   463  	infos := make([]params.NetworkInfo, len(inResult.NetworkInfos))
   464  	for i, info := range inResult.NetworkInfos {
   465  		infos[i] = networkToParamsNetworkInfo(info)
   466  	}
   467  	return params.NetworkInfoResult{
   468  		Info: infos,
   469  	}
   470  }
   471  
   472  func FanConfigToFanConfigResult(config network.FanConfig) params.FanConfigResult {
   473  	result := params.FanConfigResult{make([]params.FanConfigEntry, len(config))}
   474  	for i, entry := range config {
   475  		result.Fans[i] = params.FanConfigEntry{entry.Underlay.String(), entry.Overlay.String()}
   476  	}
   477  	return result
   478  }
   479  
   480  func FanConfigResultToFanConfig(config params.FanConfigResult) (network.FanConfig, error) {
   481  	rv := make(network.FanConfig, len(config.Fans))
   482  	for i, entry := range config.Fans {
   483  		_, ipnet, err := net.ParseCIDR(entry.Underlay)
   484  		if err != nil {
   485  			return nil, err
   486  		}
   487  		rv[i].Underlay = ipnet
   488  		_, ipnet, err = net.ParseCIDR(entry.Overlay)
   489  		if err != nil {
   490  			return nil, err
   491  		}
   492  		rv[i].Overlay = ipnet
   493  	}
   494  	return rv, nil
   495  }