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 }