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 #9072

Merged
merged 3 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
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 @@ -42,6 +42,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"`
}

// 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.

1 change: 1 addition & 0 deletions pkg/clustermanager/cluster_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ type CAPIClient interface {
GetWorkloadKubeconfig(ctx context.Context, clusterName string, cluster *types.Cluster) ([]byte, error)
}

// AwsIamAuth performs operations with AWS IAM.
type AwsIamAuth interface {
CreateAndInstallAWSIAMAuthCASecret(ctx context.Context, managementCluster *types.Cluster, workloadClusterName string) error
InstallAWSIAMAuth(ctx context.Context, management, workload *types.Cluster, spec *cluster.Spec) error
Expand Down
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
121 changes: 121 additions & 0 deletions pkg/providers/nutanix/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
"encoding/base64"
"encoding/json"
"fmt"
"log"
"net"
"strings"

"sigs.k8s.io/yaml"

Expand Down Expand Up @@ -176,9 +179,12 @@

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 @@ -568,3 +574,118 @@
}
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")
}

Check warning on line 590 in pkg/providers/nutanix/template.go

View check run for this annotation

Codecov / codecov/patch

pkg/providers/nutanix/template.go#L589-L590

Added lines #L589 - L590 were not covered by tests

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

Check warning on line 601 in pkg/providers/nutanix/template.go

View check run for this annotation

Codecov / codecov/patch

pkg/providers/nutanix/template.go#L601

Added line #L601 was not covered by tests
}

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
}
Copy link
Member

Choose a reason for hiding this comment

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

We are already validating this in the validator. Let's remove it from here.

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


// 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
}

Check warning on line 638 in pkg/providers/nutanix/template.go

View check run for this annotation

Codecov / codecov/patch

pkg/providers/nutanix/template.go#L635-L638

Added lines #L635 - L638 were not covered by tests

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
}

Check warning on line 645 in pkg/providers/nutanix/template.go

View check run for this annotation

Codecov / codecov/patch

pkg/providers/nutanix/template.go#L642-L645

Added lines #L642 - L645 were not covered by tests

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

Check warning on line 650 in pkg/providers/nutanix/template.go

View check run for this annotation

Codecov / codecov/patch

pkg/providers/nutanix/template.go#L648-L650

Added lines #L648 - L650 were not covered by tests
Copy link
Member

Choose a reason for hiding this comment

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

same as above, already validated in validator, can be removed

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


// 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
}
Copy link
Member

Choose a reason for hiding this comment

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

here as well, already validated, can be removed

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


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

func generateCcmIgnoredNodeIPsList(clusterSpec *cluster.Spec) []string {
// Add the kube-vip IP address to the list
result := []string{clusterSpec.Cluster.Spec.ControlPlaneConfiguration.Endpoint.Host}

// Add the IP addresses, IP ranges and CIDRs to the list from the NutanixDatacenter spec CcmExcludeNodeIPs
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 @@ -848,6 +848,92 @@ func TestTemplateBuilderGPUs(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