Skip to content

Commit 5ebb36b

Browse files
Merge branch 'openshift:main' into nutanixInfraChange
2 parents a2bae3d + 140a1fa commit 5ebb36b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+4257
-620
lines changed

.ci-operator.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
build_root_image:
22
name: release
33
namespace: openshift
4-
tag: rhel-9-release-golang-1.24-openshift-4.20
4+
tag: rhel-9-release-golang-1.24-openshift-4.21

Dockerfile.rhel

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
FROM registry.ci.openshift.org/ocp/builder:rhel-9-golang-1.24-openshift-4.20 AS builder
1+
FROM registry.ci.openshift.org/ocp/builder:rhel-9-golang-1.24-openshift-4.21 AS builder
22
WORKDIR /go/src/github.com/openshift/cluster-capi-operator
33
COPY . .
44
RUN make build
55

6-
FROM registry.ci.openshift.org/ocp/4.20:base-rhel9
6+
FROM registry.ci.openshift.org/ocp/4.21:base-rhel9
77
COPY --from=builder /go/src/github.com/openshift/cluster-capi-operator/bin/cluster-capi-operator .
88
COPY --from=builder /go/src/github.com/openshift/cluster-capi-operator/bin/machine-api-migration .
99
COPY --from=builder /go/src/github.com/openshift/cluster-capi-operator/manifests /manifests

cmd/cluster-capi-operator/main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,11 @@ func getDefaultCacheOptions(capiNamespace string, sync time.Duration) cache.Opti
419419
defaultMachineAPINamespace: {},
420420
},
421421
},
422+
&mapiv1beta1.Machine{}: {
423+
Namespaces: map[string]cache.Config{
424+
defaultMachineAPINamespace: {},
425+
},
426+
},
422427
},
423428
}
424429
}

manifests-gen/customizations.go

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -62,20 +62,13 @@ func processObjects(objs []unstructured.Unstructured, providerName string) map[r
6262
setNoUpgradeAnnotations(obj)
6363
providerConfigMapObjs = append(providerConfigMapObjs, obj)
6464
case "MutatingWebhookConfiguration":
65-
// Explicitly remove defaulting webhooks for the cluster-api provider.
66-
// We don't need CAPI to set any default to the cluster object because
67-
// we have a custom controller for reconciling it.
68-
// For more information: https://issues.redhat.com/browse/OCPCLOUD-1506
69-
removeClusterDefaultingWebhooks(&obj)
7065
replaceCertManagerAnnotations(&obj)
7166
providerConfigMapObjs = append(providerConfigMapObjs, obj)
7267
case "ValidatingWebhookConfiguration":
73-
removeClusterValidatingWebhooks(&obj)
7468
replaceCertManagerAnnotations(&obj)
7569
providerConfigMapObjs = append(providerConfigMapObjs, obj)
7670
case "CustomResourceDefinition":
7771
replaceCertManagerAnnotations(&obj)
78-
removeConversionWebhook(&obj)
7972
setOpenShiftAnnotations(obj, true)
8073
// Apply NoUpgrade annotations unless IPAM CRDs,
8174
// as those are in General Availability.
@@ -276,17 +269,6 @@ func replaceCertMangerServiceSecret(obj *unstructured.Unstructured, serviceSecre
276269
}
277270
}
278271

