Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Nutanix CCM ignore node IPs list #9069

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ spec:
bundle for users that configured their Prism Central with certificates
from non-publicly trusted CAs
type: string
ccmExcludeNodeIPs:
description: CcmExcludeIPs is the optional list of IP addresses that
should be excluded from the CCM IP pool for nodes. List should be
valid IP addresses and IP address ranges.
items:
type: string
type: array
credentialRef:
description: CredentialRef is the reference to the secret name that
contains the credentials for the Nutanix Prism Central. The namespace
Expand Down
5 changes: 5 additions & 0 deletions pkg/api/v1alpha1/nutanixdatacenterconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ type NutanixDatacenterConfigSpec struct {
// FailureDomains is the optional list of failure domains for the Nutanix Datacenter.
// +optional
FailureDomains []NutanixDatacenterFailureDomain `json:"failureDomains,omitempty"`

// CcmExcludeIPs is the optional list of IP addresses that should be excluded from the CCM IP pool for nodes.
// List should be valid IP addresses and IP address ranges.
// +optional
CcmExcludeNodeIPs []string `json:"ccmExcludeNodeIPs,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't make API changes in v0.20 as it would break upgrades from v0.20 to v0.21

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

}

// NutanixDatacenterFailureDomain defines the failure domain for the Nutanix Datacenter.
Expand Down
5 changes: 5 additions & 0 deletions pkg/api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pkg/providers/nutanix/config/cp-template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,8 @@ data:
"enableCustomLabeling": false,
"topologyDiscovery": {
"type": "Prism"
}
},
"ignoredNodeIPs": [{{ range $i, $ip := .ccmIgnoredNodeIPs }}{{ if $i }}, {{ end }}"{{ $ip }}"{{ end }}]
}
---
apiVersion: rbac.authorization.k8s.io/v1
Expand Down
137 changes: 137 additions & 0 deletions pkg/providers/nutanix/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"log"
"net"
"strings"

"sigs.k8s.io/yaml"

Expand Down Expand Up @@ -176,9 +179,12 @@ func buildTemplateMapCP(

failureDomains := generateNutanixFailureDomains(datacenterSpec.FailureDomains)

ccmIgnoredNodeIPs := generateCcmIgnoredNodeIPsList(clusterSpec)

values := map[string]interface{}{
"auditPolicy": auditPolicy,
"apiServerExtraArgs": apiServerExtraArgs.ToPartialYaml(),
"ccmIgnoredNodeIPs": ccmIgnoredNodeIPs,
"cloudProviderImage": versionsBundle.Nutanix.CloudProvider.VersionedImage(),
"clusterName": clusterSpec.Cluster.Name,
"controlPlaneEndpointIp": clusterSpec.Cluster.Spec.ControlPlaneConfiguration.Endpoint.Host,
Expand Down Expand Up @@ -519,3 +525,134 @@ func generateNutanixFailureDomains(eksNutanixFailureDomains []v1alpha1.NutanixDa
}
return failureDomains
}

func incrementIP(ip net.IP) {
for i := len(ip) - 1; i >= 0; i-- {
ip[i]++
if ip[i] > 0 {
break
}
}
}

func compareIP(ip1, ip2 net.IP) (int, error) {
if len(ip1) != len(ip2) {
return -1, fmt.Errorf("IP addresses are not the same protocol")
}

for i := 0; i < len(ip1); i++ {
if ip1[i] < ip2[i] {
return -1, nil
}
if ip1[i] > ip2[i] {
return 1, nil
}
}

return 0, nil
}

func addKubeVipToIgnoredNodeIPsList(clusterSpec *cluster.Spec, result []string) []string {
kubeVipStr := clusterSpec.Cluster.Spec.ControlPlaneConfiguration.Endpoint.Host
if kubeVipStr != "" {
kubeVip, err := net.ResolveIPAddr("ip", kubeVipStr)
if err != nil {
// log error and continue
log.Printf("error resolving kube-vip IP address %s: %v", kubeVipStr, err)
abhinavmpandey08 marked this conversation as resolved.
Show resolved Hide resolved
} else {
result = append(result, kubeVip.IP.String())
}
}

return result
}

func addCIDRToIgnoredNodeIPsList(cidr string, result []string) []string {
ip, ipNet, err := net.ParseCIDR(cidr)
if err != nil {
// log error and continue
log.Printf("error parsing CIDR %s: %v", cidr, err)
return result
}

// Add all ip addresses in the range to the list
for ip := ip.Mask(ipNet.Mask); ipNet.Contains(ip); incrementIP(ip) {
if ip != nil {
result = append(result, ip.String())
}
}

return result
}

func addIPRangeToIgnoredNodeIPsList(ipRangeStr string, result []string) []string {
// Parse the range
ipRange := strings.Split(ipRangeStr, "-")
if len(ipRange) != 2 {
// log error and return
log.Printf("error parsing range %s: expected 2 values, got %d", ipRangeStr, len(ipRange))
return result
}

// Parse the start and end of the range
start := net.ParseIP(strings.TrimSpace(ipRange[0]))
end := net.ParseIP(strings.TrimSpace(ipRange[1]))
if start == nil || end == nil {
// log error and return
log.Printf("error parsing range %s: invalid IP address", ipRangeStr)
return result
}

cmp, err := compareIP(start, end)
if err != nil {
// log error and return
log.Printf("error comparing IP addresses %s and %s: %v", start.String(), end.String(), err)
return result
}

if cmp >= 0 {
// swap start and end if start is greater than end
start, end = end, start
}

// Add all ip addresses in the range to the list
for ip := start; !ip.Equal(end); incrementIP(ip) {
result = append(result, ip.String())
}

result = append(result, end.String())

return result
}

func addIPAddressToIgnoredNodeIPsList(ipAddrStr string, result []string) []string {
ip := net.ParseIP(ipAddrStr)
if ip == nil {
// log error and return
log.Printf("error parsing IP address %s", ipAddrStr)
return result
}

result = append(result, ip.String())
return result
}

func generateCcmIgnoredNodeIPsList(clusterSpec *cluster.Spec) []string {
result := make([]string, 0)

// Add kube-vip to the list
result = addKubeVipToIgnoredNodeIPsList(clusterSpec, result)

for _, IPAddrOrRange := range clusterSpec.NutanixDatacenter.Spec.CcmExcludeNodeIPs {
addrOrRange := strings.TrimSpace(IPAddrOrRange)
if strings.Contains(addrOrRange, "/") {
result = addCIDRToIgnoredNodeIPsList(addrOrRange, result)
} else if strings.Contains(addrOrRange, "-") {
result = addIPRangeToIgnoredNodeIPsList(addrOrRange, result)
} else {
result = addIPAddressToIgnoredNodeIPsList(addrOrRange, result)
}
}

return result
}
86 changes: 86 additions & 0 deletions pkg/providers/nutanix/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,92 @@ func TestTemplateBuilderFailureDomains(t *testing.T) {
}
}

func TestTemplateBuilderCcmExcludeNodeIPs(t *testing.T) {
for _, tc := range []struct {
Input string
Output string
ChangeFn func(clusterSpec *cluster.Spec) *cluster.Spec
}{
{
Input: "testdata/eksa-cluster-ccm-exclude-node-ips.yaml",
Output: "testdata/expected_cluster_ccm_exclude_node_ips.yaml",
ChangeFn: func(clusterSpec *cluster.Spec) *cluster.Spec {
excludeNodeIPs := []string{
"127.100.200.101",
"10.10.10.10-10.10.10.13",
"10.123.0.0/29",
}
clusterSpec.NutanixDatacenter.Spec.CcmExcludeNodeIPs = excludeNodeIPs

return clusterSpec
},
},
{
Input: "testdata/eksa-cluster-ccm-exclude-node-ips.yaml",
Output: "testdata/expected_cluster_ccm_exclude_node_ips.yaml",
ChangeFn: func(clusterSpec *cluster.Spec) *cluster.Spec {
excludeNodeIPs := []string{
"127.100.200.101",
"10.10.10.10-10.10.10.13",
"10.123.0.0/29",
"10.10.10.20-10.10.10.30-10.10.20.30",
}
clusterSpec.NutanixDatacenter.Spec.CcmExcludeNodeIPs = excludeNodeIPs

return clusterSpec
},
},
{
Input: "testdata/eksa-cluster-ccm-exclude-node-ips.yaml",
Output: "testdata/expected_cluster_ccm_exclude_node_ips.yaml",
ChangeFn: func(clusterSpec *cluster.Spec) *cluster.Spec {
excludeNodeIPs := []string{
"127.100.200.101",
"10.10.10.10-10.10.10.13",
"10.123.0.0/29",
"244.244.1",
}
clusterSpec.NutanixDatacenter.Spec.CcmExcludeNodeIPs = excludeNodeIPs

return clusterSpec
},
},
{
Input: "testdata/eksa-cluster-ccm-exclude-node-ips.yaml",
Output: "testdata/expected_cluster_ccm_exclude_node_ips.yaml",
ChangeFn: func(clusterSpec *cluster.Spec) *cluster.Spec {
excludeNodeIPs := []string{
"127.100.200.101",
"10.10.10.10-10.10.10.13",
"10.123.0.0/29",
"10.21.0.5/55",
}
clusterSpec.NutanixDatacenter.Spec.CcmExcludeNodeIPs = excludeNodeIPs

return clusterSpec
},
},
} {
clusterSpec := test.NewFullClusterSpec(t, tc.Input)

machineCfg := clusterSpec.NutanixMachineConfig(clusterSpec.Cluster.Spec.ControlPlaneConfiguration.MachineGroupRef.Name)

t.Setenv(constants.EksaNutanixUsernameKey, "admin")
t.Setenv(constants.EksaNutanixPasswordKey, "password")
creds := GetCredsFromEnv()

clusterSpec = tc.ChangeFn(clusterSpec)

bldr := NewNutanixTemplateBuilder(&clusterSpec.NutanixDatacenter.Spec, &machineCfg.Spec, nil,
map[string]anywherev1.NutanixMachineConfigSpec{}, creds, time.Now)

cpSpec, err := bldr.GenerateCAPISpecControlPlane(clusterSpec)
assert.NoError(t, err)
assert.NotNil(t, cpSpec)
test.AssertContentToFile(t, string(cpSpec), tc.Output)
}
}

func minimalNutanixConfigSpec(t *testing.T) (*anywherev1.NutanixDatacenterConfig, *anywherev1.NutanixMachineConfig, map[string]anywherev1.NutanixMachineConfigSpec) {
dcConf := &anywherev1.NutanixDatacenterConfig{}
err := yaml.Unmarshal([]byte(nutanixDatacenterConfigSpec), dcConf)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ spec:
name: test
count: 1
endpoint:
host: test
host: 10.199.199.1
certSANs: ["foo.bar"]
machineGroupRef:
name: test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ spec:
name: test
count: 1
endpoint:
host: test
host: 10.199.199.1
certSANs: ["11.11.11.11"]
machineGroupRef:
name: test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ spec:
name: test
count: 1
endpoint:
host: test
host: 10.199.199.1
machineGroupRef:
name: test
kind: NutanixMachineConfig
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ spec:
name: test
count: 1
endpoint:
host: test
host: 10.199.199.1
machineGroupRef:
name: test
kind: NutanixMachineConfig
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ spec:
name: test
count: 1
endpoint:
host: test
host: 10.199.199.1
machineGroupRef:
name: test
kind: NutanixMachineConfig
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ spec:
name: eksa-unit-test
count: 3
endpoint:
host: test-ip
host: 10.199.199.1
machineGroupRef:
name: eksa-unit-test
kind: NutanixMachineConfig
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ spec:
name: eksa-unit-test
count: 3
endpoint:
host: test-ip
host: 10.199.199.1
machineGroupRef:
name: eksa-unit-test
kind: NutanixMachineConfig
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ spec:
name: eksa-unit-test
count: 3
endpoint:
host: test-ip
host: 10.199.199.1
machineGroupRef:
name: eksa-unit-test
kind: NutanixMachineConfig
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ spec:
name: eksa-unit-test
count: 3
endpoint:
host: test-ip
host: 10.199.199.1
machineGroupRef:
name: eksa-unit-test
kind: NutanixMachineConfig
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: anywhere.eks.amazonaws.com/v1alpha1
kind: NutanixDatacenterConfig
metadata:
name: eksa-unit-test
namespace: default
spec:
endpoint: "prism.nutanix.com"
port: 9440
credentialRef:
kind: Secret
name: "nutanix-credentials"
ccmExcludeNodeIPs:
- 10.0.0.1
- 10.0.0.0/24
- 10.0.0.10-10.0.0.30
Loading
Loading