Skip to content

Commit ccd69ae

Browse files
authored
Merge pull request #5721 from serngawy/mainFixRosaNetwork
🐛 ROSA: Fix rosaNetwork set availabilityZones
2 parents 6f867be + 50fe899 commit ccd69ae

File tree

8 files changed

+163
-16
lines changed

8 files changed

+163
-16
lines changed

config/crd/bases/infrastructure.cluster.x-k8s.io_rosanetworks.yaml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,19 +44,26 @@ spec:
4444
description: ROSANetworkSpec defines the desired state of ROSANetwork
4545
properties:
4646
availabilityZoneCount:
47-
default: 1
4847
description: |-
4948
The number of availability zones to be used for creation of the network infrastructure.
5049
You can specify anything between one and four, depending on the chosen AWS region.
50+
Either AvailabilityZoneCount OR AvailabilityZones must be set.
51+
minimum: 1
5152
type: integer
53+
x-kubernetes-validations:
54+
- message: availabilityZoneCount is immutable
55+
rule: self == oldSelf
5256
availabilityZones:
5357
description: |-
5458
The list of availability zones to be used for creation of the network infrastructure.
5559
You can specify anything between one and four valid availability zones from a given region.
56-
Should you specify both the availabilityZoneCount and availabilityZones, the list of availability zones takes preference.
60+
Either AvailabilityZones OR AvailabilityZoneCount must be set.
5761
items:
5862
type: string
5963
type: array
64+
x-kubernetes-validations:
65+
- message: availabilityZones is immutable
66+
rule: self == oldSelf
6067
cidrBlock:
6168
description: CIDR block to be used for the VPC
6269
format: cidr
@@ -85,10 +92,16 @@ spec:
8592
description: The AWS region in which the components of ROSA network
8693
infrastruture are to be crated
8794
type: string
95+
x-kubernetes-validations:
96+
- message: region is immutable
97+
rule: self == oldSelf
8898
stackName:
8999
description: The name of the cloudformation stack under which the
90100
network infrastructure would be created
91101
type: string
102+
x-kubernetes-validations:
103+
- message: stackName is immutable
104+
rule: self == oldSelf
92105
stackTags:
93106
additionalProperties:
94107
type: string

config/rbac/role.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ rules:
214214
- infrastructure.cluster.x-k8s.io
215215
resources:
216216
- rosamachinepools/finalizers
217+
- rosanetworks/finalizers
217218
- rosaroleconfigs/finalizers
218219
verbs:
219220
- update

config/webhook/manifests.yaml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,28 @@ webhooks:
223223
resources:
224224
- rosamachinepools
225225
sideEffects: None
226+
- admissionReviewVersions:
227+
- v1
228+
- v1beta1
229+
clientConfig:
230+
service:
231+
name: webhook-service
232+
namespace: system
233+
path: /mutate-infrastructure-cluster-x-k8s-io-v1beta2-rosanetwork
234+
failurePolicy: Fail
235+
matchPolicy: Equivalent
236+
name: default.rosanetwork.infrastructure.cluster.x-k8s.io
237+
rules:
238+
- apiGroups:
239+
- infrastructure.cluster.x-k8s.io
240+
apiVersions:
241+
- v1beta2
242+
operations:
243+
- CREATE
244+
- UPDATE
245+
resources:
246+
- rosanetworks
247+
sideEffects: None
226248
- admissionReviewVersions:
227249
- v1
228250
- v1beta1
@@ -603,6 +625,28 @@ webhooks:
603625
resources:
604626
- rosamachinepools
605627
sideEffects: None
628+
- admissionReviewVersions:
629+
- v1
630+
- v1beta1
631+
clientConfig:
632+
service:
633+
name: webhook-service
634+
namespace: system
635+
path: /validate-infrastructure-cluster-x-k8s-io-v1beta2-rosanetwork
636+
failurePolicy: Fail
637+
matchPolicy: Equivalent
638+
name: validation.rosanetwork.infrastructure.cluster.x-k8s.io
639+
rules:
640+
- apiGroups:
641+
- infrastructure.cluster.x-k8s.io
642+
apiVersions:
643+
- v1beta2
644+
operations:
645+
- CREATE
646+
- UPDATE
647+
resources:
648+
- rosanetworks
649+
sideEffects: None
606650
- admissionReviewVersions:
607651
- v1
608652
- v1beta1

