Skip to content

Commit 75eae02

Browse files
authored
Merge pull request #961 from AbdullahAlShaad/feature/custom-subnet
Fix Cluster Creation in User Provided Subnet
2 parents 810a96d + d6cf2e1 commit 75eae02

File tree

6 files changed

+152
-6
lines changed

6 files changed

+152
-6
lines changed

cloud/services/compute/subnets/reconcile.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func (s *Service) Delete(ctx context.Context) error {
4343
logger := log.FromContext(ctx)
4444
for _, subnetSpec := range s.scope.SubnetSpecs() {
4545
logger.V(2).Info("Deleting a subnet", "name", subnetSpec.Name)
46-
subnetKey := meta.RegionalKey(subnetSpec.Name, s.scope.Region())
46+
subnetKey := meta.RegionalKey(subnetSpec.Name, s.getSubnetRegion(subnetSpec))
4747
err := s.subnets.Delete(ctx, subnetKey)
4848
if err != nil && !gcperrors.IsNotFound(err) {
4949
logger.Error(err, "Error deleting subnet", "name", subnetSpec.Name)
@@ -60,7 +60,7 @@ func (s *Service) createOrGetSubnets(ctx context.Context) ([]*compute.Subnetwork
6060
subnets := []*compute.Subnetwork{}
6161
for _, subnetSpec := range s.scope.SubnetSpecs() {
6262
logger.V(2).Info("Looking for subnet", "name", subnetSpec.Name)
63-
subnetKey := meta.RegionalKey(subnetSpec.Name, s.scope.Region())
63+
subnetKey := meta.RegionalKey(subnetSpec.Name, s.getSubnetRegion(subnetSpec))
6464
subnet, err := s.subnets.Get(ctx, subnetKey)
6565
if err != nil {
6666
if !gcperrors.IsNotFound(err) {
@@ -86,3 +86,11 @@ func (s *Service) createOrGetSubnets(ctx context.Context) ([]*compute.Subnetwork
8686

8787
return subnets, nil
8888
}
89+
90+
// getSubnetRegion returns subnet region if user provided it, otherwise returns default scope region.
91+
func (s *Service) getSubnetRegion(subnetSpec *compute.Subnetwork) string {
92+
if subnetSpec.Region != "" {
93+
return subnetSpec.Region
94+
}
95+
return s.scope.Region()
96+
}

cloud/services/container/clusters/reconcile.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -250,10 +250,10 @@ func (s *Service) createCluster(ctx context.Context, log *logr.Logger) error {
250250
}
251251

252252
isRegional := shared.IsRegional(s.scope.Region())
253-
254253
cluster := &containerpb.Cluster{
255-
Name: s.scope.ClusterName(),
256-
Network: *s.scope.GCPManagedCluster.Spec.Network.Name,
254+
Name: s.scope.ClusterName(),
255+
Network: *s.scope.GCPManagedCluster.Spec.Network.Name,
256+
Subnetwork: s.getSubnetNameInClusterRegion(),
257257
Autopilot: &containerpb.Autopilot{
258258
Enabled: s.scope.GCPManagedControlPlane.Spec.EnableAutopilot,
259259
},
@@ -295,6 +295,16 @@ func (s *Service) createCluster(ctx context.Context, log *logr.Logger) error {
295295
return nil
296296
}
297297

298+
// getSubnetNameInClusterRegion returns the subnet which is in the same region as cluster. If not found it returns empty string.
299+
func (s *Service) getSubnetNameInClusterRegion() string {
300+
for _, subnet := range s.scope.GCPManagedCluster.Spec.Network.Subnets {
301+
if subnet.Region == s.scope.Region() {
302+
return subnet.Name
303+
}
304+
}
305+
return ""
306+
}
307+
298308
func (s *Service) updateCluster(ctx context.Context, updateClusterRequest *containerpb.UpdateClusterRequest, log *logr.Logger) error {
299309
_, err := s.scope.ManagedControlPlaneClient().UpdateCluster(ctx, updateClusterRequest)
300310
if err != nil {

exp/api/v1beta1/gcpmanagedcluster_webhook.go

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/google/go-cmp/cmp"
2121
apierrors "k8s.io/apimachinery/pkg/api/errors"
2222
"k8s.io/apimachinery/pkg/runtime"
23+
kerrors "k8s.io/apimachinery/pkg/util/errors"
2324
"k8s.io/apimachinery/pkg/util/validation/field"
2425
ctrl "sigs.k8s.io/controller-runtime"
2526
logf "sigs.k8s.io/controller-runtime/pkg/log"
@@ -53,7 +54,7 @@ var _ webhook.Validator = &GCPManagedCluster{}
5354
func (r *GCPManagedCluster) ValidateCreate() (admission.Warnings, error) {
5455
gcpmanagedclusterlog.Info("validate create", "name", r.Name)
5556

56-
return nil, nil
57+
return r.validate()
5758
}
5859

5960
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
@@ -96,3 +97,36 @@ func (r *GCPManagedCluster) ValidateDelete() (admission.Warnings, error) {
9697

9798
return nil, nil
9899
}
100+
101+
func (r *GCPManagedCluster) validate() (admission.Warnings, error) {
102+
validators := []func() error{
103+
r.validateCustomSubnet,
104+
}
105+
106+
var errs []error
107+
for _, validator := range validators {
108+
if err := validator(); err != nil {
109+
errs = append(errs, err)
110+
}
111+
}
112+
113+
return nil, kerrors.NewAggregate(errs)
114+
}
115+
116+
func (r *GCPManagedCluster) validateCustomSubnet() error {
117+
gcpmanagedclusterlog.Info("validate custom subnet", "name", r.Name)
118+
if r.Spec.Network.AutoCreateSubnetworks == nil || *r.Spec.Network.AutoCreateSubnetworks {
119+
return nil
120+
}
121+
var isSubnetExistInClusterRegion = false
122+
for _, subnet := range r.Spec.Network.Subnets {
123+
if subnet.Region == r.Spec.Region {
124+
isSubnetExistInClusterRegion = true
125+
}
126+
}
127+
128+
if !isSubnetExistInClusterRegion {
129+
return field.Required(field.NewPath("spec", "network", "subnet"), "at least one given subnets region should be same as spec.network.region when spec.network.autoCreateSubnetworks is false")
130+
}
131+
return nil
132+
}

test/e2e/config/gcp-ci.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ providers:
7171
- sourcePath: "${PWD}/test/e2e/data/infrastructure-gcp/cluster-template-ci-with-creds.yaml"
7272
- sourcePath: "${PWD}/test/e2e/data/infrastructure-gcp/cluster-template-ci-gke.yaml"
7373
- sourcePath: "${PWD}/test/e2e/data/infrastructure-gcp/cluster-template-ci-gke-autopilot.yaml"
74+
- sourcePath: "${PWD}/test/e2e/data/infrastructure-gcp/cluster-template-ci-gke-custom-subnet.yaml"
7475

7576
variables:
7677
KUBERNETES_VERSION: "${KUBERNETES_VERSION:-v1.28.3}"
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
---
2+
apiVersion: cluster.x-k8s.io/v1beta1
3+
kind: Cluster
4+
metadata:
5+
name: "${CLUSTER_NAME}"
6+
spec:
7+
clusterNetwork:
8+
pods:
9+
cidrBlocks: ["192.168.0.0/16"]
10+
infrastructureRef:
11+
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
12+
kind: GCPManagedCluster
13+
name: "${CLUSTER_NAME}"
14+
controlPlaneRef:
15+
kind: GCPManagedControlPlane
16+
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
17+
name: "${CLUSTER_NAME}-control-plane"
18+
---
19+
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
20+
kind: GCPManagedCluster
21+
metadata:
22+
name: "${CLUSTER_NAME}"
23+
spec:
24+
project: "${GCP_PROJECT}"
25+
region: "${GCP_REGION}"
26+
network:
27+
name: "${GCP_NETWORK_NAME}"
28+
autoCreateSubnetworks: false
29+
subnets:
30+
- name: "${GCP_SUBNET_NAME}"
31+
cidrBlock: "${GCP_SUBNET_CIDR}"
32+
region: "${GCP_REGION}"
33+
---
34+
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
35+
kind: GCPManagedControlPlane
36+
metadata:
37+
name: "${CLUSTER_NAME}-control-plane"
38+
spec:
39+
project: "${GCP_PROJECT}"
40+
location: "${GCP_REGION}"
41+
---
42+
apiVersion: cluster.x-k8s.io/v1beta1
43+
kind: MachinePool
44+
metadata:
45+
name: ${CLUSTER_NAME}-mp-0
46+
spec:
47+
clusterName: ${CLUSTER_NAME}
48+
replicas: ${WORKER_MACHINE_COUNT}
49+
template:
50+
spec:
51+
bootstrap:
52+
dataSecretName: ""
53+
clusterName: ${CLUSTER_NAME}
54+
infrastructureRef:
55+
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
56+
kind: GCPManagedMachinePool
57+
name: ${CLUSTER_NAME}-mp-0
58+
---
59+
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
60+
kind: GCPManagedMachinePool
61+
metadata:
62+
name: ${CLUSTER_NAME}-mp-0
63+
spec: {}
64+

test/e2e/e2e_gke_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,33 @@ var _ = Describe("GKE workload cluster creation", func() {
159159
}, result)
160160
})
161161
})
162+
163+
Context("Creating a GKE cluster with custom subnet", func() {
164+
It("Should create a cluster with 3 machine pool and custom subnet", func() {
165+
By("Initializes with 3 machine pool")
166+
167+
ApplyManagedClusterTemplateAndWait(ctx, ApplyManagedClusterTemplateAndWaitInput{
168+
ClusterProxy: bootstrapClusterProxy,
169+
ConfigCluster: clusterctl.ConfigClusterInput{
170+
LogFolder: clusterctlLogFolder,
171+
ClusterctlConfigPath: clusterctlConfigPath,
172+
KubeconfigPath: bootstrapClusterProxy.GetKubeconfigPath(),
173+
InfrastructureProvider: clusterctl.DefaultInfrastructureProvider,
174+
Flavor: "ci-gke-custom-subnet",
175+
Namespace: namespace.Name,
176+
ClusterName: clusterName,
177+
KubernetesVersion: e2eConfig.GetVariable(KubernetesVersion),
178+
ControlPlaneMachineCount: ptr.To[int64](1),
179+
WorkerMachineCount: ptr.To[int64](3),
180+
ClusterctlVariables: map[string]string{
181+
"GCP_SUBNET_NAME": "capg-test-subnet",
182+
"GCP_SUBNET_CIDR": "172.20.0.0/16",
183+
},
184+
},
185+
WaitForClusterIntervals: e2eConfig.GetIntervals(specName, "wait-cluster"),
186+
WaitForControlPlaneIntervals: e2eConfig.GetIntervals(specName, "wait-control-plane"),
187+
WaitForMachinePools: e2eConfig.GetIntervals(specName, "wait-worker-machine-pools"),
188+
}, result)
189+
})
190+
})
162191
})

0 commit comments

Comments
 (0)