Skip to content

Commit 24086c8

Browse files
Merge pull request #96 from CrystalChun/capabilities
MGMT-20013: Allow user-specified capabilities when installing a workload cluster
2 parents 2be8e50 + e0b0c1c commit 24086c8

6 files changed

+408
-5
lines changed

Diff for: controlplane/api/v1alpha2/openshiftassistedcontrolplane_types.go

+16
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,22 @@ type OpenshiftAssistedControlPlaneConfigSpec struct {
129129
// ImageRegistryRef is a reference to a configmap containing both the additional
130130
// image registries and their corresponding certificate bundles to be used in the spoke cluster
131131
ImageRegistryRef *corev1.LocalObjectReference `json:"imageRegistryRef,omitempty"`
132+
133+
// Capabilities specifies the capabilities set during an OpenShift cluster installation.
134+
Capabilities Capabilities `json:"capabilities,omitempty"`
135+
}
136+
137+
type Capabilities struct {
138+
// BaselineCapability provides a default set of capabilities to enable during the installation.
139+
// Valid values are vCurrent, v4.x, or None. See the OpenShift doc for more details.
140+
// Defaults to None for baremetal platform workload clusters or vCurrent otherwise.
141+
// +optional
142+
BaselineCapability string `json:"baselineCapability,omitempty"`
143+
144+
// AdditionalEnabledCapabilities is a list of OpenShift capabilities to specifically enable
145+
// during the installation of the workload cluster. It is empty by default.
146+
// +optional
147+
AdditionalEnabledCapabilities []string `json:"additionalEnabledCapabilities,omitempty"`
132148
}
133149

134150
// OpenshiftAssistedControlPlaneStatus defines the observed state of OpenshiftAssistedControlPlane

Diff for: controlplane/api/v1alpha2/zz_generated.deepcopy.go

+21
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: controlplane/config/crd/bases/controlplane.cluster.x-k8s.io_openshiftassistedcontrolplanes.yaml

+18
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,24 @@ spec:
106106
description: BaseDomain is the base domain to which the cluster
107107
should belong.
108108
type: string
109+
capabilities:
110+
description: Capabilities specifies the capabilities set during
111+
an OpenShift cluster installation.
112+
properties:
113+
additionalEnabledCapabilities:
114+
description: |-
115+
AdditionalEnabledCapabilities is a list of OpenShift capabilities to specifically enable
116+
during the installation of the workload cluster. It is empty by default.
117+
items:
118+
type: string
119+
type: array
120+
baselineCapability:
121+
description: |-
122+
BaselineCapability provides a default set of capabilities to enable during the installation.
123+
Valid values are vCurrent, v4.x, or None. See the OpenShift doc for more details.
124+
Defaults to None for baremetal platform workload clusters or vCurrent otherwise.
125+
type: string
126+
type: object
109127
clusterName:
110128
description: |-
111129
ClusterName is the friendly name of the cluster. It is used for subdomains,

Diff for: controlplane/internal/controller/clusterdeployment_controller.go

+103-4
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,25 @@ package controller
1818