exp/api/v1beta2/rosanetwork_types.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,41 +29,42 @@ const ROSANetworkFinalizer = "rosanetwork.infrastructure.cluster.x-k8s.io"
2929
// ROSANetworkSpec defines the desired state of ROSANetwork
3030
type ROSANetworkSpec struct {
3131
// The name of the cloudformation stack under which the network infrastructure would be created
32-
// +immutable
32+
// +kubebuilder:validation:XValidation:rule="self == oldSelf", message="stackName is immutable"
33+
// +kubebuilder:validation:Required
3334
StackName string `json:"stackName"`
3435

3536
// The AWS region in which the components of ROSA network infrastruture are to be crated
36-
// +immutable
37+
// +kubebuilder:validation:XValidation:rule="self == oldSelf", message="region is immutable"
38+
// +kubebuilder:validation:Required
3739
Region string `json:"region"`
3840

3941
// The number of availability zones to be used for creation of the network infrastructure.
4042
// You can specify anything between one and four, depending on the chosen AWS region.
41-
// +kubebuilder:default=1
43+
// Either AvailabilityZoneCount OR AvailabilityZones must be set.
44+
// +kubebuilder:validation:Minimum=1
45+
// +kubebuilder:validation:XValidation:rule="self == oldSelf", message="availabilityZoneCount is immutable"
4246
// +optional
43-
// +immutable
44-
AvailabilityZoneCount int `json:"availabilityZoneCount"`
47+
AvailabilityZoneCount int `json:"availabilityZoneCount,omitempty"`
4548

4649
// The list of availability zones to be used for creation of the network infrastructure.
4750
// You can specify anything between one and four valid availability zones from a given region.
48-
// Should you specify both the availabilityZoneCount and availabilityZones, the list of availability zones takes preference.
51+
// Either AvailabilityZones OR AvailabilityZoneCount must be set.
52+
// +kubebuilder:validation:XValidation:rule="self == oldSelf", message="availabilityZones is immutable"
4953
// +optional
50-
// +immutable
51-
AvailabilityZones []string `json:"availabilityZones"`
54+
AvailabilityZones []string `json:"availabilityZones,omitempty"`
5255

5356
// CIDR block to be used for the VPC
5457
// +kubebuilder:validation:Format=cidr
55-
// +immutable
58+
// +kubebuilder:validation:Required
5659
CIDRBlock string `json:"cidrBlock"`
5760

5861
// IdentityRef is a reference to an identity to be used when reconciling rosa network.
5962
// If no identity is specified, the default identity for this controller will be used.
60-
//
6163
// +optional
6264
IdentityRef *infrav1.AWSIdentityReference `json:"identityRef,omitempty"`
6365

6466
// StackTags is an optional set of tags to add to the created cloudformation stack.
6567
// The stack tags will then be automatically applied to the supported AWS resources (VPC, subnets, ...).
66-
//
6768
// +optional
6869
StackTags Tags `json:"stackTags,omitempty"`
6970
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package v1beta2
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
apierrors "k8s.io/apimachinery/pkg/api/errors"
8+
runtime "k8s.io/apimachinery/pkg/runtime"
9+
"k8s.io/apimachinery/pkg/util/validation/field"
10+
ctrl "sigs.k8s.io/controller-runtime"
11+
"sigs.k8s.io/controller-runtime/pkg/webhook"
12+
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
13+
)
14+
15+
// SetupWebhookWithManager will setup the webhooks for the ROSANetwork.
16+
func (r *ROSANetwork) SetupWebhookWithManager(mgr ctrl.Manager) error {
17+
w := new(rosaNetworkWebhook)
18+
return ctrl.NewWebhookManagedBy(mgr).
19+
For(r).
20+
WithValidator(w).
21+
WithDefaulter(w).
22+
Complete()
23+
}
24+
25+
// +kubebuilder:webhook:verbs=create;update,path=/validate-infrastructure-cluster-x-k8s-io-v1beta2-rosanetwork,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=infrastructure.cluster.x-k8s.io,resources=rosanetworks,versions=v1beta2,name=validation.rosanetwork.infrastructure.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1;v1beta1
26+
// +kubebuilder:webhook:verbs=create;update,path=/mutate-infrastructure-cluster-x-k8s-io-v1beta2-rosanetwork,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=infrastructure.cluster.x-k8s.io,resources=rosanetworks,versions=v1beta2,name=default.rosanetwork.infrastructure.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1;v1beta1
27+
28+
type rosaNetworkWebhook struct{}
29+
30+
var _ webhook.CustomDefaulter = &rosaNetworkWebhook{}
31+
var _ webhook.CustomValidator = &rosaNetworkWebhook{}
32+
33+
// ValidateCreate implements admission.Validator.
34+
func (r *rosaNetworkWebhook) ValidateCreate(ctx context.Context, obj runtime.Object) (warnings admission.Warnings, err error) {
35+
rosaNet, ok := obj.(*ROSANetwork)
36+
if !ok {
37+
return nil, fmt.Errorf("expected an ROSANetwork object but got %T", rosaNet)
38+
}
39+
40+
var allErrs field.ErrorList
41+
if rosaNet.Spec.AvailabilityZoneCount == 0 && len(rosaNet.Spec.AvailabilityZones) == 0 {
42+
err := field.Invalid(field.NewPath("spec.AvailabilityZones"), rosaNet.Spec.AvailabilityZones, "Either AvailabilityZones OR AvailabilityZoneCount must be set.")
43+
allErrs = append(allErrs, err)
44+
}
45+
if rosaNet.Spec.AvailabilityZoneCount != 0 && len(rosaNet.Spec.AvailabilityZones) > 0 {
46+
err := field.Invalid(field.NewPath("spec.AvailabilityZones"), rosaNet.Spec.AvailabilityZones, "Either AvailabilityZones OR AvailabilityZoneCount can be set.")
47+
allErrs = append(allErrs, err)
48+
}
49+
50+
if len(allErrs) > 0 {
51+
return nil, apierrors.NewInvalid(
52+
rosaNet.GroupVersionKind().GroupKind(),
53+
rosaNet.Name,
54+
allErrs)
55+
}
56+
57+
return nil, nil
58+
}
59+
60+
// ValidateUpdate implements admission.Validator.
61+
func (r *rosaNetworkWebhook) ValidateUpdate(ctx context.Context, old runtime.Object, updated runtime.Object) (warnings admission.Warnings, err error) {
62+
return nil, nil
63+
}
64+
65+
// ValidateDelete implements admission.Validator.
66+
func (r *rosaNetworkWebhook) ValidateDelete(ctx context.Context, obj runtime.Object) (warnings admission.Warnings, err error) {
67+
return nil, nil
68+
}
69+
70+
// Default implements admission.Defaulter.
71+
func (r *rosaNetworkWebhook) Default(ctx context.Context, obj runtime.Object) error {
72+
return nil
73+
}