279-
func removeConversionWebhook(obj *unstructured.Unstructured) {
280-
crd := &apiextensionsv1.CustomResourceDefinition{}
281-
if err := scheme.Convert(obj, crd, nil); err != nil {
282-
panic(err)
283-
}
284-
crd.Spec.Conversion = nil
285-
if err := scheme.Convert(crd, obj, nil); err != nil {
286-
panic(err)
287-
}
288-
}
289-
290272
// isCRDGroup checks whether the object provided is a CRD for the specified API group.
291273
func isCRDGroup(obj *unstructured.Unstructured, group string) bool {
292274
switch obj.GetKind() {

manifests-gen/providercustomizations.go

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package main
22

33
import (
4-
"regexp"
5-
6-
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
74
appsv1 "k8s.io/api/apps/v1"
85
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
96
)
@@ -105,63 +102,3 @@ func powerVSCustomizations(obj *unstructured.Unstructured) {
105102
}
106103
}
107104
}
108-
109-
func removeClusterDefaultingWebhooks(obj *unstructured.Unstructured) {
110-
var providerWebhooks = regexp.MustCompile(`^default\.[a-z]+cluster[a-z]*\.infrastructure\.cluster\.x-k8s\.io$`)
111-
112-
mutatingWebhookConfiguration := &admissionregistrationv1.MutatingWebhookConfiguration{}
113-
if err := scheme.Convert(obj, mutatingWebhookConfiguration, nil); err != nil {
114-
panic(err)
115-
}
116-
117-
webhooks := []admissionregistrationv1.MutatingWebhook{}
118-
for _, webhook := range mutatingWebhookConfiguration.Webhooks {
119-
// We don't need these specific webhooks.
120-
if webhook.Name == "default.cluster.cluster.x-k8s.io" || webhook.Name == "default.clusterclass.cluster.x-k8s.io" || webhook.Name == "default.clusterresourceset.addons.cluster.x-k8s.io" {
121-
continue
122-
}
123-
124-
// We also don't need provider webhooks for clusters.
125-
if providerWebhooks.MatchString(webhook.Name) {
126-
continue
127-
}
128-
129-
webhooks = append(webhooks, webhook)
130-
}
131-
132-
mutatingWebhookConfiguration.Webhooks = webhooks
133-
134-
if err := scheme.Convert(mutatingWebhookConfiguration, obj, nil); err != nil {
135-
panic(err)
136-
}
137-
}
138-
139-
func removeClusterValidatingWebhooks(obj *unstructured.Unstructured) {
140-
var providerWebhooks = regexp.MustCompile(`^validation\.[a-z]+cluster[a-z]*\.infrastructure\.cluster\.x-k8s\.io$`)
141-
142-
validatingWebhookConfiguration := &admissionregistrationv1.ValidatingWebhookConfiguration{}
143-
if err := scheme.Convert(obj, validatingWebhookConfiguration, nil); err != nil {
144-
panic(err)
145-
}
146-
147-
webhooks := []admissionregistrationv1.ValidatingWebhook{}
148-
for _, webhook := range validatingWebhookConfiguration.Webhooks {
149-
// We don't need these specific webhooks.
150-
if webhook.Name == "validation.cluster.cluster.x-k8s.io" || webhook.Name == "validation.clusterclass.cluster.x-k8s.io" || webhook.Name == "default.clusterresourceset.addons.cluster.x-k8s.io" {
151-
continue
152-
}
153-
154-
// We also don't need provider webhooks for clusters.
155-
if providerWebhooks.MatchString(webhook.Name) {
156-
continue
157-
}
158-
159-
webhooks = append(webhooks, webhook)
160-
}
161-
162-
validatingWebhookConfiguration.Webhooks = webhooks
163-
164-
if err := scheme.Convert(validatingWebhookConfiguration, obj, nil); err != nil {
165-
panic(err)
166-
}
167-
}

