From d7117277c47ebb71cc2006efd5eb5c1570454099 Mon Sep 17 00:00:00 2001 From: Marek Veber Date: Mon, 2 Jun 2025 13:40:32 +0200 Subject: [PATCH] ARO ... define structures --- PROJECT | 9 + ...ane.cluster.x-k8s.io_arocontrolplanes.yaml | 402 ++++++++++++++++++ ...tructure.cluster.x-k8s.io_aroclusters.yaml | 160 +++++++ ...ture.cluster.x-k8s.io_aromachinepools.yaml | 260 +++++++++++ config/crd/kustomization.yaml | 9 + .../patches/cainjection_in_aroclusters.yaml | 8 + .../cainjection_in_arocontrolplanes.yaml | 8 + .../cainjection_in_aromachinepools.yaml | 8 + .../patches/capicontract_in_aroclusters.yaml | 6 + .../capicontract_in_arocontrolplanes.yaml | 6 + .../capicontract_in_aromachinepools.yaml | 6 + config/manager/manager.yaml | 2 +- config/rbac/role.yaml | 32 ++ .../v1beta2/arocontrolplane_types.go | 322 ++++++++++++++ .../controlplane/v1beta2/groupversion_info.go | 36 ++ .../v1beta2/zz_generated.deepcopy.go | 243 +++++++++++ exp/api/v1beta2/arocluster_types.go | 79 ++++ exp/api/v1beta2/aromachinepool_types.go | 207 +++++++++ exp/api/v1beta2/groupversion_info.go | 36 ++ exp/api/v1beta2/zz_generated.deepcopy.go | 307 +++++++++++++ exp/controllers/arocluster_controller.go | 101 +++++ exp/controllers/arocontrolplane_controller.go | 86 ++++ exp/controllers/aromachinepool_controller.go | 83 ++++ feature/feature.go | 6 + go.mod | 3 + go.sum | 5 + main.go | 29 ++ 27 files changed, 2458 insertions(+), 1 deletion(-) create mode 100644 config/crd/bases/controlplane.cluster.x-k8s.io_arocontrolplanes.yaml create mode 100644 config/crd/bases/infrastructure.cluster.x-k8s.io_aroclusters.yaml create mode 100644 config/crd/bases/infrastructure.cluster.x-k8s.io_aromachinepools.yaml create mode 100644 config/crd/patches/cainjection_in_aroclusters.yaml create mode 100644 config/crd/patches/cainjection_in_arocontrolplanes.yaml create mode 100644 config/crd/patches/cainjection_in_aromachinepools.yaml create mode 100644 config/crd/patches/capicontract_in_aroclusters.yaml create mode 100644 config/crd/patches/capicontract_in_arocontrolplanes.yaml create mode 100644 config/crd/patches/capicontract_in_aromachinepools.yaml create mode 100644 exp/api/controlplane/v1beta2/arocontrolplane_types.go create mode 100644 exp/api/controlplane/v1beta2/groupversion_info.go create mode 100644 exp/api/controlplane/v1beta2/zz_generated.deepcopy.go create mode 100644 exp/api/v1beta2/arocluster_types.go create mode 100644 exp/api/v1beta2/aromachinepool_types.go create mode 100644 exp/api/v1beta2/groupversion_info.go create mode 100644 exp/api/v1beta2/zz_generated.deepcopy.go create mode 100644 exp/controllers/arocluster_controller.go create mode 100644 exp/controllers/arocontrolplane_controller.go create mode 100644 exp/controllers/aromachinepool_controller.go diff --git a/PROJECT b/PROJECT index 6c36f97549a..dcac96a33c7 100644 --- a/PROJECT +++ b/PROJECT @@ -47,3 +47,12 @@ resources: - group: infrastructure version: v1beta1 kind: AzureMachinePoolMachine + - group: infrastructure + version: v1beta1 + kind: AroMachinePool + - group: infrastructure + version: v1beta1 + kind: AROCluster + - group: infrastructure + version: v1beta1 + kind: AROControlPlane diff --git a/config/crd/bases/controlplane.cluster.x-k8s.io_arocontrolplanes.yaml b/config/crd/bases/controlplane.cluster.x-k8s.io_arocontrolplanes.yaml new file mode 100644 index 00000000000..3e398696a02 --- /dev/null +++ b/config/crd/bases/controlplane.cluster.x-k8s.io_arocontrolplanes.yaml @@ -0,0 +1,402 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: arocontrolplanes.controlplane.cluster.x-k8s.io +spec: + group: controlplane.cluster.x-k8s.io + names: + categories: + - cluster-api + kind: AROControlPlane + listKind: AROControlPlaneList + plural: arocontrolplanes + shortNames: + - arocp + singular: arocontrolplane + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Cluster to which this AROControl belongs + jsonPath: .metadata.labels.cluster\.x-k8s\.io/cluster-name + name: Cluster + type: string + - description: Control plane infrastructure is ready for worker nodes + jsonPath: .status.ready + name: Ready + type: string + name: v1beta2 + schema: + openAPIV3Schema: + description: AROControlPlane is the Schema for the AROControlPlanes API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: AROControlPlaneSpec defines the desired state of AROControlPlane. + properties: + additionalTags: + additionalProperties: + type: string + description: AdditionalTags are user-defined tags to be added on the + AWS resources associated with the control plane. + type: object + aroClusterName: + description: |- + Cluster name must be valid DNS-1035 label, so it must consist of lower case alphanumeric + characters or '-', start with an alphabetic character, end with an alphanumeric character + and have a max length of 54 characters. + maxLength: 54 + pattern: ^[a-z]([-a-z0-9]*[a-z0-9])?$ + type: string + x-kubernetes-validations: + - message: aroClusterName is immutable + rule: self == oldSelf + channelGroup: + default: stable + description: OpenShift version channel group, default is stable. + enum: + - stable + - candidate + - nightly + type: string + domainPrefix: + description: |- + DomainPrefix is an optional prefix added to the cluster's domain name. It will be used + when generating a sub-domain for the cluster on openshiftapps domain. It must be valid DNS-1035 label + consisting of lower case alphanumeric characters or '-', start with an alphabetic character + end with an alphanumeric character and have a max length of 15 characters. + maxLength: 15 + pattern: ^[a-z]([-a-z0-9]*[a-z0-9])?$ + type: string + x-kubernetes-validations: + - message: domainPrefix is immutable + rule: self == oldSelf + identityRef: + description: |- + IdentityRef is a reference to an identity to be used when reconciling the aro control plane. + If no identity is specified, the default identity for this controller will be used. + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: |- + If referring to a piece of an object instead of an entire object, this string + should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within a pod, this would take on a value like: + "spec.containers{name}" (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" (container with + index 2 in this pod). This syntax is chosen only to have some well-defined way of + referencing a part of an object. + type: string + kind: + description: |- + Kind of the referent. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + namespace: + description: |- + Namespace of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ + type: string + resourceVersion: + description: |- + Specific resourceVersion to which this reference is made, if any. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency + type: string + uid: + description: |- + UID of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids + type: string + type: object + x-kubernetes-map-type: atomic + network: + description: Network config for the ARO HCP cluster. + properties: + hostPrefix: + default: 23 + description: Network host prefix which is defaulted to `23` if + not specified. + type: integer + machineCIDR: + description: IP addresses block used by OpenShift while installing + the cluster, for example "10.0.0.0/16". + format: cidr + type: string + networkType: + default: OVNKubernetes + description: The CNI network type default is OVNKubernetes. + enum: + - OVNKubernetes + - Other + type: string + podCIDR: + description: IP address block from which to assign pod IP addresses, + for example `10.128.0.0/14`. + format: cidr + type: string + serviceCIDR: + description: IP address block from which to assign service IP + addresses, for example `172.30.0.0/16`. + format: cidr + type: string + type: object + platform: + description: AROPlatformProfileControlPlane represents the Azure platform + configuration. + properties: + location: + description: Location should be valid Azure location ex; centralus + type: string + managedIdentities: + description: ManagedIdentities Azure managed identities for ARO + HCP. + properties: + controlPlaneOperators: + description: ControlPlaneOperators Ref to Microsoft.ManagedIdentity/userAssignedIdentities + properties: + cloudControllerManager: + description: CloudControllerManagerManagedIdentities "cloud-controller-manager" + Microsoft.ManagedIdentity/userAssignedIdentities + type: string + cloudNetworkConfigManagedIdentities: + description: CloudNetworkConfigManagedIdentities "cloud-network-config" + Microsoft.ManagedIdentity/userAssignedIdentities + type: string + clusterApiAzureManagedIdentities: + description: ClusterAPIAzureManagedIdentities "cluster-api-azure" + Microsoft.ManagedIdentity/userAssignedIdentities + type: string + controlPlaneOperatorsManagedIdentities: + description: ControlPlaneManagedIdentities "control-plane" + Microsoft.ManagedIdentity/userAssignedIdentities + type: string + diskCsiDriverManagedIdentities: + description: DiskCsiDriverManagedIdentities "disk-csi-driver" + Microsoft.ManagedIdentity/userAssignedIdentities + type: string + fileCsiDriverManagedIdentities: + description: FileCsiDriverManagedIdentities "file-csi-driver" + Microsoft.ManagedIdentity/userAssignedIdentities + type: string + imageRegistryManagedIdentities: + description: ImageRegistryManagedIdentities "image-registry" + Microsoft.ManagedIdentity/userAssignedIdentities + type: string + ingressManagedIdentities: + description: IngressManagedIdentities "ingress" Microsoft.ManagedIdentity/userAssignedIdentities + type: string + kmsManagedIdentities: + description: KmsManagedIdentities "kms" Microsoft.ManagedIdentity/userAssignedIdentities + type: string + type: object + createAROHCPManagedIdentities: + description: |- + CreateAROHCPManagedIdentities is used to create the required ARO-HCP managed identities if not provided. + It will create UserAssignedIdentity CR for each required managed identity. Default is false. + type: boolean + dataPlaneOperators: + description: DataPlaneOperators ref to Microsoft.ManagedIdentity/userAssignedIdentities + properties: + diskCsiDriverManagedIdentities: + description: DiskCsiDriverManagedIdentities "disk-csi-driver" + Microsoft.ManagedIdentity/userAssignedIdentities + type: string + fileCsiDriverManagedIdentities: + description: FileCsiDriverManagedIdentities "file-csi-driver" + Microsoft.ManagedIdentity/userAssignedIdentities + type: string + imageRegistryManagedIdentities: + description: ImageRegistryManagedIdentities "image-registry" + Microsoft.ManagedIdentity/userAssignedIdentities + type: string + type: object + serviceManagedIdentity: + description: ServiceManagedIdentity ref to Microsoft.ManagedIdentity/userAssignedIdentities + type: string + type: object + networkSecurityGroupId: + description: Azure Network Security Group ID + type: string + outboundType: + description: OutboundType represents a routing strategy to provide + egress to the Internet. Allowed value is loadBalancer + type: string + resourceGroup: + description: Resource group name where the ARO-hcp will be attached + to it. + type: string + resourceGroupRef: + description: ResourceGroup Ref name that is used to create the + ResourceGroup CR. The ResourceGroupRef must be in the same namespace + as the AROControlPlane and cannot be set with ResourceGroup. + type: string + subnet: + description: Azure subnet id + type: string + subnetRef: + description: Subnet Ref name that is used to create the VirtualNetworksSubnet + CR. The SubnetRef must be in the same namespace as the AROControlPlane + and cannot be set with Subnet. + type: string + type: object + version: + description: OpenShift semantic version, for example "4.14.5". + type: string + versionGate: + default: WaitForAcknowledge + description: |- + VersionGate requires acknowledgment when upgrading ARO-HCP y-stream versions (e.g., from 4.15 to 4.16). + Default is WaitForAcknowledge. + WaitForAcknowledge: If acknowledgment is required, the upgrade will not proceed until VersionGate is set to Acknowledge or AlwaysAcknowledge. + Acknowledge: If acknowledgment is required, apply it for the upgrade. After upgrade is done set the version gate to WaitForAcknowledge. + AlwaysAcknowledge: If acknowledgment is required, apply it and proceed with the upgrade. + enum: + - Acknowledge + - WaitForAcknowledge + - AlwaysAcknowledge + type: string + visibility: + description: Visibility represents the visibility of an API endpoint. + Allowed values are public and private default is public. + type: string + required: + - aroClusterName + - channelGroup + - version + - versionGate + type: object + status: + description: AROControlPlaneStatus defines the observed state of AROControlPlane. + properties: + apiURL: + description: APIURL is the url for the ARO-HCP openshift cluster api + endPoint. + type: string + availableUpgrades: + description: Available upgrades for the ARO hosted control plane. + items: + type: string + type: array + conditions: + description: Conditions specifies the conditions for the managed control + plane + items: + description: Condition defines an observation of a Cluster API resource + operational state. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This field may be empty. + maxLength: 10240 + minLength: 1 + type: string + reason: + description: |- + reason is the reason for the condition's last transition in CamelCase. + The specific API may choose whether or not this field is considered a guaranteed API. + This field may be empty. + maxLength: 256 + minLength: 1 + type: string + severity: + description: |- + severity provides an explicit classification of Reason code, so the users or machines can immediately + understand the current situation and act accordingly. + The Severity field MUST be set only when Status=False. + maxLength: 32 + type: string + status: + description: status of the condition, one of True, False, Unknown. + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions + can be useful (see .node.status.conditions), the ability to deconflict is important. + maxLength: 256 + minLength: 1 + type: string + required: + - lastTransitionTime + - status + - type + type: object + type: array + consoleURL: + description: ConsoleURL is the url for the openshift console. + type: string + externalManagedControlPlane: + default: true + description: |- + ExternalManagedControlPlane indicates to cluster-api that the control plane + is managed by an external service such as AKS, EKS, GKE, etc. + type: boolean + failureMessage: + description: |- + FailureMessage will be set in the event that there is a terminal problem + reconciling the state and will be set to a descriptive error message. + + This field should not be set for transitive errors that a controller + faces that are expected to be fixed automatically over + time (like service outages), but instead indicate that something is + fundamentally wrong with the spec or the configuration of + the controller, and that manual intervention is required. + type: string + id: + description: ID is the cluster ID given by ARO. + type: string + initialized: + description: |- + Initialized denotes whether or not the control plane has the + uploaded kubernetes config-map. + type: boolean + ready: + default: false + description: Ready denotes that the AROControlPlane API Server is + ready to receive requests. + type: boolean + version: + description: ARO-HCP OpenShift semantic version, for example "4.20.0". + type: string + required: + - ready + - version + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_aroclusters.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_aroclusters.yaml new file mode 100644 index 00000000000..5403d04f6c4 --- /dev/null +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_aroclusters.yaml @@ -0,0 +1,160 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: aroclusters.infrastructure.cluster.x-k8s.io +spec: + group: infrastructure.cluster.x-k8s.io + names: + categories: + - cluster-api + kind: AROCluster + listKind: AROClusterList + plural: aroclusters + shortNames: + - aroc + singular: arocluster + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Cluster to which this AroManagedControl belongs + jsonPath: .metadata.labels.cluster\.x-k8s\.io/cluster-name + name: Cluster + type: string + - description: Control plane infrastructure is ready for worker nodes + jsonPath: .status.ready + name: Ready + type: string + - description: API Endpoint + jsonPath: .spec.controlPlaneEndpoint.host + name: Endpoint + priority: 1 + type: string + name: v1beta2 + schema: + openAPIV3Schema: + description: AROCluster is the Schema for the AROClusters API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: AROClusterSpec defines the desired state of AROCluster. + properties: + controlPlaneEndpoint: + description: ControlPlaneEndpoint represents the endpoint used to + communicate with the control plane. + properties: + host: + description: host is the hostname on which the API server is serving. + maxLength: 512 + type: string + port: + description: port is the port on which the API server is serving. + format: int32 + type: integer + required: + - host + - port + type: object + type: object + status: + description: AROClusterStatus defines the observed state of AROCluster. + properties: + conditions: + description: Conditions define the current service state of the AROCluster. + items: + description: Condition defines an observation of a Cluster API resource + operational state. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This field may be empty. + maxLength: 10240 + minLength: 1 + type: string + reason: + description: |- + reason is the reason for the condition's last transition in CamelCase. + The specific API may choose whether or not this field is considered a guaranteed API. + This field may be empty. + maxLength: 256 + minLength: 1 + type: string + severity: + description: |- + severity provides an explicit classification of Reason code, so the users or machines can immediately + understand the current situation and act accordingly. + The Severity field MUST be set only when Status=False. + maxLength: 32 + type: string + status: + description: status of the condition, one of True, False, Unknown. + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions + can be useful (see .node.status.conditions), the ability to deconflict is important. + maxLength: 256 + minLength: 1 + type: string + required: + - lastTransitionTime + - status + - type + type: object + type: array + failureDomains: + additionalProperties: + description: |- + FailureDomainSpec is the Schema for Cluster API failure domains. + It allows controllers to understand how many failure domains a cluster can optionally span across. + properties: + attributes: + additionalProperties: + type: string + description: attributes is a free form map of attributes an + infrastructure provider might use or require. + type: object + controlPlane: + description: controlPlane determines if this failure domain + is suitable for use by control plane machines. + type: boolean + type: object + description: FailureDomains specifies a list fo available availability + zones that can be used + type: object + ready: + description: Ready is when the AROControlPlane has a API server URL. + type: boolean + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_aromachinepools.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_aromachinepools.yaml new file mode 100644 index 00000000000..6919d5cd281 --- /dev/null +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_aromachinepools.yaml @@ -0,0 +1,260 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: aromachinepools.infrastructure.cluster.x-k8s.io +spec: + group: infrastructure.cluster.x-k8s.io + names: + categories: + - cluster-api + kind: AROMachinePool + listKind: AROMachinePoolList + plural: aromachinepools + shortNames: + - aromp + singular: aromachinepool + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: MachinePool ready status + jsonPath: .status.ready + name: Ready + type: string + - description: Number of replicas + jsonPath: .status.replicas + name: Replicas + type: integer + name: v1beta2 + schema: + openAPIV3Schema: + description: AROMachinePool is the Schema for the aromachinepools API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: AROMachinePoolSpec defines the desired state of AROMachinePool. + properties: + additionalTags: + additionalProperties: + type: string + description: AdditionalTags are user-defined tags to be added on the + underlying EC2 instances associated with this machine pool. + type: object + autoRepair: + default: true + description: |- + AutoRepair specifies whether health checks should be enabled for machines + in the NodePool. The default is true. + type: boolean + autoscaling: + description: |- + Autoscaling specifies auto scaling behaviour for this MachinePool. + required if Replicas is not configured + properties: + maxReplicas: + minimum: 1 + type: integer + minReplicas: + minimum: 1 + type: integer + type: object + labels: + additionalProperties: + type: string + description: Labels specifies labels for the Kubernetes node objects + type: object + nodePoolName: + description: |- + NodePoolName specifies the name of the nodepool in ARO + must be a valid DNS-1035 label, so it must consist of lower case alphanumeric and have a max length of 15 characters. + maxLength: 15 + pattern: ^[a-z]([-a-z0-9]*[a-z0-9])?$ + type: string + x-kubernetes-validations: + - message: nodepoolName is immutable + rule: self == oldSelf + platform: + description: AROPlatformProfileMachinePool represents the NodePool + Azure platform configuration. + properties: + availabilityZone: + description: AvailabilityZone specifying the availability zone + where instances of this machine pool should run. + type: string + diskSizeGiB: + description: DiskSizeGiB sets the disk volume size for the machine + pool, in Gib. + format: int32 + type: integer + diskStorageAccountType: + description: |- + DiskStorageAccountType represents supported Azure storage account types. + Available values are Premium_LRS, StandardSSD_LRS and Standard_LRS. + type: string + subnet: + description: Azure subnet id + type: string + subnetRef: + description: Subnet Ref name that is used to create the VirtualNetworksSubnet + CR. The SubnetRef must be in the same namespace as the AroMachinePool + and cannot be set with Subnet. + type: string + vmSize: + description: VMSize sets the VM disk volume size to the node. + type: string + type: object + taints: + description: Taints specifies the taints to apply to the nodes of + the machine pool + items: + description: AROTaint represents a taint to be applied to a node. + properties: + effect: + description: |- + The effect of the taint on pods that do not tolerate the taint. + Valid effects are NoSchedule, PreferNoSchedule and NoExecute. + enum: + - NoSchedule + - PreferNoSchedule + - NoExecute + type: string + key: + description: The taint key to be applied to a node. + type: string + value: + description: The taint value corresponding to the taint key. + pattern: ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$ + type: string + required: + - effect + - key + type: object + type: array + version: + description: |- + Version specifies the OpenShift version of the nodes associated with this machinepool. + AROControlPlane version is used if not set. + type: string + required: + - nodePoolName + type: object + status: + description: AROMachinePoolStatus defines the observed state of AROMachinePool. + properties: + availableUpgrades: + description: Available upgrades for the ARO MachinePool. + items: + type: string + type: array + conditions: + description: Conditions defines current service state of the managed + machine pool + items: + description: Condition defines an observation of a Cluster API resource + operational state. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This field may be empty. + maxLength: 10240 + minLength: 1 + type: string + reason: + description: |- + reason is the reason for the condition's last transition in CamelCase. + The specific API may choose whether or not this field is considered a guaranteed API. + This field may be empty. + maxLength: 256 + minLength: 1 + type: string + severity: + description: |- + severity provides an explicit classification of Reason code, so the users or machines can immediately + understand the current situation and act accordingly. + The Severity field MUST be set only when Status=False. + maxLength: 32 + type: string + status: + description: status of the condition, one of True, False, Unknown. + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions + can be useful (see .node.status.conditions), the ability to deconflict is important. + maxLength: 256 + minLength: 1 + type: string + required: + - lastTransitionTime + - status + - type + type: object + type: array + failureMessage: + description: |- + FailureMessage will be set in the event that there is a terminal problem + reconciling the state and will be set to a descriptive error message. + + This field should not be set for transitive errors that a controller + faces that are expected to be fixed automatically over + time (like service outages), but instead indicate that something is + fundamentally wrong with the spec or the configuration of + the controller, and that manual intervention is required. + type: string + id: + description: ID is the ID given by ARO. + type: string + provisioningState: + description: |- + ProvisioningState represents the asynchronous provisioning state of an ARM resource. + Allowed values are; Succeeded, Failed, Canceled, Accepted, Deleting, Provisioning and Updating. + type: string + ready: + default: false + description: |- + Ready denotes that the AROMachinePool nodepool has joined + the cluster + type: boolean + replicas: + description: Replicas is the most recently observed number of replicas. + format: int32 + type: integer + version: + description: ARO-HCP OpenShift semantic version, for example "4.20.0". + type: string + required: + - ready + - version + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index e90153253af..114a7bb3069 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -24,6 +24,9 @@ resources: - bases/infrastructure.cluster.x-k8s.io_azureasomanagedcontrolplanetemplates.yaml - bases/infrastructure.cluster.x-k8s.io_azureasomanagedmachinepools.yaml - bases/infrastructure.cluster.x-k8s.io_azureasomanagedmachinepooltemplates.yaml +- bases/infrastructure.cluster.x-k8s.io_aroclusters.yaml +- bases/infrastructure.cluster.x-k8s.io_aromachinepools.yaml +- bases/controlplane.cluster.x-k8s.io_arocontrolplanes.yaml # +kubebuilder:scaffold:crdkustomizeresource patches: @@ -50,6 +53,9 @@ patches: - path: patches/cainjection_in_azuremachinetemplates.yaml - path: patches/cainjection_in_azuremachinepools.yaml - path: patches/cainjection_in_azuremachinepoolmachines.yaml +- path: patches/cainjection_in_aroclusters.yaml +- path: patches/cainjection_in_arocontrolplanes.yaml +- path: patches/cainjection_in_aromachinepools.yaml # - path: patches/cainjection_in_azuremanagedmachinepools.yaml # - path: patches/cainjection_in_azuremanagedclusters.yaml # - path: patches/cainjection_in_azuremanagedcontrolplanes.yaml @@ -74,6 +80,9 @@ patches: - path: patches/capicontract_in_azureasomanagedcontrolplanetemplates.yaml - path: patches/capicontract_in_azureasomanagedmachinepools.yaml - path: patches/capicontract_in_azureasomanagedmachinepooltemplates.yaml +- path: patches/capicontract_in_aroclusters.yaml +- path: patches/capicontract_in_arocontrolplanes.yaml +- path: patches/capicontract_in_aromachinepools.yaml # the following config is for teaching kustomize how to do kustomization for CRDs. configurations: diff --git a/config/crd/patches/cainjection_in_aroclusters.yaml b/config/crd/patches/cainjection_in_aroclusters.yaml new file mode 100644 index 00000000000..72f9ab8582b --- /dev/null +++ b/config/crd/patches/cainjection_in_aroclusters.yaml @@ -0,0 +1,8 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +# CRD conversion requires k8s 1.13 or later. +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE_PLACEHOLDER/CERTIFICATE_NAME_PLACEHOLDER + name: aroclusters.infrastructure.cluster.x-k8s.io diff --git a/config/crd/patches/cainjection_in_arocontrolplanes.yaml b/config/crd/patches/cainjection_in_arocontrolplanes.yaml new file mode 100644 index 00000000000..6c6c298a39d --- /dev/null +++ b/config/crd/patches/cainjection_in_arocontrolplanes.yaml @@ -0,0 +1,8 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +# CRD conversion requires k8s 1.13 or later. +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: arocontrolplanes.controlplane.cluster.x-k8s.io diff --git a/config/crd/patches/cainjection_in_aromachinepools.yaml b/config/crd/patches/cainjection_in_aromachinepools.yaml new file mode 100644 index 00000000000..76f5240a573 --- /dev/null +++ b/config/crd/patches/cainjection_in_aromachinepools.yaml @@ -0,0 +1,8 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +# CRD conversion requires k8s 1.13 or later. +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE_PLACEHOLDER/CERTIFICATE_NAME_PLACEHOLDER + name: aromachinepools.infrastructure.cluster.x-k8s.io diff --git a/config/crd/patches/capicontract_in_aroclusters.yaml b/config/crd/patches/capicontract_in_aroclusters.yaml new file mode 100644 index 00000000000..4cb666eb68d --- /dev/null +++ b/config/crd/patches/capicontract_in_aroclusters.yaml @@ -0,0 +1,6 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: aroclusters.infrastructure.cluster.x-k8s.io + labels: + cluster.x-k8s.io/v1beta2: v1beta2 diff --git a/config/crd/patches/capicontract_in_arocontrolplanes.yaml b/config/crd/patches/capicontract_in_arocontrolplanes.yaml new file mode 100644 index 00000000000..03f9a868467 --- /dev/null +++ b/config/crd/patches/capicontract_in_arocontrolplanes.yaml @@ -0,0 +1,6 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: arocontrolplanes.controlplane.cluster.x-k8s.io + labels: + cluster.x-k8s.io/v1beta2: v1beta2 diff --git a/config/crd/patches/capicontract_in_aromachinepools.yaml b/config/crd/patches/capicontract_in_aromachinepools.yaml new file mode 100644 index 00000000000..fd6882024a9 --- /dev/null +++ b/config/crd/patches/capicontract_in_aromachinepools.yaml @@ -0,0 +1,6 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: aromachinepools.infrastructure.cluster.x-k8s.io + labels: + cluster.x-k8s.io/v1beta2: v1beta2 diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 2f2c4b4e770..db10ce98554 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -24,7 +24,7 @@ spec: - --leader-elect - "--diagnostics-address=${CAPZ_DIAGNOSTICS_ADDRESS:=:8443}" - "--insecure-diagnostics=${CAPZ_INSECURE_DIAGNOSTICS:=false}" - - "--feature-gates=MachinePool=${EXP_MACHINE_POOL:=true},AKSResourceHealth=${EXP_AKS_RESOURCE_HEALTH:=false},EdgeZone=${EXP_EDGEZONE:=false},ASOAPI=${EXP_ASO_API:=true},APIServerILB=${EXP_APISERVER_ILB:=false}" + - "--feature-gates=MachinePool=${EXP_MACHINE_POOL:=true},AKSResourceHealth=${EXP_AKS_RESOURCE_HEALTH:=false},EdgeZone=${EXP_EDGEZONE:=false},ASOAPI=${EXP_ASO_API:=true},APIServerILB=${EXP_APISERVER_ILB:=false},ARO=${EXP_ARO:=false}" - "--v=0" image: controller:latest imagePullPolicy: Always diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 6706cf79b50..364eba1b909 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -127,6 +127,32 @@ rules: - get - list - watch +- apiGroups: + - controlplane.cluster.x-k8s.io + resources: + - arocontrolplanes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - controlplane.cluster.x-k8s.io + resources: + - arocontrolplanes/finalizers + verbs: + - update +- apiGroups: + - controlplane.cluster.x-k8s.io + resources: + - arocontrolplanes/status + verbs: + - get + - patch + - update - apiGroups: - "" resources: @@ -138,6 +164,8 @@ rules: - apiGroups: - infrastructure.cluster.x-k8s.io resources: + - aroclusters + - aromachinepools - azureasomanagedclusters - azureasomanagedcontrolplanes - azureasomanagedmachinepools @@ -161,6 +189,8 @@ rules: - apiGroups: - infrastructure.cluster.x-k8s.io resources: + - aroclusters/finalizers + - aromachinepools/finalizers - azureasomanagedclusters/finalizers - azureasomanagedcontrolplanes/finalizers - azureasomanagedmachinepools/finalizers @@ -169,6 +199,8 @@ rules: - apiGroups: - infrastructure.cluster.x-k8s.io resources: + - aroclusters/status + - aromachinepools/status - azureasomanagedclusters/status - azureasomanagedcontrolplanes/status - azureasomanagedmachinepools/status diff --git a/exp/api/controlplane/v1beta2/arocontrolplane_types.go b/exp/api/controlplane/v1beta2/arocontrolplane_types.go new file mode 100644 index 00000000000..e62cc8c8b69 --- /dev/null +++ b/exp/api/controlplane/v1beta2/arocontrolplane_types.go @@ -0,0 +1,322 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta2 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + + infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" +) + +// VersionGateAckType specifies the version gate acknowledgment. +type VersionGateAckType string + +const ( + // Acknowledge if acknowledgment is required and proceed with the upgrade. + Acknowledge VersionGateAckType = "Acknowledge" + + // WaitForAcknowledge if acknowledgment is required, wait not to proceed with the upgrade. + WaitForAcknowledge VersionGateAckType = "WaitForAcknowledge" + + // AlwaysAcknowledge always acknowledg if required and proceed with the upgrade. + AlwaysAcknowledge VersionGateAckType = "AlwaysAcknowledge" +) + +// ChannelGroupType specifies the OpenShift version channel group. +type ChannelGroupType string + +const ( + // Stable channel group is the default channel group for stable releases. + Stable ChannelGroupType = "stable" + + // Candidate channel group is for testing candidate builds. + Candidate ChannelGroupType = "candidate" + + // Nightly channel group is for testing nigtly builds. + Nightly ChannelGroupType = "nightly" +) + +// AROControlPlaneSpec defines the desired state of AROControlPlane. +type AROControlPlaneSpec struct { //nolint: maligned + // Cluster name must be valid DNS-1035 label, so it must consist of lower case alphanumeric + // characters or '-', start with an alphabetic character, end with an alphanumeric character + // and have a max length of 54 characters. + // + // +immutable + // +kubebuilder:validation:XValidation:rule="self == oldSelf", message="aroClusterName is immutable" + // +kubebuilder:validation:MaxLength:=54 + // +kubebuilder:validation:Pattern:=`^[a-z]([-a-z0-9]*[a-z0-9])?$` + AroClusterName string `json:"aroClusterName"` + + // AROPlatformProfileControlPlane represents the Azure platform configuration. + Platform AROPlatformProfileControlPlane `json:"platform,omitempty"` + + // Visibility represents the visibility of an API endpoint. Allowed values are public and private default is public. + Visibility string `json:"visibility,omitempty"` + + // Network config for the ARO HCP cluster. + // +optional + Network *NetworkSpec `json:"network,omitempty"` + + // DomainPrefix is an optional prefix added to the cluster's domain name. It will be used + // when generating a sub-domain for the cluster on openshiftapps domain. It must be valid DNS-1035 label + // consisting of lower case alphanumeric characters or '-', start with an alphabetic character + // end with an alphanumeric character and have a max length of 15 characters. + // + // +immutable + // +kubebuilder:validation:XValidation:rule="self == oldSelf", message="domainPrefix is immutable" + // +kubebuilder:validation:MaxLength:=15 + // +kubebuilder:validation:Pattern:=`^[a-z]([-a-z0-9]*[a-z0-9])?$` + // +optional + DomainPrefix string `json:"domainPrefix,omitempty"` + + // OpenShift semantic version, for example "4.14.5". + Version string `json:"version"` + + // OpenShift version channel group, default is stable. + // + // +kubebuilder:validation:Enum=stable;candidate;nightly + // +kubebuilder:default=stable + ChannelGroup ChannelGroupType `json:"channelGroup"` + + // VersionGate requires acknowledgment when upgrading ARO-HCP y-stream versions (e.g., from 4.15 to 4.16). + // Default is WaitForAcknowledge. + // WaitForAcknowledge: If acknowledgment is required, the upgrade will not proceed until VersionGate is set to Acknowledge or AlwaysAcknowledge. + // Acknowledge: If acknowledgment is required, apply it for the upgrade. After upgrade is done set the version gate to WaitForAcknowledge. + // AlwaysAcknowledge: If acknowledgment is required, apply it and proceed with the upgrade. + // + // +kubebuilder:validation:Enum=Acknowledge;WaitForAcknowledge;AlwaysAcknowledge + // +kubebuilder:default=WaitForAcknowledge + VersionGate VersionGateAckType `json:"versionGate"` + + // IdentityRef is a reference to an identity to be used when reconciling the aro control plane. + // If no identity is specified, the default identity for this controller will be used. + IdentityRef *corev1.ObjectReference `json:"identityRef,omitempty"` + + // AdditionalTags are user-defined tags to be added on the AWS resources associated with the control plane. + // +optional + AdditionalTags infrav1.Tags `json:"additionalTags,omitempty"` +} + +// AROPlatformProfileControlPlane represents the Azure platform configuration. +type AROPlatformProfileControlPlane struct { + // Location should be valid Azure location ex; centralus + Location string `json:"location,omitempty"` + + // Resource group name where the ARO-hcp will be attached to it. + ResourceGroup string `json:"resourceGroup,omitempty"` + + // ResourceGroup Ref name that is used to create the ResourceGroup CR. The ResourceGroupRef must be in the same namespace as the AROControlPlane and cannot be set with ResourceGroup. + ResourceGroupRef string `json:"resourceGroupRef,omitempty"` + + // Azure subnet id + Subnet string `json:"subnet,omitempty"` + + // Subnet Ref name that is used to create the VirtualNetworksSubnet CR. The SubnetRef must be in the same namespace as the AROControlPlane and cannot be set with Subnet. + SubnetRef string `json:"subnetRef,omitempty"` + + // OutboundType represents a routing strategy to provide egress to the Internet. Allowed value is loadBalancer + OutboundType string `json:"outboundType,omitempty"` + + // Azure Network Security Group ID + NetworkSecurityGroupID string `json:"networkSecurityGroupId,omitempty"` + + // ManagedIdentities Azure managed identities for ARO HCP. + ManagedIdentities ManagedIdentities `json:"managedIdentities,omitempty"` +} + +// ManagedIdentities represents managed identities for the Azure platform configuration. +type ManagedIdentities struct { + // CreateAROHCPManagedIdentities is used to create the required ARO-HCP managed identities if not provided. + // It will create UserAssignedIdentity CR for each required managed identity. Default is false. + CreateAROHCPManagedIdentities bool `json:"createAROHCPManagedIdentities,omitempty"` + + // ControlPlaneOperators Ref to Microsoft.ManagedIdentity/userAssignedIdentities + ControlPlaneOperators *ControlPlaneOperators `json:"controlPlaneOperators,omitempty"` + + // DataPlaneOperators ref to Microsoft.ManagedIdentity/userAssignedIdentities + DataPlaneOperators *DataPlaneOperators `json:"dataPlaneOperators,omitempty"` + + // ServiceManagedIdentity ref to Microsoft.ManagedIdentity/userAssignedIdentities + ServiceManagedIdentity string `json:"serviceManagedIdentity,omitempty"` +} + +// ControlPlaneOperators represents managed identities for the ControlPlane. +type ControlPlaneOperators struct { + // ControlPlaneManagedIdentities "control-plane" Microsoft.ManagedIdentity/userAssignedIdentities + ControlPlaneManagedIdentities string `json:"controlPlaneOperatorsManagedIdentities,omitempty"` + + // ClusterAPIAzureManagedIdentities "cluster-api-azure" Microsoft.ManagedIdentity/userAssignedIdentities + ClusterAPIAzureManagedIdentities string `json:"clusterApiAzureManagedIdentities,omitempty"` + + // CloudControllerManagerManagedIdentities "cloud-controller-manager" Microsoft.ManagedIdentity/userAssignedIdentities + CloudControllerManagerManagedIdentities string `json:"cloudControllerManager,omitempty"` + + // IngressManagedIdentities "ingress" Microsoft.ManagedIdentity/userAssignedIdentities + IngressManagedIdentities string `json:"ingressManagedIdentities,omitempty"` + + // DiskCsiDriverManagedIdentities "disk-csi-driver" Microsoft.ManagedIdentity/userAssignedIdentities + DiskCsiDriverManagedIdentities string `json:"diskCsiDriverManagedIdentities,omitempty"` + + // FileCsiDriverManagedIdentities "file-csi-driver" Microsoft.ManagedIdentity/userAssignedIdentities + FileCsiDriverManagedIdentities string `json:"fileCsiDriverManagedIdentities,omitempty"` + + // ImageRegistryManagedIdentities "image-registry" Microsoft.ManagedIdentity/userAssignedIdentities + ImageRegistryManagedIdentities string `json:"imageRegistryManagedIdentities,omitempty"` + + // CloudNetworkConfigManagedIdentities "cloud-network-config" Microsoft.ManagedIdentity/userAssignedIdentities + CloudNetworkConfigManagedIdentities string `json:"cloudNetworkConfigManagedIdentities,omitempty"` + + // KmsManagedIdentities "kms" Microsoft.ManagedIdentity/userAssignedIdentities + KmsManagedIdentities string `json:"kmsManagedIdentities,omitempty"` +} + +// DataPlaneOperators represents managed identities for the DataPlane. +type DataPlaneOperators struct { + // DiskCsiDriverManagedIdentities "disk-csi-driver" Microsoft.ManagedIdentity/userAssignedIdentities + DiskCsiDriverManagedIdentities string `json:"diskCsiDriverManagedIdentities,omitempty"` + + // FileCsiDriverManagedIdentities "file-csi-driver" Microsoft.ManagedIdentity/userAssignedIdentities + FileCsiDriverManagedIdentities string `json:"fileCsiDriverManagedIdentities,omitempty"` + + // ImageRegistryManagedIdentities "image-registry" Microsoft.ManagedIdentity/userAssignedIdentities + ImageRegistryManagedIdentities string `json:"imageRegistryManagedIdentities,omitempty"` +} + +// NetworkSpec for ARO-HCP. +type NetworkSpec struct { + // IP addresses block used by OpenShift while installing the cluster, for example "10.0.0.0/16". + // +kubebuilder:validation:Format=cidr + // +optional + MachineCIDR string `json:"machineCIDR,omitempty"` + + // IP address block from which to assign pod IP addresses, for example `10.128.0.0/14`. + // +kubebuilder:validation:Format=cidr + // +optional + PodCIDR string `json:"podCIDR,omitempty"` + + // IP address block from which to assign service IP addresses, for example `172.30.0.0/16`. + // +kubebuilder:validation:Format=cidr + // +optional + ServiceCIDR string `json:"serviceCIDR,omitempty"` + + // Network host prefix which is defaulted to `23` if not specified. + // +kubebuilder:default=23 + // +optional + HostPrefix int `json:"hostPrefix,omitempty"` + + // The CNI network type default is OVNKubernetes. + // +kubebuilder:validation:Enum=OVNKubernetes;Other + // +kubebuilder:default=OVNKubernetes + // +optional + NetworkType string `json:"networkType,omitempty"` +} + +// AROControlPlaneStatus defines the observed state of AROControlPlane. +type AROControlPlaneStatus struct { + // ExternalManagedControlPlane indicates to cluster-api that the control plane + // is managed by an external service such as AKS, EKS, GKE, etc. + // +kubebuilder:default=true + ExternalManagedControlPlane *bool `json:"externalManagedControlPlane,omitempty"` // TODO: is in ROSA + // Initialized denotes whether or not the control plane has the + // uploaded kubernetes config-map. + // +optional + Initialized bool `json:"initialized"` + // Ready denotes that the AROControlPlane API Server is ready to receive requests. + // +kubebuilder:default=false + Ready bool `json:"ready"` + // FailureMessage will be set in the event that there is a terminal problem + // reconciling the state and will be set to a descriptive error message. + // + // This field should not be set for transitive errors that a controller + // faces that are expected to be fixed automatically over + // time (like service outages), but instead indicate that something is + // fundamentally wrong with the spec or the configuration of + // the controller, and that manual intervention is required. + // + // +optional + FailureMessage *string `json:"failureMessage,omitempty"` + // Conditions specifies the conditions for the managed control plane + Conditions clusterv1.Conditions `json:"conditions,omitempty"` + + // ID is the cluster ID given by ARO. + ID string `json:"id,omitempty"` + // ConsoleURL is the url for the openshift console. + ConsoleURL string `json:"consoleURL,omitempty"` + + // APIURL is the url for the ARO-HCP openshift cluster api endPoint. + APIURL string `json:"apiURL,omitempty"` + + // ARO-HCP OpenShift semantic version, for example "4.20.0". + Version string `json:"version"` + + // Available upgrades for the ARO hosted control plane. + AvailableUpgrades []string `json:"availableUpgrades,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:resource:path=arocontrolplanes,shortName=arocp,scope=Namespaced,categories=cluster-api +// +kubebuilder:storageversion +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Cluster",type="string",JSONPath=".metadata.labels.cluster\\.x-k8s\\.io/cluster-name",description="Cluster to which this AROControl belongs" +// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.ready",description="Control plane infrastructure is ready for worker nodes" +// +k8s:defaulter-gen=true +// +kubebuilder:rbac:groups=controlplane.cluster.x-k8s.io,resources=arocontrolplanes,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=controlplane.cluster.x-k8s.io,resources=arocontrolplanes/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=controlplane.cluster.x-k8s.io,resources=arocontrolplanes/finalizers,verbs=update + +// AROControlPlane is the Schema for the AROControlPlanes API. +type AROControlPlane struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec AROControlPlaneSpec `json:"spec,omitempty"` + Status AROControlPlaneStatus `json:"status,omitempty"` +} + +const ( + // AROControlPlaneKind is the kind for AROControlPlane. + AROControlPlaneKind = "AROControlPlane" + + // AROControlPlaneFinalizer is the finalizer added to AROControlPlanes. + AROControlPlaneFinalizer = "arocontrolplanes/finalizer" +) + +// +kubebuilder:object:root=true + +// AROControlPlaneList contains a list of AROControlPlane. +type AROControlPlaneList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []AROControlPlane `json:"items"` +} + +// GetConditions returns the control planes conditions. +func (r *AROControlPlane) GetConditions() clusterv1.Conditions { + return r.Status.Conditions +} + +// SetConditions sets the status conditions for the AROControlPlane. +func (r *AROControlPlane) SetConditions(conditions clusterv1.Conditions) { + r.Status.Conditions = conditions +} + +func init() { + SchemeBuilder.Register(&AROControlPlane{}, &AROControlPlaneList{}) +} diff --git a/exp/api/controlplane/v1beta2/groupversion_info.go b/exp/api/controlplane/v1beta2/groupversion_info.go new file mode 100644 index 00000000000..cc761cb3c0e --- /dev/null +++ b/exp/api/controlplane/v1beta2/groupversion_info.go @@ -0,0 +1,36 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package v1beta2 contains API Schema definitions for the exp v1beta2 API group +// +kubebuilder:object:generate=true +// +groupName=controlplane.cluster.x-k8s.io +package v1beta2 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects. + GroupVersion = schema.GroupVersion{Group: "controlplane.cluster.x-k8s.io", Version: "v1beta2"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme. + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/exp/api/controlplane/v1beta2/zz_generated.deepcopy.go b/exp/api/controlplane/v1beta2/zz_generated.deepcopy.go new file mode 100644 index 00000000000..a352f24ab18 --- /dev/null +++ b/exp/api/controlplane/v1beta2/zz_generated.deepcopy.go @@ -0,0 +1,243 @@ +//go:build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1beta2 + +import ( + "k8s.io/api/core/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" + apiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AROControlPlane) DeepCopyInto(out *AROControlPlane) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AROControlPlane. +func (in *AROControlPlane) DeepCopy() *AROControlPlane { + if in == nil { + return nil + } + out := new(AROControlPlane) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AROControlPlane) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AROControlPlaneList) DeepCopyInto(out *AROControlPlaneList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]AROControlPlane, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AROControlPlaneList. +func (in *AROControlPlaneList) DeepCopy() *AROControlPlaneList { + if in == nil { + return nil + } + out := new(AROControlPlaneList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AROControlPlaneList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AROControlPlaneSpec) DeepCopyInto(out *AROControlPlaneSpec) { + *out = *in + in.Platform.DeepCopyInto(&out.Platform) + if in.Network != nil { + in, out := &in.Network, &out.Network + *out = new(NetworkSpec) + **out = **in + } + if in.IdentityRef != nil { + in, out := &in.IdentityRef, &out.IdentityRef + *out = new(v1.ObjectReference) + **out = **in + } + if in.AdditionalTags != nil { + in, out := &in.AdditionalTags, &out.AdditionalTags + *out = make(v1beta1.Tags, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AROControlPlaneSpec. +func (in *AROControlPlaneSpec) DeepCopy() *AROControlPlaneSpec { + if in == nil { + return nil + } + out := new(AROControlPlaneSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AROControlPlaneStatus) DeepCopyInto(out *AROControlPlaneStatus) { + *out = *in + if in.ExternalManagedControlPlane != nil { + in, out := &in.ExternalManagedControlPlane, &out.ExternalManagedControlPlane + *out = new(bool) + **out = **in + } + if in.FailureMessage != nil { + in, out := &in.FailureMessage, &out.FailureMessage + *out = new(string) + **out = **in + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make(apiv1beta1.Conditions, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.AvailableUpgrades != nil { + in, out := &in.AvailableUpgrades, &out.AvailableUpgrades + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AROControlPlaneStatus. +func (in *AROControlPlaneStatus) DeepCopy() *AROControlPlaneStatus { + if in == nil { + return nil + } + out := new(AROControlPlaneStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AROPlatformProfileControlPlane) DeepCopyInto(out *AROPlatformProfileControlPlane) { + *out = *in + in.ManagedIdentities.DeepCopyInto(&out.ManagedIdentities) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AROPlatformProfileControlPlane. +func (in *AROPlatformProfileControlPlane) DeepCopy() *AROPlatformProfileControlPlane { + if in == nil { + return nil + } + out := new(AROPlatformProfileControlPlane) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControlPlaneOperators) DeepCopyInto(out *ControlPlaneOperators) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControlPlaneOperators. +func (in *ControlPlaneOperators) DeepCopy() *ControlPlaneOperators { + if in == nil { + return nil + } + out := new(ControlPlaneOperators) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataPlaneOperators) DeepCopyInto(out *DataPlaneOperators) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataPlaneOperators. +func (in *DataPlaneOperators) DeepCopy() *DataPlaneOperators { + if in == nil { + return nil + } + out := new(DataPlaneOperators) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManagedIdentities) DeepCopyInto(out *ManagedIdentities) { + *out = *in + if in.ControlPlaneOperators != nil { + in, out := &in.ControlPlaneOperators, &out.ControlPlaneOperators + *out = new(ControlPlaneOperators) + **out = **in + } + if in.DataPlaneOperators != nil { + in, out := &in.DataPlaneOperators, &out.DataPlaneOperators + *out = new(DataPlaneOperators) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManagedIdentities. +func (in *ManagedIdentities) DeepCopy() *ManagedIdentities { + if in == nil { + return nil + } + out := new(ManagedIdentities) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkSpec) DeepCopyInto(out *NetworkSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkSpec. +func (in *NetworkSpec) DeepCopy() *NetworkSpec { + if in == nil { + return nil + } + out := new(NetworkSpec) + in.DeepCopyInto(out) + return out +} diff --git a/exp/api/v1beta2/arocluster_types.go b/exp/api/v1beta2/arocluster_types.go new file mode 100644 index 00000000000..e1ec1cb46cc --- /dev/null +++ b/exp/api/v1beta2/arocluster_types.go @@ -0,0 +1,79 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta2 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" +) + +// AROClusterSpec defines the desired state of AROCluster. +type AROClusterSpec struct { + // ControlPlaneEndpoint represents the endpoint used to communicate with the control plane. + // +optional + ControlPlaneEndpoint clusterv1.APIEndpoint `json:"controlPlaneEndpoint"` +} + +// AROClusterStatus defines the observed state of AROCluster. +type AROClusterStatus struct { + // Ready is when the AROControlPlane has a API server URL. + // +optional + Ready bool `json:"ready,omitempty"` + + // FailureDomains specifies a list fo available availability zones that can be used + // +optional + FailureDomains clusterv1.FailureDomains `json:"failureDomains,omitempty"` + + // Conditions define the current service state of the AROCluster. + Conditions clusterv1.Conditions `json:"conditions,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:resource:path=aroclusters,scope=Namespaced,categories=cluster-api,shortName=aroc +// +kubebuilder:storageversion +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Cluster",type="string",JSONPath=".metadata.labels.cluster\\.x-k8s\\.io/cluster-name",description="Cluster to which this AroManagedControl belongs" +// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.ready",description="Control plane infrastructure is ready for worker nodes" +// +kubebuilder:printcolumn:name="Endpoint",type="string",JSONPath=".spec.controlPlaneEndpoint.host",description="API Endpoint",priority=1 +// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=aroclusters,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=aroclusters/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=aroclusters/finalizers,verbs=update + +// AROCluster is the Schema for the AROClusters API. +type AROCluster struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec AROClusterSpec `json:"spec,omitempty"` + Status AROClusterStatus `json:"status,omitempty"` +} + +// AROClusterKind is the kind for AROCluster. +const AROClusterKind = "AROCluster" + +// +kubebuilder:object:root=true + +// AROClusterList contains a list of AROCluster. +type AROClusterList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []AROCluster `json:"items"` +} + +func init() { + SchemeBuilder.Register(&AROCluster{}, &AROClusterList{}) +} diff --git a/exp/api/v1beta2/aromachinepool_types.go b/exp/api/v1beta2/aromachinepool_types.go new file mode 100644 index 00000000000..cbf125bf20c --- /dev/null +++ b/exp/api/v1beta2/aromachinepool_types.go @@ -0,0 +1,207 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta2 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + + infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" +) + +// AROMachinePoolSpec defines the desired state of AROMachinePool. +type AROMachinePoolSpec struct { + // NodePoolName specifies the name of the nodepool in ARO + // must be a valid DNS-1035 label, so it must consist of lower case alphanumeric and have a max length of 15 characters. + // + // +immutable + // +kubebuilder:validation:XValidation:rule="self == oldSelf", message="nodepoolName is immutable" + // +kubebuilder:validation:MaxLength:=15 + // +kubebuilder:validation:Pattern:=`^[a-z]([-a-z0-9]*[a-z0-9])?$` + NodePoolName string `json:"nodePoolName"` + + // Version specifies the OpenShift version of the nodes associated with this machinepool. + // AROControlPlane version is used if not set. + // + // +optional + Version string `json:"version,omitempty"` + + // AROPlatformProfileMachinePool represents the NodePool Azure platform configuration. + Platform AROPlatformProfileMachinePool `json:"platform,omitempty"` + + // Labels specifies labels for the Kubernetes node objects + // +optional + Labels map[string]string `json:"labels,omitempty"` + + // Taints specifies the taints to apply to the nodes of the machine pool + // +optional + Taints []AROTaint `json:"taints,omitempty"` + + // AdditionalTags are user-defined tags to be added on the underlying EC2 instances associated with this machine pool. + // +immutable + // +optional + AdditionalTags infrav1.Tags `json:"additionalTags,omitempty"` + + // AutoRepair specifies whether health checks should be enabled for machines + // in the NodePool. The default is true. + // +kubebuilder:default=true + // +optional + AutoRepair bool `json:"autoRepair,omitempty"` + + // Autoscaling specifies auto scaling behaviour for this MachinePool. + // required if Replicas is not configured + // +optional + Autoscaling *AROMachinePoolAutoScaling `json:"autoscaling,omitempty"` +} + +// AROPlatformProfileMachinePool represents the Azure platform configuration. +type AROPlatformProfileMachinePool struct { + // Azure subnet id + Subnet string `json:"subnet,omitempty"` + + // Subnet Ref name that is used to create the VirtualNetworksSubnet CR. The SubnetRef must be in the same namespace as the AroMachinePool and cannot be set with Subnet. + SubnetRef string `json:"subnetRef,omitempty"` + + // VMSize sets the VM disk volume size to the node. + VMSize string `json:"vmSize,omitempty"` + + // DiskSizeGiB sets the disk volume size for the machine pool, in Gib. + DiskSizeGiB int32 `json:"diskSizeGiB,omitempty"` + + // DiskStorageAccountType represents supported Azure storage account types. + // Available values are Premium_LRS, StandardSSD_LRS and Standard_LRS. + DiskStorageAccountType string `json:"diskStorageAccountType,omitempty"` + + // AvailabilityZone specifying the availability zone where instances of this machine pool should run. + AvailabilityZone string `json:"availabilityZone,omitempty"` +} + +// AROTaint represents a taint to be applied to a node. +type AROTaint struct { + // The taint key to be applied to a node. + // + // +kubebuilder:validation:Required + Key string `json:"key"` + // The taint value corresponding to the taint key. + // + // +kubebuilder:validation:Pattern:=`^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$` + // +optional + Value string `json:"value,omitempty"` + // The effect of the taint on pods that do not tolerate the taint. + // Valid effects are NoSchedule, PreferNoSchedule and NoExecute. + // + // +kubebuilder:validation:Required + // +kubebuilder:validation:Enum=NoSchedule;PreferNoSchedule;NoExecute + Effect corev1.TaintEffect `json:"effect"` +} + +// AROMachinePoolAutoScaling specifies scaling options. +type AROMachinePoolAutoScaling struct { + // +kubebuilder:validation:Minimum=1 + MinReplicas int `json:"minReplicas,omitempty"` + // +kubebuilder:validation:Minimum=1 + MaxReplicas int `json:"maxReplicas,omitempty"` +} + +// AROMachinePoolStatus defines the observed state of AROMachinePool. +type AROMachinePoolStatus struct { + // Ready denotes that the AROMachinePool nodepool has joined + // the cluster + // +kubebuilder:default=false + Ready bool `json:"ready"` + // Replicas is the most recently observed number of replicas. + // +optional + Replicas int32 `json:"replicas"` + // Conditions defines current service state of the managed machine pool + // +optional + Conditions clusterv1.Conditions `json:"conditions,omitempty"` + // FailureMessage will be set in the event that there is a terminal problem + // reconciling the state and will be set to a descriptive error message. + // + // This field should not be set for transitive errors that a controller + // faces that are expected to be fixed automatically over + // time (like service outages), but instead indicate that something is + // fundamentally wrong with the spec or the configuration of + // the controller, and that manual intervention is required. + // + // +optional + FailureMessage *string `json:"failureMessage,omitempty"` + + // ID is the ID given by ARO. + ID string `json:"id,omitempty"` + + // Available upgrades for the ARO MachinePool. + AvailableUpgrades []string `json:"availableUpgrades,omitempty"` + + // ProvisioningState represents the asynchronous provisioning state of an ARM resource. + // Allowed values are; Succeeded, Failed, Canceled, Accepted, Deleting, Provisioning and Updating. + ProvisioningState string `json:"provisioningState,omitempty"` + + // ARO-HCP OpenShift semantic version, for example "4.20.0". + Version string `json:"version"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:resource:path=aromachinepools,scope=Namespaced,categories=cluster-api,shortName=aromp +// +kubebuilder:storageversion +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.ready",description="MachinePool ready status" +// +kubebuilder:printcolumn:name="Replicas",type="integer",JSONPath=".status.replicas",description="Number of replicas" +// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=aromachinepools,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=aromachinepools/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=aromachinepools/finalizers,verbs=update + +// AROMachinePool is the Schema for the aromachinepools API. +type AROMachinePool struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec AROMachinePoolSpec `json:"spec,omitempty"` + Status AROMachinePoolStatus `json:"status,omitempty"` +} + +const ( + // AROMachinePoolKind is the kind for AROMachinePool. + AROMachinePoolKind = "AROMachinePool" + + // AROMachinePoolFinalizer is the finalizer added to AROControlPlanes. + AROMachinePoolFinalizer = "aromachinepool/finalizer" +) + +// +kubebuilder:object:root=true + +// AROMachinePoolList contains a list of AROMachinePools. +type AROMachinePoolList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []AROMachinePool `json:"items"` +} + +// GetConditions returns the observations of the operational state of the AROMachinePool resource. +func (r *AROMachinePool) GetConditions() clusterv1.Conditions { + return r.Status.Conditions +} + +// SetConditions sets the underlying service state of the AROMachinePool to the predescribed clusterv1.Conditions. +func (r *AROMachinePool) SetConditions(conditions clusterv1.Conditions) { + r.Status.Conditions = conditions +} + +func init() { + SchemeBuilder.Register(&AROMachinePool{}, &AROMachinePoolList{}) +} diff --git a/exp/api/v1beta2/groupversion_info.go b/exp/api/v1beta2/groupversion_info.go new file mode 100644 index 00000000000..92c1e37ef47 --- /dev/null +++ b/exp/api/v1beta2/groupversion_info.go @@ -0,0 +1,36 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package v1beta2 contains API Schema definitions for the exp v1beta2 API group +// +kubebuilder:object:generate=true +// +groupName=infrastructure.cluster.x-k8s.io +package v1beta2 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects. + GroupVersion = schema.GroupVersion{Group: "infrastructure.cluster.x-k8s.io", Version: "v1beta2"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme. + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/exp/api/v1beta2/zz_generated.deepcopy.go b/exp/api/v1beta2/zz_generated.deepcopy.go new file mode 100644 index 00000000000..c49f97dae14 --- /dev/null +++ b/exp/api/v1beta2/zz_generated.deepcopy.go @@ -0,0 +1,307 @@ +//go:build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1beta2 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" + apiv1beta1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" + "sigs.k8s.io/cluster-api/api/v1beta1" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AROCluster) DeepCopyInto(out *AROCluster) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AROCluster. +func (in *AROCluster) DeepCopy() *AROCluster { + if in == nil { + return nil + } + out := new(AROCluster) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AROCluster) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AROClusterList) DeepCopyInto(out *AROClusterList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]AROCluster, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AROClusterList. +func (in *AROClusterList) DeepCopy() *AROClusterList { + if in == nil { + return nil + } + out := new(AROClusterList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AROClusterList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AROClusterSpec) DeepCopyInto(out *AROClusterSpec) { + *out = *in + out.ControlPlaneEndpoint = in.ControlPlaneEndpoint +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AROClusterSpec. +func (in *AROClusterSpec) DeepCopy() *AROClusterSpec { + if in == nil { + return nil + } + out := new(AROClusterSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AROClusterStatus) DeepCopyInto(out *AROClusterStatus) { + *out = *in + if in.FailureDomains != nil { + in, out := &in.FailureDomains, &out.FailureDomains + *out = make(v1beta1.FailureDomains, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make(v1beta1.Conditions, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AROClusterStatus. +func (in *AROClusterStatus) DeepCopy() *AROClusterStatus { + if in == nil { + return nil + } + out := new(AROClusterStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AROMachinePool) DeepCopyInto(out *AROMachinePool) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AROMachinePool. +func (in *AROMachinePool) DeepCopy() *AROMachinePool { + if in == nil { + return nil + } + out := new(AROMachinePool) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AROMachinePool) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AROMachinePoolAutoScaling) DeepCopyInto(out *AROMachinePoolAutoScaling) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AROMachinePoolAutoScaling. +func (in *AROMachinePoolAutoScaling) DeepCopy() *AROMachinePoolAutoScaling { + if in == nil { + return nil + } + out := new(AROMachinePoolAutoScaling) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AROMachinePoolList) DeepCopyInto(out *AROMachinePoolList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]AROMachinePool, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AROMachinePoolList. +func (in *AROMachinePoolList) DeepCopy() *AROMachinePoolList { + if in == nil { + return nil + } + out := new(AROMachinePoolList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AROMachinePoolList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AROMachinePoolSpec) DeepCopyInto(out *AROMachinePoolSpec) { + *out = *in + out.Platform = in.Platform + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Taints != nil { + in, out := &in.Taints, &out.Taints + *out = make([]AROTaint, len(*in)) + copy(*out, *in) + } + if in.AdditionalTags != nil { + in, out := &in.AdditionalTags, &out.AdditionalTags + *out = make(apiv1beta1.Tags, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Autoscaling != nil { + in, out := &in.Autoscaling, &out.Autoscaling + *out = new(AROMachinePoolAutoScaling) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AROMachinePoolSpec. +func (in *AROMachinePoolSpec) DeepCopy() *AROMachinePoolSpec { + if in == nil { + return nil + } + out := new(AROMachinePoolSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AROMachinePoolStatus) DeepCopyInto(out *AROMachinePoolStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make(v1beta1.Conditions, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.FailureMessage != nil { + in, out := &in.FailureMessage, &out.FailureMessage + *out = new(string) + **out = **in + } + if in.AvailableUpgrades != nil { + in, out := &in.AvailableUpgrades, &out.AvailableUpgrades + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AROMachinePoolStatus. +func (in *AROMachinePoolStatus) DeepCopy() *AROMachinePoolStatus { + if in == nil { + return nil + } + out := new(AROMachinePoolStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AROPlatformProfileMachinePool) DeepCopyInto(out *AROPlatformProfileMachinePool) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AROPlatformProfileMachinePool. +func (in *AROPlatformProfileMachinePool) DeepCopy() *AROPlatformProfileMachinePool { + if in == nil { + return nil + } + out := new(AROPlatformProfileMachinePool) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AROTaint) DeepCopyInto(out *AROTaint) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AROTaint. +func (in *AROTaint) DeepCopy() *AROTaint { + if in == nil { + return nil + } + out := new(AROTaint) + in.DeepCopyInto(out) + return out +} diff --git a/exp/controllers/arocluster_controller.go b/exp/controllers/arocluster_controller.go new file mode 100644 index 00000000000..c61bc1efbaf --- /dev/null +++ b/exp/controllers/arocluster_controller.go @@ -0,0 +1,101 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controllers + +import ( + "context" + "fmt" + + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + "sigs.k8s.io/cluster-api/util" + "sigs.k8s.io/cluster-api/util/predicates" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/handler" + + infracontroller "sigs.k8s.io/cluster-api-provider-azure/controllers" + infrav2exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1beta2" + "sigs.k8s.io/cluster-api-provider-azure/util/tele" +) + +// AROClusterReconciler reconciles a AROCluster object. +type AROClusterReconciler struct { + client.Client + WatchFilterValue string +} + +// SetupWithManager sets up the controller with the Manager. +func (r *AROClusterReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { + ctx, log, done := tele.StartSpanWithLogger(ctx, + "controllers.AROClusterReconciler.SetupWithManager", + tele.KVP("controller", infrav2exp.AROClusterKind), + ) + defer done() + + _, err := ctrl.NewControllerManagedBy(mgr). + WithOptions(options). + For(&infrav2exp.AROCluster{}). + WithEventFilter(predicates.ResourceHasFilterLabel(mgr.GetScheme(), log, r.WatchFilterValue)). + WithEventFilter(predicates.ResourceIsNotExternallyManaged(mgr.GetScheme(), log)). + // Watch clusters for pause/unpause notifications + Watches( + &clusterv1.Cluster{}, + handler.EnqueueRequestsFromMapFunc( + util.ClusterToInfrastructureMapFunc(ctx, infrav2exp.GroupVersion.WithKind(infrav2exp.AROClusterKind), mgr.GetClient(), &infrav2exp.AROCluster{}), + ), + builder.WithPredicates( + predicates.ResourceHasFilterLabel(mgr.GetScheme(), log, r.WatchFilterValue), + infracontroller.ClusterUpdatePauseChange(log), + ), + ). + Build(r) + if err != nil { + return fmt.Errorf("creating new controller manager: %w", err) + } + + return nil +} + +// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=aroclusters,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=aroclusters/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=aroclusters/finalizers,verbs=update + +// Reconcile reconciles an AROCluster. +func (r *AROClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, resultErr error) { + ctx, log, done := tele.StartSpanWithLogger(ctx, + "controllers.AROClusterReconciler.Reconcile", + tele.KVP("namespace", req.Namespace), + tele.KVP("name", req.Name), + tele.KVP("kind", infrav2exp.AROClusterKind), + ) + defer done() + + log = log.WithValues("namespace", req.Namespace, "AROCluster", req.Name) + + // Fetch the AROCluster instance + aroCluster := &infrav2exp.AROCluster{} + err := r.Get(ctx, req.NamespacedName, aroCluster) + if err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + err = fmt.Errorf("not implemented") + log.Error(err, fmt.Sprintf("Reconciling %s", infrav2exp.AROClusterKind)) + return ctrl.Result{}, err +} diff --git a/exp/controllers/arocontrolplane_controller.go b/exp/controllers/arocontrolplane_controller.go new file mode 100644 index 00000000000..80d239cd5d3 --- /dev/null +++ b/exp/controllers/arocontrolplane_controller.go @@ -0,0 +1,86 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controllers + +import ( + "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/cluster-api/util/predicates" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + + control2exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/controlplane/v1beta2" + infrav2exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1beta2" + "sigs.k8s.io/cluster-api-provider-azure/util/tele" +) + +// AROControlPlaneReconciler reconciles a AroControlPlane object. +type AROControlPlaneReconciler struct { + client.Client + WatchFilterValue string +} + +// SetupWithManager sets up the controller with the Manager. +func (r *AROControlPlaneReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { + _, log, done := tele.StartSpanWithLogger(ctx, + "controllers.AROControlPlaneReconciler.SetupWithManager", + tele.KVP("controller", control2exp.AROControlPlaneKind), + ) + defer done() + + _, err := ctrl.NewControllerManagedBy(mgr). + WithOptions(options). + For(&control2exp.AROControlPlane{}). + WithEventFilter(predicates.ResourceHasFilterLabel(mgr.GetScheme(), log, r.WatchFilterValue)). + Owns(&corev1.Secret{}). + Build(r) + if err != nil { + return fmt.Errorf("creating new controller manager: %w", err) + } + + return nil +} + +//+kubebuilder:rbac:groups=controlplane.cluster.x-k8s.io,resources=arocontrolplanes,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=controlplane.cluster.x-k8s.io,resources=arocontrolplanes/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=controlplane.cluster.x-k8s.io,resources=arocontrolplanes/finalizers,verbs=update + +// Reconcile reconciles an AROControlPlane. +func (r *AROControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, resultErr error) { + ctx, log, done := tele.StartSpanWithLogger(ctx, + "controllers.AROControlPlaneReconciler.Reconcile", + tele.KVP("namespace", req.Namespace), + tele.KVP("name", req.Name), + tele.KVP("kind", control2exp.AROControlPlaneKind), + ) + defer done() + + log = log.WithValues("namespace", req.Namespace, "azureControlPlane", req.Name) + + aroControlPlane := &control2exp.AROControlPlane{} + err := r.Get(ctx, req.NamespacedName, aroControlPlane) + if err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + err = fmt.Errorf("not implemented") + log.Error(err, fmt.Sprintf("Reconciling %s", infrav2exp.AROMachinePoolKind)) + return ctrl.Result{}, err +} diff --git a/exp/controllers/aromachinepool_controller.go b/exp/controllers/aromachinepool_controller.go new file mode 100644 index 00000000000..5783de3e41c --- /dev/null +++ b/exp/controllers/aromachinepool_controller.go @@ -0,0 +1,83 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controllers + +import ( + "context" + "fmt" + + "sigs.k8s.io/cluster-api/util/predicates" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + + infrav2exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1beta2" + "sigs.k8s.io/cluster-api-provider-azure/util/tele" +) + +// AroMachinePoolReconciler reconciles an AroMachinePool object. +type AroMachinePoolReconciler struct { + client.Client + WatchFilterValue string +} + +// SetupWithManager sets up the controller with the Manager. +func (r *AroMachinePoolReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { + _, log, done := tele.StartSpanWithLogger(ctx, + "controllers.AroMachinePoolReconciler.SetupWithManager", + tele.KVP("controller", infrav2exp.AROMachinePoolKind), + ) + defer done() + + _, err := ctrl.NewControllerManagedBy(mgr). + WithOptions(options). + For(&infrav2exp.AROMachinePool{}). + WithEventFilter(predicates.ResourceHasFilterLabel(mgr.GetScheme(), log, r.WatchFilterValue)). + Build(r) + if err != nil { + return fmt.Errorf("creating new controller manager: %w", err) + } + + return nil +} + +// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=aromachinepools,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=aromachinepools/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=aromachinepools/finalizers,verbs=update + +// Reconcile reconciles an AroMachinePool. +func (r *AroMachinePoolReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, resultErr error) { + ctx, log, done := tele.StartSpanWithLogger(ctx, + "controllers.AroMachinePoolReconciler.Reconcile", + tele.KVP("namespace", req.Namespace), + tele.KVP("name", req.Name), + tele.KVP("kind", infrav2exp.AROMachinePoolKind), + ) + defer done() + + log = log.WithValues("namespace", req.Namespace, "azureMachinePool", req.Name) + + aroMachinePool := &infrav2exp.AROMachinePool{} + err := r.Get(ctx, req.NamespacedName, aroMachinePool) + if err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + err = fmt.Errorf("not implemented") + log.Error(err, fmt.Sprintf("Reconciling %s", infrav2exp.AROMachinePoolKind)) + return ctrl.Result{}, err +} diff --git a/feature/feature.go b/feature/feature.go index 31ca915e0a6..044b2b0f26d 100644 --- a/feature/feature.go +++ b/feature/feature.go @@ -58,6 +58,11 @@ const ( // owner: @nawazkh // alpha: v1.18 APIServerILB featuregate.Feature = "APIServerILB" + + // ARO is the feature gate for enabling the ARO support. + // owner: @marek-veber + // alpha: v1.19 + ARO featuregate.Feature = "ARO" ) func init() { @@ -73,4 +78,5 @@ var defaultCAPZFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{ EdgeZone: {Default: false, PreRelease: featuregate.Alpha}, ASOAPI: {Default: true, PreRelease: featuregate.GA}, APIServerILB: {Default: false, PreRelease: featuregate.Alpha}, + ARO: {Default: false, PreRelease: featuregate.Alpha}, } diff --git a/go.mod b/go.mod index 0d458824264..207314f5cd4 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.23.2 toolchain go1.23.8 require ( + github.com/Azure/azure-sdk-for-go v68.0.0+incompatible github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.2.0 @@ -82,6 +83,8 @@ require ( github.com/Azure/go-autorest/autorest/adal v0.9.24 // indirect github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect + github.com/Azure/go-autorest/autorest/to v0.4.1 // indirect + github.com/Azure/go-autorest/autorest/validation v0.3.2 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect diff --git a/go.sum b/go.sum index 2ed656c3c54..2ff2fcdb9d9 100644 --- a/go.sum +++ b/go.sum @@ -7,6 +7,7 @@ dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.0 h1:j8BorDEigD8UFOSZQiSqAMOOleyQOOQPnUAwV+Ls1gA= @@ -120,6 +121,10 @@ github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSY github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw= github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= +github.com/Azure/go-autorest/autorest/to v0.4.1 h1:CxNHBqdzTr7rLtdrtb5CMjJcDut+WNGCVv7OmS5+lTc= +github.com/Azure/go-autorest/autorest/to v0.4.1/go.mod h1:EtaofgU4zmtvn1zT2ARsjRFdq9vXx0YWtmElwL+GZ9M= +github.com/Azure/go-autorest/autorest/validation v0.3.2 h1:myD3tcvs+Fk1bkJ1Xx7xidop4z4FWvWADiMGMXeVd2E= +github.com/Azure/go-autorest/autorest/validation v0.3.2/go.mod h1:4z7eU88lSINAB5XL8mhfPumiUdoAQo/c7qXwbsM8Zhc= github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= diff --git a/main.go b/main.go index a55a3629005..88a9c0de324 100644 --- a/main.go +++ b/main.go @@ -61,7 +61,9 @@ import ( infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" "sigs.k8s.io/cluster-api-provider-azure/azure" "sigs.k8s.io/cluster-api-provider-azure/controllers" + cplanev1beta2exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/controlplane/v1beta2" infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1beta1" + infrav1beta2exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1beta2" infrav1controllersexp "sigs.k8s.io/cluster-api-provider-azure/exp/controllers" "sigs.k8s.io/cluster-api-provider-azure/feature" "sigs.k8s.io/cluster-api-provider-azure/pkg/coalescing" @@ -79,6 +81,8 @@ func init() { _ = clientgoscheme.AddToScheme(scheme) _ = infrav1.AddToScheme(scheme) _ = infrav1exp.AddToScheme(scheme) + _ = cplanev1beta2exp.AddToScheme(scheme) + _ = infrav1beta2exp.AddToScheme(scheme) _ = clusterv1.AddToScheme(scheme) _ = expv1.AddToScheme(scheme) _ = kubeadmv1.AddToScheme(scheme) @@ -606,6 +610,31 @@ func registerControllers(ctx context.Context, mgr manager.Manager) { os.Exit(1) } } + if feature.Gates.Enabled(feature.ARO) { + if err := (&infrav1controllersexp.AROClusterReconciler{ + Client: mgr.GetClient(), + WatchFilterValue: watchFilterValue, + }).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: azureClusterConcurrency}); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "AROCluster") + os.Exit(1) + } + + if err := (&infrav1controllersexp.AROControlPlaneReconciler{ + Client: mgr.GetClient(), + WatchFilterValue: watchFilterValue, + }).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: azureClusterConcurrency}); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "AROControlPlane") + os.Exit(1) + } + + if err := (&infrav1controllersexp.AroMachinePoolReconciler{ + Client: mgr.GetClient(), + WatchFilterValue: watchFilterValue, + }).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: azureMachinePoolConcurrency}); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "AROMachinePool") + os.Exit(1) + } + } } func registerWebhooks(mgr manager.Manager) {