exp/controllers/rosanetwork_controller.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ type ROSANetworkReconciler struct {
6060

6161
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=rosanetworks,verbs=get;list;watch;create;update;patch;delete
6262
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=rosanetworks/status,verbs=get;update;patch
63+
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=rosanetworks/finalizers,verbs=update
6364

65+
// Reconcile reconcile ROSANetwork.
6466
func (r *ROSANetworkReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res ctrl.Result, reterr error) {
6567
log := logger.FromContext(ctx)
6668

@@ -136,15 +138,20 @@ func (r *ROSANetworkReconciler) reconcileNormal(ctx context.Context, rosaNetScop
136138

137139
if r.cfStack == nil { // The CF stack does not exist yet
138140
templateBody := string(rosaCFNetwork.CloudFormationTemplateFile)
141+
142+
zoneCount := 1
143+
if rosaNetScope.ROSANetwork.Spec.AvailabilityZoneCount > 0 {
144+
zoneCount = rosaNetScope.ROSANetwork.Spec.AvailabilityZoneCount
145+
}
139146
cfParams := map[string]string{
140-
"AvailabilityZoneCount": strconv.Itoa(rosaNetScope.ROSANetwork.Spec.AvailabilityZoneCount),
147+
"AvailabilityZoneCount": strconv.Itoa(zoneCount),
141148
"Region": rosaNetScope.ROSANetwork.Spec.Region,
142149
"Name": rosaNetScope.ROSANetwork.Spec.StackName,
143150
"VpcCidr": rosaNetScope.ROSANetwork.Spec.CIDRBlock,
144151
}
145152
// Explicitly specified AZs
146-
for i, zone := range rosaNetScope.ROSANetwork.Spec.AvailabilityZones {
147-
cfParams[fmt.Sprintf("AZ%d", i)] = zone
153+
for idx, zone := range rosaNetScope.ROSANetwork.Spec.AvailabilityZones {
154+
cfParams[fmt.Sprintf("AZ%d", (idx+1))] = zone
148155
}
149156

150157
// Call the AWS CF stack create API

exp/controllers/suite_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ func setup() {
8989
if err := (&expinfrav1.ROSARoleConfig{}).SetupWebhookWithManager(testEnv); err != nil {
9090
panic(fmt.Sprintf("Unable to setup ROSARoleConfig webhook: %v", err))
9191
}
92+
if err := (&expinfrav1.ROSANetwork{}).SetupWebhookWithManager(testEnv); err != nil {
93+
panic(fmt.Sprintf("Unable to setup ROSANetwork webhook: %v", err))
94+
}
9295
if err := (&rosacontrolplanev1.ROSAControlPlane{}).SetupWebhookWithManager(testEnv); err != nil {
9396
panic(fmt.Sprintf("Unable to setup ROSAControlPlane webhook: %v", err))
9497
}

main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,11 @@ func main() {
291291
os.Exit(1)
292292
}
293293

294+
if err := (&expinfrav1.ROSANetwork{}).SetupWebhookWithManager(mgr); err != nil {
295+
setupLog.Error(err, "unable to create webhook", "webhook", "ROSANetwork")
296+
os.Exit(1)
297+
}
298+
294299
setupLog.Debug("enabling ROSA role config controller")
295300
if err = (&expcontrollers.ROSARoleConfigReconciler{
296301
Client: mgr.GetClient(),

0 commit comments

Comments
 (0)