manifests/0000_30_cluster-api_09_admission-policies.yaml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,40 @@ data:
236236
policyName: openshift-only-create-mapi-machine-if-authoritative-api-capi
237237
validationActions:
238238
- Deny
239+
---
240+
apiVersion: admissionregistration.k8s.io/v1
241+
kind: ValidatingAdmissionPolicy
242+
metadata:
243+
name: openshift-prevent-migration-when-machine-updating
244+
spec:
245+
failurePolicy: Fail
246+
247+
matchConstraints:
248+
resourceRules:
249+
- apiGroups: ["machine.openshift.io"]
250+
apiVersions: ["*"]
251+
operations: ["UPDATE"]
252+
resources: ["machines"]
253+
254+
# All validations must evaluate to true
255+
validations:
256+
- expression: '!(has(object.status) && has(object.status.phase) && object.status.phase == "Provisioning" && (oldObject.spec.authoritativeAPI != object.spec.authoritativeAPI))'
257+
message: 'Cannot update .spec.authoritativeAPI when machine is in Provisioning phase'
258+
- expression: '!(has(object.metadata.deletionTimestamp) && (oldObject.spec.authoritativeAPI != object.spec.authoritativeAPI))'
259+
message: 'Cannot update .spec.authoritativeAPI when machine has a non-zero deletion timestamp'
260+
---
261+
apiVersion: admissionregistration.k8s.io/v1
262+
kind: ValidatingAdmissionPolicyBinding
263+
metadata:
264+
name: openshift-prevent-migration-when-machine-updating
265+
spec:
266+
matchResources:
267+
namespaceSelector:
268+
matchLabels:
269+
kubernetes.io/metadata.name: openshift-machine-api
270+
policyName: openshift-prevent-migration-when-machine-updating
271+
validationActions:
272+
- Deny
239273
---
240274
apiVersion: v1
241275
kind: ConfigMap

pkg/controllers/infracluster/aws.go

Lines changed: 120 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,34 +17,50 @@ package infracluster
1717

1818
import (
1919
"context"
20+
"errors"
2021
"fmt"
2122
"net/url"
2223
"strconv"
24+
"strings"
2325

2426
"github.com/go-logr/logr"
2527
cerrors "k8s.io/apimachinery/pkg/api/errors"
2628
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29+
"k8s.io/klog/v2"
2730
awsv1 "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
2831
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
2932
"sigs.k8s.io/controller-runtime/pkg/client"
33+
34+
mapiv1beta1 "github.com/openshift/api/machine/v1beta1"
35+
)
36+
37+
var (
38+
// ErrNoControlPlaneLoadBalancerConfigured indicates there is no control plane load balancer configuration present.
39+
ErrNoControlPlaneLoadBalancerConfigured = errors.New("no control plane load balancer configured")
40+
// ErrNilProviderSpec indicates a nil provider spec raw extension.
41+
ErrNilProviderSpec = errors.New("provider spec is nil")
42+
// ErrInvalidNumberOfControlPlaneLoadBalancers indicates an invalid number of control plane load balancers has been configured.
43+
ErrInvalidNumberOfControlPlaneLoadBalancers = errors.New("invalid number of control plane load balancers")
44+
// ErrUnsupportedLoadBalancerType indicates an unsupported load balancer type.
45+
ErrUnsupportedLoadBalancerType = errors.New("unsupported load balancer type")
3046
)
3147

