Skip to content

Commit 9b5bf4f

Browse files
authored
feat: expose GenerateNoProxy func (#594)
**What problem does this PR solve?**: Exposes generating http no_proxy value. **Which issue(s) this PR fixes**: Fixes # **How Has This Been Tested?**: <!-- Please describe the tests that you ran to verify your changes. Provide output from the tests and any manual steps needed to replicate the tests. --> **Special notes for your reviewer**: <!-- Use this to provide any additional information to the reviewers. This may include: - Best way to review the PR. - Where the author wants the most review attention on. - etc. -->
1 parent b7efa2e commit 9b5bf4f

File tree

7 files changed

+302
-271
lines changed

7 files changed

+302
-271
lines changed

api/v1alpha1/clusterconfig_types.go

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -210,21 +210,6 @@ type Etcd struct {
210210
Image *Image `json:"image,omitempty"`
211211
}
212212

213-
// HTTPProxy required for providing proxy configuration.
214-
type HTTPProxy struct {
215-
// HTTP proxy value.
216-
HTTP string `json:"http,omitempty"`
217-
218-
// HTTPS proxy value.
219-
HTTPS string `json:"https,omitempty"`
220-
221-
// AdditionalNo Proxy list that will be added to the automatically calculated
222-
// values that will apply no_proxy configuration for cluster internal network.
223-
// Default values: localhost,127.0.0.1,<POD_NETWORK>,<SERVICE_NETWORK>,kubernetes
224-
// ,kubernetes.default,.svc,.svc.<SERVICE_DOMAIN>
225-
AdditionalNo []string `json:"additionalNo"`
226-
}
227-
228213
type RegistryCredentials struct {
229214
// A reference to the Secret containing the registry credentials and optional CA certificate
230215
// using the keys `username`, `password` and `ca.crt`.

api/v1alpha1/http_proxy.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// Copyright 2023 D2iQ, Inc. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package v1alpha1
5+
6+
import (
7+
"fmt"
8+
"strings"
9+
10+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
11+
)
12+
13+
const (
14+
// instanceMetadataIP is the IPv4 address used to retrieve
15+
// instance metadata in AWS, Azure, OpenStack, etc.
16+
instanceMetadataIP = "169.254.169.254"
17+
)
18+
19+
// HTTPProxy required for providing proxy configuration.
20+
type HTTPProxy struct {
21+
// HTTP proxy value.
22+
HTTP string `json:"http,omitempty"`
23+
24+
// HTTPS proxy value.
25+
HTTPS string `json:"https,omitempty"`
26+
27+
// AdditionalNo Proxy list that will be added to the automatically calculated
28+
// values that will apply no_proxy configuration for cluster internal network.
29+
// Default values: localhost,127.0.0.1,<POD_NETWORK>,<SERVICE_NETWORK>,kubernetes
30+
// ,kubernetes.default,.svc,.svc.<SERVICE_DOMAIN>
31+
AdditionalNo []string `json:"additionalNo"`
32+
}
33+
34+
// GenerateNoProxy creates default NO_PROXY values that should be applied on cluster
35+
// in any environment and are preventing the use of proxy for cluster internal
36+
// networking. It appends additional values from HTTPProxy.AdditionalNo.
37+
func (p *HTTPProxy) GenerateNoProxy(cluster *clusterv1.Cluster) []string {
38+
noProxy := []string{
39+
"localhost",
40+
"127.0.0.1",
41+
}
42+
43+
if cluster.Spec.ClusterNetwork != nil &&
44+
cluster.Spec.ClusterNetwork.Pods != nil {
45+
noProxy = append(noProxy, cluster.Spec.ClusterNetwork.Pods.CIDRBlocks...)
46+
}
47+
48+
if cluster.Spec.ClusterNetwork != nil &&
49+
cluster.Spec.ClusterNetwork.Services != nil {
50+
noProxy = append(noProxy, cluster.Spec.ClusterNetwork.Services.CIDRBlocks...)
51+
}
52+
53+
serviceDomain := "cluster.local"
54+
if cluster.Spec.ClusterNetwork != nil &&
55+
cluster.Spec.ClusterNetwork.ServiceDomain != "" {
56+
serviceDomain = cluster.Spec.ClusterNetwork.ServiceDomain
57+
}
58+
59+
noProxy = append(
60+
noProxy,
61+
"kubernetes",
62+
"kubernetes.default",
63+
".svc",
64+
// append .svc.<SERVICE_DOMAIN>
65+
fmt.Sprintf(".svc.%s", strings.TrimLeft(serviceDomain, ".")),
66+
)
67+
68+
if cluster.Spec.InfrastructureRef == nil {
69+
return append(noProxy, p.AdditionalNo...)
70+
}
71+
72+
// Add infra-specific entries
73+
switch cluster.Spec.InfrastructureRef.Kind {
74+
case "AWSCluster", "AWSManagedCluster":
75+
noProxy = append(
76+
noProxy,
77+
// Exclude the instance metadata service
78+
instanceMetadataIP,
79+
// Exclude the control plane endpoint
80+
".elb.amazonaws.com",
81+
)
82+
case "AzureCluster", "AzureManagedControlPlane":
83+
noProxy = append(
84+
noProxy,
85+
// Exclude the instance metadata service
86+
instanceMetadataIP,
87+
)
88+
case "GCPCluster":
89+
noProxy = append(
90+
noProxy,
91+
// Exclude the instance metadata service
92+
instanceMetadataIP,
93+
// Exclude aliases for instance metadata service.
94+
// See https://cloud.google.com/vpc/docs/special-configurations
95+
"metadata",
96+
"metadata.google.internal",
97+
)
98+
default:
99+
// Unknown infrastructure. Do nothing.
100+
}
101+
return append(noProxy, p.AdditionalNo...)
102+
}

api/v1alpha1/http_proxy_test.go

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
// Copyright 2023 D2iQ, Inc. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package v1alpha1_test
5+
6+
import (
7+
"testing"
8+
9+
"github.com/onsi/gomega"
10+
v1 "k8s.io/api/core/v1"
11+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
12+
13+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1"
14+
)
15+
16+
func TestGenerateNoProxy(t *testing.T) {
17+
t.Parallel()
18+
19+
testCases := []struct {
20+
name string
21+
cluster *clusterv1.Cluster
22+
expectedNoProxy []string
23+
additonalNo []string
24+
}{{
25+
name: "no networking config",
26+
cluster: &clusterv1.Cluster{},
27+
expectedNoProxy: []string{
28+
"localhost", "127.0.0.1", "kubernetes", "kubernetes.default",
29+
".svc", ".svc.cluster.local",
30+
},
31+
}, {
32+
name: "no networking config with additional no proxy",
33+
cluster: &clusterv1.Cluster{},
34+
additonalNo: []string{"example.com"},
35+
expectedNoProxy: []string{
36+
"localhost", "127.0.0.1", "kubernetes", "kubernetes.default",
37+
".svc", ".svc.cluster.local", "example.com",
38+
},
39+
}, {
40+
name: "custom pod network",
41+
cluster: &clusterv1.Cluster{
42+
Spec: clusterv1.ClusterSpec{
43+
ClusterNetwork: &clusterv1.ClusterNetwork{
44+
Pods: &clusterv1.NetworkRanges{
45+
CIDRBlocks: []string{"10.0.0.0/24", "10.0.1.0/24"},
46+
},
47+
},
48+
},
49+
},
50+
expectedNoProxy: []string{
51+
"localhost", "127.0.0.1", "10.0.0.0/24", "10.0.1.0/24", "kubernetes",
52+
"kubernetes.default", ".svc", ".svc.cluster.local",
53+
},
54+
}, {
55+
name: "Unknown infrastructure cluster",
56+
cluster: &clusterv1.Cluster{
57+
Spec: clusterv1.ClusterSpec{
58+
InfrastructureRef: &v1.ObjectReference{
59+
Kind: "SomeFakeInfrastructureCluster",
60+
},
61+
},
62+
},
63+
expectedNoProxy: []string{
64+
"localhost", "127.0.0.1", "kubernetes", "kubernetes.default",
65+
".svc", ".svc.cluster.local",
66+
},
67+
}, {
68+
name: "AWS cluster",
69+
cluster: &clusterv1.Cluster{
70+
Spec: clusterv1.ClusterSpec{
71+
InfrastructureRef: &v1.ObjectReference{
72+
Kind: "AWSCluster",
73+
},
74+
},
75+
},
76+
expectedNoProxy: []string{
77+
"localhost", "127.0.0.1", "kubernetes", "kubernetes.default",
78+
".svc", ".svc.cluster.local", "169.254.169.254", ".elb.amazonaws.com",
79+
},
80+
}, {
81+
name: "AWS managed (EKS) cluster",
82+
cluster: &clusterv1.Cluster{
83+
Spec: clusterv1.ClusterSpec{
84+
InfrastructureRef: &v1.ObjectReference{
85+
Kind: "AWSManagedCluster",
86+
},
87+
},
88+
},
89+
expectedNoProxy: []string{
90+
"localhost", "127.0.0.1", "kubernetes", "kubernetes.default",
91+
".svc", ".svc.cluster.local", "169.254.169.254", ".elb.amazonaws.com",
92+
},
93+
}, {
94+
name: "Azure cluster",
95+
cluster: &clusterv1.Cluster{
96+
Spec: clusterv1.ClusterSpec{
97+
InfrastructureRef: &v1.ObjectReference{
98+
Kind: "AzureCluster",
99+
},
100+
},
101+
},
102+
expectedNoProxy: []string{
103+
"localhost", "127.0.0.1", "kubernetes", "kubernetes.default",
104+
".svc", ".svc.cluster.local", "169.254.169.254",
105+
},
106+
}, {
107+
name: "Azure managed (AKS) cluster",
108+
cluster: &clusterv1.Cluster{
109+
Spec: clusterv1.ClusterSpec{
110+
InfrastructureRef: &v1.ObjectReference{
111+
Kind: "AzureCluster",
112+
},
113+
},
114+
},
115+
expectedNoProxy: []string{
116+
"localhost", "127.0.0.1", "kubernetes", "kubernetes.default",
117+
".svc", ".svc.cluster.local", "169.254.169.254",
118+
},
119+
}, {
120+
name: "GCP cluster",
121+
cluster: &clusterv1.Cluster{
122+
Spec: clusterv1.ClusterSpec{
123+
InfrastructureRef: &v1.ObjectReference{
124+
Kind: "GCPCluster",
125+
},
126+
},
127+
},
128+
expectedNoProxy: []string{
129+
"localhost", "127.0.0.1", "kubernetes", "kubernetes.default",
130+
".svc", ".svc.cluster.local", "169.254.169.254", "metadata", "metadata.google.internal",
131+
},
132+
}, {
133+
name: "custom service network",
134+
cluster: &clusterv1.Cluster{
135+
Spec: clusterv1.ClusterSpec{
136+
ClusterNetwork: &clusterv1.ClusterNetwork{
137+
Services: &clusterv1.NetworkRanges{
138+
CIDRBlocks: []string{"172.16.0.0/24", "172.16.1.0/24"},
139+
},
140+
},
141+
},
142+
},
143+
expectedNoProxy: []string{
144+
"localhost", "127.0.0.1", "172.16.0.0/24", "172.16.1.0/24", "kubernetes",
145+
"kubernetes.default", ".svc", ".svc.cluster.local",
146+
},
147+
}, {
148+
name: "custom servicedomain",
149+
cluster: &clusterv1.Cluster{
150+
Spec: clusterv1.ClusterSpec{
151+
ClusterNetwork: &clusterv1.ClusterNetwork{
152+
ServiceDomain: "foo.bar",
153+
},
154+
},
155+
},
156+
expectedNoProxy: []string{
157+
"localhost", "127.0.0.1", "kubernetes", "kubernetes.default",
158+
".svc", ".svc.foo.bar",
159+
},
160+
}, {
161+
name: "all options",
162+
cluster: &clusterv1.Cluster{
163+
Spec: clusterv1.ClusterSpec{
164+
ClusterNetwork: &clusterv1.ClusterNetwork{
165+
Pods: &clusterv1.NetworkRanges{
166+
CIDRBlocks: []string{"10.10.0.0/16"},
167+
},
168+
Services: &clusterv1.NetworkRanges{
169+
CIDRBlocks: []string{"172.16.0.0/16"},
170+
},
171+
ServiceDomain: "foo.bar",
172+
},
173+
},
174+
},
175+
additonalNo: []string{"example.com"},
176+
expectedNoProxy: []string{
177+
"localhost", "127.0.0.1", "10.10.0.0/16", "172.16.0.0/16", "kubernetes",
178+
"kubernetes.default", ".svc", ".svc.foo.bar", "example.com",
179+
},
180+
}}
181+
182+
for idx := range testCases {
183+
tt := testCases[idx]
184+
185+
t.Run(tt.name, func(t *testing.T) {
186+
t.Parallel()
187+
188+
g := gomega.NewWithT(t)
189+
190+
g.Expect((&v1alpha1.HTTPProxy{
191+
AdditionalNo: tt.additonalNo,
192+
}).GenerateNoProxy(tt.cluster)).To(gomega.Equal(tt.expectedNoProxy))
193+
})
194+
}
195+
}

0 commit comments

Comments
 (0)