1919
import (
2020
"context"
21+
"encoding/json"
22+
"fmt"
23+
"regexp"
24+
"slices"
25+
"strings"
2126

2227
controlplanev1alpha2 "github.com/openshift-assisted/cluster-api-agent/controlplane/api/v1alpha2"
2328
"github.com/openshift-assisted/cluster-api-agent/controlplane/internal/imageregistry"
2429
"github.com/openshift-assisted/cluster-api-agent/controlplane/internal/release"
2530
"github.com/openshift-assisted/cluster-api-agent/util"
2631
logutil "github.com/openshift-assisted/cluster-api-agent/util/log"
32+
2733
configv1 "github.com/openshift/api/config/v1"
2834
hiveext "github.com/openshift/assisted-service/api/hiveextension/v1beta1"
2935
aiv1beta1 "github.com/openshift/assisted-service/api/v1beta1"
3036
hivev1 "github.com/openshift/hive/apis/hive/v1"
37+
3138
corev1 "k8s.io/api/core/v1"
39+
"k8s.io/apimachinery/pkg/api/equality"
3240
apierrors "k8s.io/apimachinery/pkg/api/errors"
3341
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3442
"k8s.io/apimachinery/pkg/runtime"
@@ -40,7 +48,13 @@ import (
4048
)
4149

4250
const (
43-
InstallConfigOverrides = aiv1beta1.Group + "/install-config-overrides"
51+
InstallConfigOverrides = aiv1beta1.Group + "/install-config-overrides"
52+
defaultBaremetalBaselineCapability = "None"
53+
defaultBaselineCapability = "vCurrent"
54+
)
55+
56+
var (
57+
defaultBaremetalAdditionalCapabilities = []configv1.ClusterVersionCapability{"baremetal", "Console", "Insights", "OperatorLifecycleManager", "Ingress"}
4458
)
4559

4660
// ClusterDeploymentReconciler reconciles a ClusterDeployment object
@@ -250,9 +264,9 @@ func (r *ClusterDeploymentReconciler) computeAgentClusterInstall(
250264
aci.Spec.APIVIPs = acp.Spec.Config.APIVIPs
251265
aci.Spec.IngressVIPs = acp.Spec.Config.IngressVIPs
252266
aci.Spec.PlatformType = hiveext.PlatformType(configv1.BareMetalPlatformType)
253-
aci.Annotations = map[string]string{
254-
InstallConfigOverrides: `{"capabilities": {"baselineCapabilitySet": "None", "additionalEnabledCapabilities": ["baremetal","Console","Insights","OperatorLifecycleManager","Ingress"]}}"`,
255-
}
267+
}
268+
if err := setACICapabilities(&acp, aci); err != nil {
269+
return nil, err
256270
}
257271
return aci, nil
258272
}
@@ -273,3 +287,88 @@ func (r *ClusterDeploymentReconciler) createImageRegistry(ctx context.Context, r
273287
}
274288
return nil
275289
}
290+
291+
type InstallConfigOverride struct {
292+
Capability configv1.ClusterVersionCapabilitiesSpec `json:"capabilities,omitempty"`
293+
}
294+
295+
// setACICapabilities will set the install config override annotation in the AgentClusterInstall if there
296+
// are additional enabled capabilities that need to be defined.
297+
// For SNO (single node openshift) and non-baremetal platform MNO (multi-node openshift), this is set if
298+
// the OpenshiftAssistedControlPlane has additional capabilities set.
299+
// For MNO (multi-node openshift), this is set to the default list for baremetal platform,
300+
// but the OpenshiftAssistedControlPlane can specify additional capabilities to be appended to this list.
301+
func setACICapabilities(oacp *controlplanev1alpha2.OpenshiftAssistedControlPlane, aci *hiveext.AgentClusterInstall) error {
302+
isBaremetalPlatform := aci.Spec.PlatformType == hiveext.BareMetalPlatformType
303+
if isCapabilitiesEmpty(oacp.Spec.Config.Capabilities) && !isBaremetalPlatform {
304+
return nil
305+
}
306+
var installCfgOverride InstallConfigOverride
307+
baselineCapability, err := getBaselineCapability(oacp.Spec.Config.Capabilities.BaselineCapability, isBaremetalPlatform)
308+
if err != nil {
309+
return err
310+
}
311+
installCfgOverride.Capability.BaselineCapabilitySet = configv1.ClusterVersionCapabilitySet(baselineCapability)
312+
313+
additionalEnabledCapabilities := getAdditionalCapabilities(oacp.Spec.Config.Capabilities.AdditionalEnabledCapabilities, isBaremetalPlatform)
314+
installCfgOverride.Capability.AdditionalEnabledCapabilities = additionalEnabledCapabilities
315+
316+
installCfgOverrideStr, err := json.Marshal(installCfgOverride)
317+
if err != nil {
318+
return err
319+
}
320+
321+
if aci.Annotations == nil {
322+
aci.Annotations = make(map[string]string)
323+
}
324+
325+
aci.Annotations[InstallConfigOverrides] = string(installCfgOverrideStr)
326+
return nil
327+
}
328+
329+
func getBaselineCapability(capability string, isBaremetalPlatform bool) (string, error) {
330+
baselineCapability := capability
331+
if baselineCapability == "None" || baselineCapability == "vCurrent" {
332+
return baselineCapability, nil
333+
}
334+
335+
if baselineCapability == "" {
336+
baselineCapability = defaultBaselineCapability
337+
if isBaremetalPlatform {
338+
baselineCapability = defaultBaremetalBaselineCapability
339+
}
340+
return baselineCapability, nil
341+
}
342+
343+
var baselineCapabilityRegexp = regexp.MustCompile(`v4\.[0-9]+`)
344+
if !baselineCapabilityRegexp.MatchString(baselineCapability) {
345+
return "",
346+
fmt.Errorf("invalid baseline capability set, must be one of: None, vCurrent, or v4.x. Got: [%s]", baselineCapability)
347+
}
348+
return baselineCapability, nil
349+
}
350+
351+
func getAdditionalCapabilities(specifiedAdditionalCapabilities []string, isBaremetalPlatform bool) []configv1.ClusterVersionCapability {
352+
additionalCapabilitiesList := []configv1.ClusterVersionCapability{}
353+
if isBaremetalPlatform {
354+
additionalCapabilitiesList = append([]configv1.ClusterVersionCapability{}, defaultBaremetalAdditionalCapabilities...)
355+
}
356+
357+
for _, capability := range specifiedAdditionalCapabilities {
358+
// Ignore MAPI for baremetal MNO clusters and ignore duplicates
359+
if (strings.EqualFold(capability, "MachineAPI") && isBaremetalPlatform) || slices.Contains(additionalCapabilitiesList, configv1.ClusterVersionCapability(capability)) {
360+
continue
361+
}
362+
additionalCapabilitiesList = append(additionalCapabilitiesList, configv1.ClusterVersionCapability(capability))
363+
}
364+
365+
if len(additionalCapabilitiesList) < 1 {
366+
return nil
367+
}
368+
369+
return additionalCapabilitiesList
370+
}
371+
372+
func isCapabilitiesEmpty(capabilities controlplanev1alpha2.Capabilities) bool {
373+
return equality.Semantic.DeepEqual(capabilities, controlplanev1alpha2.Capabilities{})
374+
}

0 commit comments

Comments
 (0)