3248
// ensureAWSCluster ensures the AWSCluster cluster object exists.
3349
func (r *InfraClusterController) ensureAWSCluster(ctx context.Context, log logr.Logger) (client.Object, error) {
34-
target := &awsv1.AWSCluster{ObjectMeta: metav1.ObjectMeta{
50+
awsCluster := &awsv1.AWSCluster{ObjectMeta: metav1.ObjectMeta{
3551
Name: r.Infra.Status.InfrastructureName,
36-
Namespace: defaultCAPINamespace,
52+
Namespace: r.CAPINamespace,
3753
}}
3854

3955
// Checking whether InfraCluster object exists. If it doesn't, create it.
40-
41-
if err := r.Get(ctx, client.ObjectKeyFromObject(target), target); err != nil && !cerrors.IsNotFound(err) {
56+
if err := r.Get(ctx, client.ObjectKeyFromObject(awsCluster), awsCluster); err != nil && !cerrors.IsNotFound(err) {
4257
return nil, fmt.Errorf("failed to get InfraCluster: %w", err)
4358
} else if err == nil {
44-
return target, nil
59+
return awsCluster, nil
4560
}
4661

47-
log.Info(fmt.Sprintf("AWSCluster %s/%s does not exist, creating it", target.Namespace, target.Name))
62+
log = log.WithValues("AWSCluster", klog.KObj(awsCluster))
63+
log.Info("AWSCluster does not exist, creating it")
4864

4965
apiURL, err := url.Parse(r.Infra.Status.APIServerInternalURL)
5066
if err != nil {
@@ -60,10 +76,35 @@ func (r *InfraClusterController) ensureAWSCluster(ctx context.Context, log logr.
6076
return nil, fmt.Errorf("infrastructure PlatformStatus should not be nil: %w", err)
6177
}
6278

63-
target = &awsv1.AWSCluster{
79+
providerSpec, err := r.getAWSMAPIProviderSpec(ctx, r.Client)
80+
if err != nil {
81+
return nil, fmt.Errorf("unable to obtain MAPI ProviderSpec: %w", err)
82+
}
83+
84+
awsCluster, err = r.newAWSCluster(providerSpec, apiURL, int32(port))
85+
if err != nil {
86+
return nil, fmt.Errorf("failed to get AWSCluster: %w", err)
87+
}
88+
89+
if err := r.Create(ctx, awsCluster); err != nil {
90+
return nil, fmt.Errorf("failed to create AWSCluster: %w", err)
91+
}
92+
93+
log.Info("AWSCluster successfully created")
94+
95+
return awsCluster, nil
96+
}
97+
98+
func (r *InfraClusterController) newAWSCluster(providerSpec *mapiv1beta1.AWSMachineProviderConfig, apiURL *url.URL, port int32) (*awsv1.AWSCluster, error) {
99+
controlPlaneLoadBalancer, secondaryControlPlaneLoadBalancer, err := extractLoadBalancerConfigFromMAPIAWSProviderSpec(providerSpec)
100+
if err != nil {
101+
return nil, fmt.Errorf("failed to extract control plane load balancer configuration: %w", err)
102+
}
103+
104+
target := &awsv1.AWSCluster{
64105
ObjectMeta: metav1.ObjectMeta{
65106
Name: r.Infra.Status.InfrastructureName,
66-
Namespace: defaultCAPINamespace,
107+
Namespace: r.CAPINamespace,
67108
// The ManagedBy Annotation is set so CAPI infra providers ignore the InfraCluster object,
68109
// as that's managed externally, in this case by this controller.
69110
Annotations: map[string]string{
@@ -74,7 +115,7 @@ func (r *InfraClusterController) ensureAWSCluster(ctx context.Context, log logr.
74115
Region: r.Infra.Status.PlatformStatus.AWS.Region,
75116
ControlPlaneEndpoint: clusterv1.APIEndpoint{
76117
Host: apiURL.Hostname(),
77-
Port: int32(port),
118+
Port: port,
78119
},
79120
// This default IdentityRef will be created by the controlleridentitycreator controller.
80121
// Leaving it as nil works the same as this value, but fills the log with log messages
@@ -84,14 +125,80 @@ func (r *InfraClusterController) ensureAWSCluster(ctx context.Context, log logr.
84125
Kind: awsv1.ControllerIdentityKind,
85126
Name: "default",
86127
},
128+
// Set control plane load balancer configuration extracted from MAPI machines
129+
ControlPlaneLoadBalancer: controlPlaneLoadBalancer,
130+
SecondaryControlPlaneLoadBalancer: secondaryControlPlaneLoadBalancer,
87131
},
88132
}
89133

90-
if err := r.Create(ctx, target); err != nil {
91-
return nil, fmt.Errorf("failed to create InfraCluster: %w", err)
134+
return target, nil
135+
}
136+
137+
func (r *InfraClusterController) getAWSMAPIProviderSpec(ctx context.Context, cl client.Client) (*mapiv1beta1.AWSMachineProviderConfig, error) {
138+
return getMAPIProviderSpec[mapiv1beta1.AWSMachineProviderConfig](ctx, cl, r.getRawMAPIProviderSpec)
139+
}
140+
141+
// extractLoadBalancerConfigFromMAPIAWSProviderSpec extracts one or two control plane load balancers from a MAPI machine's provider spec.
142+
// When two load balancers are present, the one whose name ends with "-int" is preferred as the return value.
143+
// Returns an error if zero or more than two load balancers are defined.
144+
func extractLoadBalancerConfigFromMAPIAWSProviderSpec(providerSpec *mapiv1beta1.AWSMachineProviderConfig) (*awsv1.AWSLoadBalancerSpec, *awsv1.AWSLoadBalancerSpec, error) {
145+
if providerSpec == nil {
146+
return nil, nil, ErrNilProviderSpec
92147
}
93148

94-
log.Info(fmt.Sprintf("InfraCluster '%s/%s' successfully created", defaultCAPINamespace, r.Infra.Status.InfrastructureName))
149+
switch len(providerSpec.LoadBalancers) {
150+
case 0:
151+
return nil, nil, ErrNoControlPlaneLoadBalancerConfigured
152+
case 1:
153+
lbPrimary := providerSpec.LoadBalancers[0]
154+
155+
lbType, err := convertMAPILoadBalancerTypeToCAPI(lbPrimary.Type)
156+
if err != nil {
157+
return nil, nil, fmt.Errorf("failed to convert load balancer type: %w", err)
158+
}
159+
160+
return &awsv1.AWSLoadBalancerSpec{
161+
Name: &lbPrimary.Name,
162+
LoadBalancerType: lbType,
163+
}, nil, nil
164+
case 2:
165+
lbFirst := providerSpec.LoadBalancers[0]
166+
lbSecond := providerSpec.LoadBalancers[1]
167+
// Prefer the load balancer with "-int" suffix as primary when two are present.
168+
if strings.HasSuffix(lbSecond.Name, "-int") && !strings.HasSuffix(lbFirst.Name, "-int") {
169+
lbFirst, lbSecond = lbSecond, lbFirst
170+
}
171+
172+
lbTypeFirst, err := convertMAPILoadBalancerTypeToCAPI(lbFirst.Type)
173+
if err != nil {
174+
return nil, nil, fmt.Errorf("failed to convert load balancer type: %w", err)
175+
}
176+
177+
lbTypeSecond, err := convertMAPILoadBalancerTypeToCAPI(lbSecond.Type)
178+
if err != nil {
179+
return nil, nil, fmt.Errorf("failed to convert load balancer type: %w", err)
180+
}
181+
182+
return &awsv1.AWSLoadBalancerSpec{
183+
Name: &lbFirst.Name,
184+
LoadBalancerType: lbTypeFirst,
185+
}, &awsv1.AWSLoadBalancerSpec{
186+
Name: &lbSecond.Name,
187+
LoadBalancerType: lbTypeSecond,
188+
}, nil
189+
default:
190+
return nil, nil, fmt.Errorf("%w: expected 1 or 2, got %d", ErrInvalidNumberOfControlPlaneLoadBalancers, len(providerSpec.LoadBalancers))
191+
}
192+
}
95193

96-
return target, nil
194+
// convertMAPILoadBalancerTypeToCAPI converts MAPI AWSLoadBalancerType to CAPI LoadBalancerType.
195+
func convertMAPILoadBalancerTypeToCAPI(mapiType mapiv1beta1.AWSLoadBalancerType) (awsv1.LoadBalancerType, error) {
196+
switch mapiType {
197+
case mapiv1beta1.ClassicLoadBalancerType:
198+
return awsv1.LoadBalancerTypeClassic, nil
199+
case mapiv1beta1.NetworkLoadBalancerType:
200+
return awsv1.LoadBalancerTypeNLB, nil
201+
default:
202+
return "", fmt.Errorf("%w: unknown load balancer type: %s", ErrUnsupportedLoadBalancerType, mapiType)
203+
}
97204
}

0 commit comments

Comments
 (0)