Skip to content
Permalink
Browse files

New IP address discovery logic

  • Loading branch information
zuzzas committed Oct 30, 2019
1 parent 6d76e17 commit 5f9f2215b70f0c1f04e15c292d3dbb1bf03139cc
@@ -45,13 +45,18 @@ func init() {
if err != nil {
return nil, err
}
return newVSphere(cfg, true)

cpiConfig, err := ReadCPIConfig(config)
if err != nil {
return nil, err
}
return newVSphere(cfg, cpiConfig, true)
})
}

// Creates new Controller node interface and returns
func newVSphere(cfg *vcfg.Config, finalize ...bool) (*VSphere, error) {
vs, err := buildVSphereFromConfig(cfg)
func newVSphere(cfg *vcfg.Config, cpiCfg *CPIConfig, finalize ...bool) (*VSphere, error) {
vs, err := buildVSphereFromConfig(cfg, cpiCfg)
if err != nil {
return nil, err
}
@@ -144,7 +149,7 @@ func (vs *VSphere) HasClusterID() bool {
}

// Initializes vSphere from vSphere CloudProvider Configuration
func buildVSphereFromConfig(cfg *vcfg.Config) (*VSphere, error) {
func buildVSphereFromConfig(cfg *vcfg.Config, cpiCfg *CPIConfig) (*VSphere, error) {
nm := &NodeManager{
nodeNameMap: make(map[string]*NodeInfo),
nodeUUIDMap: make(map[string]*NodeInfo),
@@ -154,6 +159,7 @@ func buildVSphereFromConfig(cfg *vcfg.Config) (*VSphere, error) {

vs := VSphere{
cfg: cfg,
cpiCfg: cpiCfg,
nodeManager: nm,
instances: newInstances(nm),
zones: newZones(nm, cfg.Labels.Zone, cfg.Labels.Region),
@@ -0,0 +1,85 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package vsphere

import (
"fmt"
"gopkg.in/gcfg.v1"
"io"
"os"
"strings"
)

// CPIConfig is used to read and store information (related only to the CPI) from the cloud configuration file
type CPIConfig struct {
CPI struct {
// address options for each network type (internal and/or external) are mutually inclusive
// e.g., if you specify "internal-network-name" and "internal-network-subnet-cidr"
// only the addresses that match BOTH will match

// VirtualMachine network interfaces backed by the following vSphere Networks
// will be used in respective status.addresses fields.
InternalNetworkName []string `gcfg:"internal-network-name"`
ExternalNetworkName []string `gcfg:"external-network-name"`

// IP addresses on VirtualMachine's network interfaces included in the fields' CIDRs
// will be used in respective status.addresses fields.
InternalNetworkSubnetCIDR []string `gcfg:"internal-network-subnet-cidr"`
ExternalNetworkSubnetCIDR []string `gcfg:"external-network-subnet-cidr"`
}
}

// FromEnv initializes the provided configuratoin object with values
// obtained from environment variables. If an environment variable is set
// for a property that's already initialized, the environment variable's value
// takes precedence.
func (cfg *CPIConfig) FromEnv() {
if v := os.Getenv("VSPHERE_INTERNAL_NETWORK_NAME"); v != "" {
cfg.CPI.InternalNetworkName = strings.Split(v, ",")
}

if v := os.Getenv("VSPHERE_EXTERNAL_NETWORK_NAME"); v != "" {
cfg.CPI.ExternalNetworkName = strings.Split(v, ",")
}

if v := os.Getenv("VSPHERE_INTERNAL_NETWORK_SUBNET_CIDR"); v != "" {
cfg.CPI.InternalNetworkSubnetCIDR = strings.Split(v, ",")
}

if v := os.Getenv("VSPHERE_EXTERNAL_NETWORK_SUBNET_CIDR"); v != "" {
cfg.CPI.ExternalNetworkSubnetCIDR = strings.Split(v, ",")
}
}

// ReadCPIConfig parses vSphere cloud config file and stores it into CPIConfig.
// Environment variables are also checked
func ReadCPIConfig(config io.Reader) (*CPIConfig, error) {
if config == nil {
return nil, fmt.Errorf("no vSphere cloud provider config file given")
}

cfg := &CPIConfig{}

if err := gcfg.FatalOnly(gcfg.ReadInto(cfg, config)); err != nil {
return nil, err
}

// Env Vars should override config file entries if present
cfg.FromEnv()

return cfg, nil
}
@@ -158,6 +158,22 @@ func returnIPsFromSpecificFamily(family string, ips []string) []string {
return matching
}

func isMatchingSubnet(address net.IP, subnets []*net.IPNet) (matched bool) {
for _, subnet := range subnets {
if subnet.Contains(address) {
matched = true
break
}
}

return
}

func isMatchingName(networkName string, networkNameMap map[string]struct{}) (matched bool) {
_, matched = networkNameMap[networkName]
return
}

// DiscoverNode finds a node's VM using the specified search value and search
// type.
func (nm *NodeManager) DiscoverNode(nodeID string, searchBy cm.FindVM) error {
@@ -190,6 +206,37 @@ func (nm *NodeManager) DiscoverNode(nodeID string, searchBy cm.FindVM) error {
klog.Warningf("Unable to find vcInstance for %s. Defaulting to ipv4.", tenantRef)
}

internalNetworkNameMap := make(map[string]struct{})
externalNetworkNameMap := make(map[string]struct{})
for _, intName := range nm.cpiCfg.CPI.InternalNetworkName {
internalNetworkNameMap[intName] = struct{}{}
}
for _, extName := range nm.cpiCfg.CPI.ExternalNetworkName {
externalNetworkNameMap[extName] = struct{}{}
}

var internalNetworkSubnets []*net.IPNet
for _, cidrStr := range nm.cpiCfg.CPI.InternalNetworkSubnetCIDR {
_, subnet, err := net.ParseCIDR(cidrStr)
if err != nil {
return err
}
internalNetworkSubnets = append(internalNetworkSubnets, subnet)
}
var externalNetworkSubnets []*net.IPNet
for _, cidrStr := range nm.cpiCfg.CPI.ExternalNetworkSubnetCIDR {
_, subnet, err := net.ParseCIDR(cidrStr)
if err != nil {
return err
}
externalNetworkSubnets = append(externalNetworkSubnets, subnet)
}

var addressMatchingEnabled bool
if len(internalNetworkNameMap) > 0 || len(externalNetworkNameMap) > 0 || len(internalNetworkSubnets) > 0 || len(externalNetworkSubnets) > 0 {
addressMatchingEnabled = true
}

found := false
addrs := []v1.NodeAddress{}
for _, v := range oVM.Guest.Net {
@@ -198,29 +245,75 @@ func (nm *NodeManager) DiscoverNode(nodeID string, searchBy cm.FindVM) error {
continue
}

if (len(internalNetworkNameMap) > 0) && (len(externalNetworkNameMap) > 0) && v.Network == "" {
klog.Warningln("Skipping device because network name-based IP address detection is enabled and the \"Network\" field is not set on vNIC")
continue
}

// Only return a single IP address based on the preference of IPFamily
// Must break out of loop in the event of ipv6,ipv4 where the NIC does
// contain a valid IPv6 and IPV4 address
for _, family := range ipFamily {
ips := returnIPsFromSpecificFamily(family, v.IpAddress)

for _, ip := range ips {
klog.V(2).Infof("Adding IP: %s", ip)
if addressMatchingEnabled {
klog.V(2).Infof("Adding Hostname")
v1helper.AddToNodeAddresses(&addrs,
v1.NodeAddress{
Type: v1.NodeExternalIP,
Address: ip,
}, v1.NodeAddress{
Type: v1.NodeInternalIP,
Address: ip,
}, v1.NodeAddress{
Type: v1.NodeHostName,
Address: oVM.Guest.HostName,
},
)

found = true
break
for _, ip := range ips {
parsedIP := net.ParseIP(ip)
if parsedIP == nil {
return err
}

internalNameMatched := isMatchingName(v.Network, internalNetworkNameMap)
internalSubnetMatched := isMatchingSubnet(parsedIP, externalNetworkSubnets)
if internalNameMatched || internalSubnetMatched {
klog.V(2).Infof("Adding Internal IP: %s", ip)
v1helper.AddToNodeAddresses(&addrs,
v1.NodeAddress{
Type: v1.NodeInternalIP,
Address: ip,
},
)
found = true
}

externalNameMatched := isMatchingName(v.Network, externalNetworkNameMap)
externalSubnetMatched := isMatchingSubnet(parsedIP, externalNetworkSubnets)
if externalNameMatched || externalSubnetMatched {
klog.V(2).Infof("Adding External IP: %s", ip)
v1helper.AddToNodeAddresses(&addrs,
v1.NodeAddress{
Type: v1.NodeExternalIP,
Address: ip,
},
)
found = true
}
}
} else {
for _, ip := range ips {
klog.V(2).Infof("Adding IP: %s", ip)
v1helper.AddToNodeAddresses(&addrs,
v1.NodeAddress{
Type: v1.NodeExternalIP,
Address: ip,
}, v1.NodeAddress{
Type: v1.NodeInternalIP,
Address: ip,
}, v1.NodeAddress{
Type: v1.NodeHostName,
Address: oVM.Guest.HostName,
},
)
found = true
break
}
}

if found {
@@ -37,6 +37,7 @@ type GRPCServer interface {
// VSphere is an implementation of cloud provider Interface for VSphere.
type VSphere struct {
cfg *vcfg.Config
cpiCfg *CPIConfig
connectionManager *cm.ConnectionManager
nodeManager *NodeManager
informMgr *k8s.InformerManager
@@ -84,6 +85,9 @@ type NodeManager struct {
// NodeLister to track Node properties
nodeLister clientv1.NodeLister

// Reference to CPI-specific configuration
cpiCfg *CPIConfig

// Mutexes
nodeInfoLock sync.RWMutex
nodeRegInfoLock sync.RWMutex

0 comments on commit 5f9f221

Please sign in to comment.
You can’t perform that action at this time.