func interfaceAddressToNetworkConfig(interfaceName, configType string, address net.Addr) (params.NetworkConfig, error) { config := params.NetworkConfig{ ConfigType: configType, } cidrAddress := address.String() if cidrAddress == "" { return config, nil } ip, ipNet, err := net.ParseCIDR(cidrAddress) if err != nil { logger.Infof("cannot parse %q on interface %q as CIDR, trying as IP address: %v", cidrAddress, interfaceName, err) if ip = net.ParseIP(cidrAddress); ip == nil { return config, errors.Errorf("cannot parse IP address %q on interface %q", cidrAddress, interfaceName) } else { ipNet = &net.IPNet{IP: ip} } } if ip.To4() == nil { logger.Debugf("skipping observed IPv6 address %q on %q: not fully supported yet", ip, interfaceName) // TODO(dimitern): Treat IPv6 addresses as empty until we can handle // them reliably. return config, nil } if ipNet.Mask != nil { config.CIDR = ipNet.String() } config.Address = ip.String() if configType != string(network.ConfigLoopback) { config.ConfigType = string(network.ConfigStatic) } // TODO(dimitern): Add DNS servers, search domains, and gateway // later. return config, nil }
// MergeProviderAndObservedNetworkConfigs returns the effective, sorted, network // configs after merging providerConfig with observedConfig. func MergeProviderAndObservedNetworkConfigs(providerConfigs, observedConfigs []params.NetworkConfig) []params.NetworkConfig { providerConfigsByName := make(map[string][]params.NetworkConfig) sortedProviderConfigs := SortNetworkConfigsByParents(providerConfigs) for _, config := range sortedProviderConfigs { name := config.InterfaceName providerConfigsByName[name] = append(providerConfigsByName[name], config) } jsonProviderConfig, err := NetworkConfigsToIndentedJSON(sortedProviderConfigs) if err != nil { logger.Warningf("cannot serialize provider config %#v as JSON: %v", sortedProviderConfigs, err) } else { logger.Debugf("provider network config of machine:\n%s", jsonProviderConfig) } sortedObservedConfigs := SortNetworkConfigsByParents(observedConfigs) jsonObservedConfig, err := NetworkConfigsToIndentedJSON(sortedObservedConfigs) if err != nil { logger.Warningf("cannot serialize observed config %#v as JSON: %v", sortedObservedConfigs, err) } else { logger.Debugf("observed network config of machine:\n%s", jsonObservedConfig) } var mergedConfigs []params.NetworkConfig for _, config := range sortedObservedConfigs { name := config.InterfaceName logger.Tracef("merging observed config for device %q: %+v", name, config) if strings.HasPrefix(name, instancecfg.DefaultBridgePrefix) { logger.Tracef("found potential juju bridge %q in observed config", name) unprefixedName := strings.TrimPrefix(name, instancecfg.DefaultBridgePrefix) underlyingConfigs, underlyingKnownByProvider := providerConfigsByName[unprefixedName] logger.Tracef("device %q underlying %q has provider config: %+v", name, unprefixedName, underlyingConfigs) if underlyingKnownByProvider { // This config is for a bridge created by Juju and not known by // the provider. The bridge is configured to adopt the address // allocated to the underlying interface, which is known by the // provider. However, since the same underlying interface can // have multiple addresses, we need to match the adopted // bridgeConfig to the correct address. var underlyingConfig params.NetworkConfig for i, underlying := range underlyingConfigs { if underlying.Address == config.Address { logger.Tracef("replacing undelying config %+v", underlying) // Remove what we found before changing it below. underlyingConfig = underlying underlyingConfigs = append(underlyingConfigs[:i], underlyingConfigs[i+1:]...) break } } logger.Tracef("underlying provider config after update: %+v", underlyingConfigs) bridgeConfig := config bridgeConfig.InterfaceType = string(network.BridgeInterface) bridgeConfig.ConfigType = underlyingConfig.ConfigType bridgeConfig.VLANTag = underlyingConfig.VLANTag bridgeConfig.ProviderId = "" // Juju-created bridges never have a ProviderID bridgeConfig.ProviderSpaceId = underlyingConfig.ProviderSpaceId bridgeConfig.ProviderVLANId = underlyingConfig.ProviderVLANId bridgeConfig.ProviderSubnetId = underlyingConfig.ProviderSubnetId bridgeConfig.ProviderAddressId = underlyingConfig.ProviderAddressId if underlyingParent := underlyingConfig.ParentInterfaceName; underlyingParent != "" { bridgeConfig.ParentInterfaceName = instancecfg.DefaultBridgePrefix + underlyingParent } underlyingConfig.ConfigType = string(network.ConfigManual) underlyingConfig.ParentInterfaceName = name underlyingConfig.ProviderAddressId = "" underlyingConfig.CIDR = "" underlyingConfig.Address = "" underlyingConfigs = append(underlyingConfigs, underlyingConfig) providerConfigsByName[unprefixedName] = underlyingConfigs logger.Tracef("updated provider network config by name: %+v", providerConfigsByName) mergedConfigs = append(mergedConfigs, bridgeConfig) continue } } knownProviderConfigs, knownByProvider := providerConfigsByName[name] if !knownByProvider { // Not known by the provider and not a Juju-created bridge, so just // use the observed config for it. logger.Tracef("device %q not known to provider - adding only observed config: %+v", name, config) mergedConfigs = append(mergedConfigs, config) continue } logger.Tracef("device %q has known provider network config: %+v", name, knownProviderConfigs) for _, providerConfig := range knownProviderConfigs { if providerConfig.Address == config.Address { logger.Tracef( "device %q has observed address %q, index %d, and MTU %q; overriding index %d and MTU %d from provider config", name, config.Address, config.DeviceIndex, config.MTU, providerConfig.DeviceIndex, providerConfig.MTU, ) // Prefer observed device indices and MTU values as more up-to-date. providerConfig.DeviceIndex = config.DeviceIndex providerConfig.MTU = config.MTU mergedConfigs = append(mergedConfigs, providerConfig) break } } } sortedMergedConfigs := SortNetworkConfigsByParents(mergedConfigs) jsonMergedConfig, err := NetworkConfigsToIndentedJSON(sortedMergedConfigs) if err != nil { logger.Warningf("cannot serialize merged config %#v as JSON: %v", sortedMergedConfigs, err) } else { logger.Debugf("combined machine network config:\n%s", jsonMergedConfig) } return mergedConfigs }