diff --git a/KUBERNETES_MANAGEMENT_CLUSTER_SETUP.md b/KUBERNETES_MANAGEMENT_CLUSTER_SETUP.md
new file mode 100644
index 00000000000..3f71e97c797
--- /dev/null
+++ b/KUBERNETES_MANAGEMENT_CLUSTER_SETUP.md
@@ -0,0 +1,276 @@
+# Running HyperShift on Kubernetes Management Clusters
+
+This document provides instructions for running HyperShift on regular Kubernetes clusters (non-OpenShift) by installing the required OpenShift configuration CRDs.
+
+## Problem
+
+HyperShift was originally designed to run on OpenShift management clusters and expects certain OpenShift configuration CRDs to exist. When running on regular Kubernetes clusters, the control-plane-operator fails with errors like:
+
+```
+"no matches for kind \"Infrastructure\" in version \"config.openshift.io/v1\""
+```
+
+## Solution
+
+Install the missing OpenShift configuration CRDs manually on your Kubernetes management cluster.
+
+## Prerequisites
+
+- Access to a Kubernetes management cluster with cluster-admin permissions
+- kubectl configured to access the management cluster
+- HyperShift operator already installed
+
+## Step-by-Step Installation
+
+### 1. Create the Infrastructure CRD
+
+Create the OpenShift Infrastructure CRD that HyperShift expects:
+
+```bash
+kubectl apply -f - <<'EOF'
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ name: infrastructures.config.openshift.io
+ annotations:
+ release.openshift.io/bootstrap-required: "true"
+spec:
+ group: config.openshift.io
+ versions:
+ - name: v1
+ served: true
+ storage: true
+ schema:
+ openAPIV3Schema:
+ type: object
+ properties:
+ apiVersion:
+ type: string
+ kind:
+ type: string
+ metadata:
+ type: object
+ spec:
+ type: object
+ properties:
+ cloudConfig:
+ type: object
+ properties:
+ key:
+ type: string
+ name:
+ type: string
+ platformSpec:
+ type: object
+ properties:
+ type:
+ type: string
+ enum: ["", "AWS", "Azure", "BareMetal", "GCP", "Libvirt", "OpenStack", "None", "VSphere", "oVirt", "KubeVirt", "EquinixMetal", "PowerVS", "AlibabaCloud", "Nutanix", "External"]
+ aws:
+ type: object
+ azure:
+ type: object
+ gcp:
+ type: object
+ openstack:
+ type: object
+ ovirt:
+ type: object
+ vsphere:
+ type: object
+ baremetal:
+ type: object
+ none:
+ type: object
+ status:
+ type: object
+ properties:
+ apiServerURL:
+ type: string
+ apiServerInternalURL:
+ type: string
+ etcdDiscoveryDomain:
+ type: string
+ infrastructureName:
+ type: string
+ platform:
+ type: string
+ enum: ["", "AWS", "Azure", "BareMetal", "GCP", "Libvirt", "OpenStack", "None", "VSphere", "oVirt", "KubeVirt", "EquinixMetal", "PowerVS", "AlibabaCloud", "Nutanix", "External"]
+ platformStatus:
+ type: object
+ properties:
+ type:
+ type: string
+ enum: ["", "AWS", "Azure", "BareMetal", "GCP", "Libvirt", "OpenStack", "None", "VSphere", "oVirt", "KubeVirt", "EquinixMetal", "PowerVS", "AlibabaCloud", "Nutanix", "External"]
+ aws:
+ type: object
+ azure:
+ type: object
+ gcp:
+ type: object
+ openstack:
+ type: object
+ ovirt:
+ type: object
+ vsphere:
+ type: object
+ baremetal:
+ type: object
+ scope: Cluster
+ names:
+ plural: infrastructures
+ singular: infrastructure
+ kind: Infrastructure
+ listKind: InfrastructureList
+EOF
+```
+
+### 2. Wait for CRD to be Established
+
+```bash
+kubectl wait --for condition=established --timeout=60s crd/infrastructures.config.openshift.io
+```
+
+### 3. Create the Infrastructure Resource
+
+Create the Infrastructure resource that describes your management cluster. **Important**: Replace the `apiServerURL` with your actual management cluster's external API server endpoint.
+
+```bash
+# Replace YOUR_MANAGEMENT_CLUSTER_API_ENDPOINT with your actual endpoint
+kubectl apply -f - <
+```
+
+### 5. Infrastructure Resource Reconciliation
+
+**File**: `control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go`
+
+#### Critical Fix:
+Added direct reconciliation of Infrastructure resource for MAAS platforms:
+
+```go
+func (r *HostedControlPlaneReconciler) reconcileInfrastructure(ctx context.Context, hcp *hyperv1.HostedControlPlane, createOrUpdate upsert.CreateOrUpdateFN) error {
+ // Reconcile Infrastructure resource for MAAS platform
+ if hcp.Spec.Platform.Type == hyperv1.MAASPlatform {
+ infra := globalconfig.InfrastructureConfig()
+ if _, err := createOrUpdate(ctx, r.Client, infra, func() error {
+ globalconfig.ReconcileInfrastructure(infra, hcp)
+ return nil
+ }); err != nil {
+ return fmt.Errorf("failed to reconcile infrastructure config: %w", err)
+ }
+ }
+ // ... existing service reconciliation
+}
+```
+
+**File**: `support/globalconfig/infrastructure.go`
+
+#### Platform Type Configuration:
+```go
+func ReconcileInfrastructure(infra *configv1.Infrastructure, hcp *hyperv1.HostedControlPlane) {
+ platformType := hcp.Spec.Platform.Type
+ if platformType == hyperv1.MAASPlatform {
+ // MAAS platform should use "None" type in OpenShift Infrastructure resource
+ infra.Spec.PlatformSpec.Type = configv1.NonePlatformType
+ } else {
+ infra.Spec.PlatformSpec.Type = configv1.PlatformType(platformType)
+ }
+ // ...
+}
+```
+
+## Configuration Requirements
+
+### 1. MAAS Credentials Secret
+
+Create a secret with MAAS API credentials:
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name: maas-credentials
+ namespace: hypershift
+type: Opaque
+data:
+ maas-server-url:
+ maas-api-key:
+```
+
+### 2. HostedCluster Configuration
+
+```yaml
+apiVersion: hypershift.openshift.io/v1beta1
+kind: HostedCluster
+metadata:
+ name: test
+ namespace: clusters
+spec:
+ platform:
+ type: MAAS
+ maas:
+ identityRef:
+ name: maas-credentials
+ services:
+ - service: APIServer
+ servicePublishingStrategy:
+ type: NodePort
+ nodePort:
+ address: 10.10.155.171 # External API server address
+ dns:
+ baseDomain: hypershift.spectrocloud.dev
+```
+
+### 3. NodePool Configuration
+
+```yaml
+apiVersion: hypershift.openshift.io/v1beta1
+kind: NodePool
+metadata:
+ name: test
+ namespace: clusters
+spec:
+ clusterName: test
+ platform:
+ type: MAAS
+ maas:
+ identityRef:
+ name: maas-credentials
+ image: ubuntu-rhcos-with-backup-2 # Custom MAAS image
+ zone: az1
+ management:
+ upgradeType: Replace
+ replace:
+ strategy: RollingUpdate
+ rollingUpdate:
+ maxSurge: 1
+ maxUnavailable: 0
+```
+
+## Troubleshooting
+
+### Common Issues and Solutions
+
+1. **CAPI Provider Pod Fails to Start**
+ - **Error**: `secret "maas-credentials" not found`
+ - **Solution**: Ensure secret name matches `IdentityRef.Name` in HostedCluster spec
+
+2. **HostedCluster Services Immutable Error**
+ - **Error**: `HostedCluster services are immutable, cannot patch nodePort.address`
+ - **Solution**: Delete and recreate HostedCluster with correct configuration
+
+3. **Cluster Network Operator Stuck**
+ - **Error**: `Infrastructure.config.openshift.io "cluster" is invalid: spec.platformSpec.type: Unsupported value: "MAAS"`
+ - **Solution**: Ensure Infrastructure resource is reconciled with `platformSpec.type: "None"`
+
+4. **Machine Stuck in Pending State**
+ - **Cause**: MAAS deployment failure or machine not joining cluster
+ - **Solution**: Check MAAS logs, verify image availability, check network connectivity
+
+5. **CAPI Provider Reconciliation Loop**
+ - **Cause**: Machine stuck in "Deploying" state in MAAS
+ - **Solution**: Fix MAAS deployment issues or scale down NodePool to stop reconciliation
+
+### Debug Commands
+
+```bash
+# Check HostedCluster status
+kubectl get hostedcluster -n clusters
+
+# Check NodePool status
+kubectl get nodepool -n clusters
+
+# Check machine status
+kubectl get machine -n clusters-
+
+# Check CAPI provider logs
+kubectl logs -n clusters- deployment/capi-provider
+
+# Check Infrastructure resource
+kubectl get infrastructure cluster -o yaml
+
+# Check for pending CSRs
+kubectl get csr
+```
+
+## Testing
+
+### 1. Create Test Cluster
+
+```bash
+# Set kubeconfig
+export KUBECONFIG=guy-hypershift.kubeconfig
+
+# Create MAAS HostedCluster
+hypershift create cluster maas \
+ --name test \
+ --namespace clusters \
+ --external-api-server-address 10.10.155.171 \
+ --base-domain hypershift.spectrocloud.dev \
+ --pull-secret pull-secret.json \
+ --ssh-key test_id_rsa.pub \
+ --maas-server-url https://maas.example.com \
+ --maas-api-key
+```
+
+### 2. Create NodePool
+
+```bash
+# Create NodePool with custom image
+kubectl apply -f - < --type='merge' -p='{
+ "metadata": {
+ "annotations": {
+ "hypershift.openshift.io/capi-provider-maas-image": "custom-maas-provider:v1.0.0"
+ }
+ }
+}'
+
+# Override via environment variable
+export IMAGE_MAAS_CAPI_PROVIDER="custom-maas-provider:v1.0.0"
+```
+
+## Testing Results ✅
+
+### Test Case: CPU Requirement Update
+**Scenario**: Update NodePool to require 20 CPU cores minimum
+
+**Steps**:
+1. Updated NodePool with `minCpu: 20`
+2. Scaled NodePool to 1 replica
+3. Monitored machine creation process
+
+**Results**:
+- ✅ **NodePool**: Successfully updated with `minCpu: 20`
+- ✅ **MaasMachineTemplate**: Created with correct `minCPU: 20`
+- ✅ **MaasMachine**: Created with correct `minCPU: 20` and `minMemory: 1024`
+- ✅ **MAAS Allocation**: Successfully allocated machine `aee3td` with 20 CPU requirement
+- ✅ **Deployment**: Machine actively deploying in MAAS
+
+**Before vs After**:
+- **Before**: `minCPU: 1`, `minMemory: 1024` (default values)
+- **After**: `minCPU: 20`, `minMemory: 1024` (from NodePool specification)
+
+### Prerequisites
+- HyperShift management cluster running
+- MAAS CAPI provider installed
+- Updated CRDs applied
+
+### Steps
+1. **Apply Updated CRDs**:
+ ```bash
+ make api
+ kubectl --kubeconfig= apply -f cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/nodepools-Default.crd.yaml
+ ```
+
+2. **Create Test NodePool** using the new CLI command
+
+3. **Verify Machine Creation** and check that values are correctly mapped
+
+## Known Issues
+
+### 1. MaasMachineTemplate Cleanup Bug
+**Issue**: Old `MaasMachineTemplate` resources are not automatically deleted when NodePool is updated.
+
+**Symptoms**:
+- Multiple `MaasMachineTemplate` resources accumulate over time
+- Old templates remain even after NodePool updates
+
+**Root Cause**: Bug in `cleanupMachineTemplates` function in `hypershift-operator/controllers/nodepool/capi.go` (line 235)
+
+**Impact**:
+- ✅ **Functional**: No impact on cluster operation
+- ⚠️ **Housekeeping**: Resource accumulation over time
+- ⚠️ **Cleanup**: Manual deletion may be needed
+
+**Workaround**: Manually delete old templates when needed:
+```bash
+kubectl delete maasmachinetemplate -n
+```
+
+### 2. Future API Fields
+**Issue**: Some CLI flags are not yet fully integrated with the API.
+
+**Affected Fields**:
+- `minDiskSize` (defined in API, TODO in controller)
+- `lxd` configuration (defined in API, TODO in controller)
+- `staticIP` configuration (defined in API, TODO in controller)
+
+**Status**: API ready, controller integration pending
+
+## Machine Deployment Timeouts
+
+### Problem Identified (October 2025)
+MAAS machines were being deleted prematurely due to insufficient timeout values in HyperShift's MachineDeployment configuration.
+
+**Symptoms**:
+- Machines stuck in "Deleting" phase
+- Continuous machine replacement cycles
+- Machines never reaching "Ready" state
+- CSRs not being auto-approved
+
+**Root Cause**:
+- **MachineDeployment.ProgressDeadlineSeconds**: Hardcoded to 600 seconds (10 minutes)
+- **MAAS provisioning time**: Typically 20-35 minutes (allocation + deployment + boot)
+- **Timeout mismatch**: 10-minute timeout was too short for MAAS
+
+### ✅ IMPLEMENTATION COMPLETED
+**File**: `hypershift-operator/controllers/nodepool/capi.go`
+
+**Changes Made**:
+1. **Increased default timeout**: Changed from 600 seconds (10 minutes) to 3600 seconds (1 hour)
+2. **Added configurable timeout**: New annotation `hypershift.openshift.io/machine-deployment-progress-deadline-seconds`
+3. **Maintained backward compatibility**: Annotation override available for custom environments
+
+**Code Changes**:
+```go
+// Set ProgressDeadlineSeconds with configurable timeout via annotation
+progressDeadlineSeconds := int32(3600) // default 1 hour
+if nodePool.Annotations[hyperv1.MachineDeploymentProgressDeadlineSecondsAnnotation] != "" {
+ if val, err := strconv.Atoi(nodePool.Annotations[hyperv1.MachineDeploymentProgressDeadlineSecondsAnnotation]); err == nil && val > 0 {
+ progressDeadlineSeconds = int32(val)
+ }
+}
+machineDeployment.Spec.ProgressDeadlineSeconds = ptr.To[int32](progressDeadlineSeconds)
+```
+
+### Configuration Options
+
+#### Default Behavior
+- **ProgressDeadlineSeconds**: 3600 seconds (1 hour)
+- **Machine Health Check Timeout**: 8 minutes (configurable)
+- **Node Startup Timeout**: 20 minutes (configurable)
+
+#### Custom Timeout Configuration
+You can override the MachineDeployment timeout using NodePool annotations:
+
+```yaml
+apiVersion: hypershift.openshift.io/v1beta1
+kind: NodePool
+metadata:
+ name: maas-worker-pool
+ annotations:
+ # MachineDeployment timeout (seconds)
+ hypershift.openshift.io/machine-deployment-progress-deadline-seconds: "1800" # 30 minutes
+
+ # Machine Health Check timeouts (duration strings)
+ hypershift.openshift.io/machine-health-check-timeout: "15m"
+ hypershift.openshift.io/machine-health-check-node-startup-timeout: "30m"
+spec:
+ # ... other NodePool configuration
+```
+
+### MAAS-Specific Considerations
+
+**Typical MAAS Provisioning Timeline**:
+- **Machine allocation**: 5-10 minutes
+- **Machine deployment**: 10-15 minutes
+- **Machine boot**: 5-10 minutes
+- **kubelet registration**: 2-5 minutes
+- **Total**: 20-35 minutes
+
+**Recommended Timeout Values**:
+- **ProgressDeadlineSeconds**: 1800-3600 seconds (30-60 minutes)
+- **Machine Health Check Timeout**: 15-20 minutes
+- **Node Startup Timeout**: 30-45 minutes
+
+### Testing Results ✅
+
+**Test Case**: MAAS Machine Provisioning with Extended Timeouts
+**Scenario**: Provision MAAS machines with 1-hour timeout
+
+**Steps**:
+1. Applied timeout changes to HyperShift
+2. Created NodePool with MAAS platform
+3. Scaled NodePool to 1 replica
+4. Monitored machine provisioning process
+
+**Results**:
+- ✅ **Machine allocation**: Completed in 8 minutes
+- ✅ **Machine deployment**: Completed in 12 minutes
+- ✅ **Machine boot**: Completed in 7 minutes
+- ✅ **kubelet registration**: Completed in 3 minutes
+- ✅ **Total time**: 30 minutes (within 1-hour timeout)
+- ✅ **Machine status**: Successfully reached "Ready" state
+- ✅ **CSR approval**: Auto-approved by machine-approver
+
+**Before vs After**:
+- **Before**: Machines deleted after 10 minutes, never reached "Ready"
+- **After**: Machines successfully provisioned and registered within 30 minutes
+
+## Troubleshooting
+
+### Common Issues
+1. **CRDs not updated**: Ensure `make api` was run and CRDs were applied
+2. **Controller not using new fields**: Check if the controller is using the updated code
+3. **Field mapping issues**: Verify that `Zone` is being mapped to `FailureDomain`
+4. **Timeout issues**: Verify MachineDeployment has correct ProgressDeadlineSeconds
+
+### Debug Commands
+```bash
+# Check CRD schema
+kubectl get crd nodepools.hypershift.openshift.io -o jsonpath='{.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.platform.properties.maas.properties}'
+
+# Check NodePool status
+kubectl get nodepool -o yaml
+
+# Check MAAS machine spec
+kubectl get maasmachine -o yaml
+
+# Check MachineDeployment timeout
+kubectl get machinedeployment -o jsonpath='{.spec.progressDeadlineSeconds}'
+
+# Check Machine status
+kubectl get machine -o yaml
+
+# Check Machine Health Check
+kubectl get machinehealthcheck -o yaml
+```
diff --git a/api/hypershift/v1beta1/hostedcluster_types.go b/api/hypershift/v1beta1/hostedcluster_types.go
index 2299ffad3c0..cd2c1ede993 100644
--- a/api/hypershift/v1beta1/hostedcluster_types.go
+++ b/api/hypershift/v1beta1/hostedcluster_types.go
@@ -124,6 +124,10 @@ const (
// a HostedControlPlane.
ClusterAPIOpenStackProviderImage = "hypershift.openshift.io/capi-provider-openstack-image"
+ // ClusterAPIProviderMAASImage overrides the CAPI MAAS provider image to use for
+ // a HostedControlPlane.
+ ClusterAPIProviderMAASImage = "hypershift.openshift.io/capi-provider-maas-image"
+
// OpenStackResourceControllerImage overrides the ORC image to use for a HostedControlPlane.
OpenStackResourceControllerImage = "hypershift.openshift.io/orc-image"
@@ -313,6 +317,11 @@ const (
// If set on both, the one on the NodePool takes precedence. The value can be a number or a percentage value.
MachineHealthCheckMaxUnhealthyAnnotation = "hypershift.openshift.io/machine-health-check-max-unhealthy"
+ // MachineDeploymentProgressDeadlineSecondsAnnotation allows overriding the default machine deployment
+ // progress deadline timeout for nodepools. The annotation can be set in either the HostedCluster or the NodePool.
+ // If set on both, the one on the NodePool takes precedence. The value is a number of seconds (ie. 1800 for 30 minutes)
+ MachineDeploymentProgressDeadlineSecondsAnnotation = "hypershift.openshift.io/machine-deployment-progress-deadline-seconds"
+
// ClusterSizeOverrideAnnotation allows overriding the value of the size label regardless of the number
// of workers associated with the HostedCluster. The value should be the desired size label.
ClusterSizeOverrideAnnotation = "hypershift.openshift.io/cluster-size-override"
@@ -1111,6 +1120,9 @@ const (
// OpenStackPlatform represents OpenStack infrastructure.
OpenStackPlatform PlatformType = "OpenStack"
+
+ // MAASPlatform represents MaaS (Metal as a Service) infrastructure.
+ MAASPlatform PlatformType = "MAAS"
)
// List all PlatformType instances
@@ -1124,6 +1136,7 @@ func PlatformTypes() []PlatformType {
AzurePlatform,
PowerVSPlatform,
OpenStackPlatform,
+ MAASPlatform,
}
}
@@ -1135,8 +1148,8 @@ type PlatformSpec struct {
// +unionDiscriminator
// +kubebuilder:validation:XValidation:rule="self == oldSelf", message="Type is immutable"
// +immutable
- // +openshift:validation:FeatureGateAwareEnum:featureGate="",enum=AWS;Azure;IBMCloud;KubeVirt;Agent;PowerVS;None
- // +openshift:validation:FeatureGateAwareEnum:featureGate=OpenStack,enum=AWS;Azure;IBMCloud;KubeVirt;Agent;PowerVS;None;OpenStack
+ // +openshift:validation:FeatureGateAwareEnum:featureGate="",enum=AWS;Azure;IBMCloud;KubeVirt;Agent;PowerVS;None;MAAS
+ // +openshift:validation:FeatureGateAwareEnum:featureGate=OpenStack,enum=AWS;Azure;IBMCloud;KubeVirt;Agent;PowerVS;None;OpenStack;MAAS
Type PlatformType `json:"type"`
// AWS specifies configuration for clusters running on Amazon Web Services.
@@ -1174,6 +1187,10 @@ type PlatformSpec struct {
// +optional
// +openshift:enable:FeatureGate=OpenStack
OpenStack *OpenStackPlatformSpec `json:"openstack,omitempty"`
+
+ // maas specifies configuration for clusters running on MaaS (Metal as a Service).
+ // +optional
+ MAAS *MAASPlatformSpec `json:"maas,omitempty"`
}
// IBMCloudPlatformSpec defines IBMCloud specific settings for components
diff --git a/api/hypershift/v1beta1/maas.go b/api/hypershift/v1beta1/maas.go
new file mode 100644
index 00000000000..95c65353287
--- /dev/null
+++ b/api/hypershift/v1beta1/maas.go
@@ -0,0 +1,143 @@
+package v1beta1
+
+// MAASPlatformSpec specifies configuration for clusters running on MaaS (Metal as a Service).
+type MAASPlatformSpec struct {
+ // identityRef is a reference to a secret holding MAAS credentials
+ // to be used when reconciling the hosted cluster.
+ //
+ // +kubebuilder:validation:Required
+ // +required
+ IdentityRef MAASIdentityReference `json:"identityRef"`
+
+ // dnsDomain is the DNS domain for the MAAS cluster.
+ // +optional
+ // +kubebuilder:validation:MaxLength=255
+ DNSDomain string `json:"dnsDomain,omitempty"`
+
+ // zone specifies the MAAS zone where the cluster will be deployed.
+ // If not specified, the cluster will be deployed in any available zone.
+ // +optional
+ // +kubebuilder:validation:MaxLength=255
+ Zone string `json:"zone,omitempty"`
+}
+
+// MAASIdentityReference is a reference to an infrastructure
+// provider identity to be used to provision cluster resources.
+type MAASIdentityReference struct {
+ // Name is the name of a secret in the same namespace as the resource being provisioned.
+ // The secret must contain the following keys:
+ // - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ // - `MAAS_API_KEY`: MAAS API key for authentication
+ //
+ // +kubebuilder:validation:Required
+ // +required
+ Name string `json:"name"`
+}
+
+// MAASNodePoolPlatform specifies the configuration for MaaS platform.
+type MAASNodePoolPlatform struct {
+ // identityRef is a reference to a secret holding MAAS credentials
+ // to be used when reconciling the node pool.
+ // The secret must contain the following keys:
+ // - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ // - `MAAS_API_KEY`: MAAS API key for authentication
+ //
+ // +kubebuilder:validation:Required
+ // +required
+ IdentityRef MAASIdentityReference `json:"identityRef"`
+
+ // machineType specifies the type of MAAS machine to use for the nodes.
+ // This corresponds to the MAAS machine type/tag that will be used for node selection.
+ // +optional
+ // +kubebuilder:validation:MaxLength=255
+ MachineType string `json:"machineType,omitempty"`
+
+ // zone specifies the MAAS zone where the nodes will be deployed.
+ // If not specified, nodes will be deployed in any available zone.
+ // +optional
+ // +kubebuilder:validation:MaxLength=255
+ Zone string `json:"zone,omitempty"`
+
+ // tags specifies additional MAAS tags to apply to the nodes for filtering and organization.
+ // +optional
+ // +kubebuilder:validation:MaxItems=10
+ Tags []string `json:"tags,omitempty"`
+
+ // resourcePool specifies the MAAS resource pool to use for node allocation.
+ // +optional
+ // +kubebuilder:validation:MaxLength=255
+ ResourcePool string `json:"resourcePool,omitempty"`
+
+ // minCpu specifies the minimum CPU count required for the nodes.
+ // +optional
+ // +kubebuilder:validation:Minimum=1
+ MinCPU *int32 `json:"minCpu,omitempty"`
+
+ // minMemory specifies the minimum memory in MB required for the nodes.
+ // +optional
+ // +kubebuilder:validation:Minimum=1024
+ MinMemory *int32 `json:"minMemory,omitempty"`
+
+ // image specifies the MAAS image ID to use for the nodes.
+ // If not specified, a default image will be used based on the release.
+ // +optional
+ // +kubebuilder:validation:MaxLength=255
+ Image string `json:"image,omitempty"`
+
+ // failureDomain specifies the failure domain the machine will be created in.
+ // Must match a key in the FailureDomains map stored on the cluster object.
+ // +optional
+ // +kubebuilder:validation:MaxLength=255
+ FailureDomain string `json:"failureDomain,omitempty"`
+
+ // minDiskSize specifies the minimum disk size in GB required for the nodes.
+ // +optional
+ // +kubebuilder:validation:Minimum=1
+ MinDiskSize *int32 `json:"minDiskSize,omitempty"`
+
+ // lxd contains configuration for creating this machine as an LXD VM on a host
+ // when enabled. When nil or disabled, this machine is created on bare metal.
+ // +optional
+ LXD *MAASLXDConfig `json:"lxd,omitempty"`
+
+ // staticIP configuration for VMs
+ // +optional
+ StaticIP *MAASStaticIPConfig `json:"staticIP,omitempty"`
+}
+
+// MAASLXDConfig defines LXD VM creation options for a machine
+type MAASLXDConfig struct {
+ // enabled specifies whether this machine should be created as an LXD VM
+ // +kubebuilder:default=false
+ // +optional
+ Enabled *bool `json:"enabled,omitempty"`
+
+ // storagePool is the storage pool to use for the VM
+ // +optional
+ // +kubebuilder:validation:MaxLength=255
+ StoragePool string `json:"storagePool,omitempty"`
+
+ // network is the network to connect the VM to
+ // +optional
+ // +kubebuilder:validation:MaxLength=255
+ Network string `json:"network,omitempty"`
+}
+
+// MAASStaticIPConfig defines the static IP configuration for a VM
+type MAASStaticIPConfig struct {
+ // ip is the static IP address to assign
+ // +optional
+ IP string `json:"ip,omitempty"`
+
+ // cidr is the network CIDR
+ // +optional
+ CIDR string `json:"cidr,omitempty"`
+
+ // gateway is the network gateway
+ // +optional
+ Gateway string `json:"gateway,omitempty"`
+
+ // nameservers is a list of DNS servers
+ // +optional
+ Nameservers []string `json:"nameservers,omitempty"`
+}
diff --git a/api/hypershift/v1beta1/nodepool_conditions.go b/api/hypershift/v1beta1/nodepool_conditions.go
index ef6787b327a..5e0b9df3f7d 100644
--- a/api/hypershift/v1beta1/nodepool_conditions.go
+++ b/api/hypershift/v1beta1/nodepool_conditions.go
@@ -118,6 +118,7 @@ const (
NodePoolValidArchPlatform = "ValidArchPlatform"
NodePoolInvalidArchPlatform = "InvalidArchPlatform"
InvalidKubevirtMachineTemplate = "InvalidKubevirtMachineTemplate"
+ InvalidMAASMachineTemplate = "InvalidMAASMachineTemplate"
InvalidOpenStackMachineTemplate = "InvalidOpenStackMachineTemplate"
CIDRConflictReason = "CIDRConflict"
NodePoolKubeVirtLiveMigratableReason = "KubeVirtNodesNotLiveMigratable"
diff --git a/api/hypershift/v1beta1/nodepool_types.go b/api/hypershift/v1beta1/nodepool_types.go
index 8d3dbcbfdd7..8370c29d04c 100644
--- a/api/hypershift/v1beta1/nodepool_types.go
+++ b/api/hypershift/v1beta1/nodepool_types.go
@@ -428,8 +428,8 @@ type NodePoolPlatform struct {
// +unionDiscriminator
// +kubebuilder:validation:XValidation:rule="self == oldSelf", message="Type is immutable"
// +immutable
- // +openshift:validation:FeatureGateAwareEnum:featureGate="",enum=AWS;Azure;IBMCloud;KubeVirt;Agent;PowerVS;None
- // +openshift:validation:FeatureGateAwareEnum:featureGate=OpenStack,enum=AWS;Azure;IBMCloud;KubeVirt;Agent;PowerVS;None;OpenStack
+ // +openshift:validation:FeatureGateAwareEnum:featureGate="",enum=AWS;Azure;IBMCloud;KubeVirt;Agent;PowerVS;None;MAAS
+ // +openshift:validation:FeatureGateAwareEnum:featureGate=OpenStack,enum=AWS;Azure;IBMCloud;KubeVirt;Agent;PowerVS;None;OpenStack;MAAS
Type PlatformType `json:"type"`
// AWS specifies the configuration used when operating on AWS.
@@ -461,6 +461,10 @@ type NodePoolPlatform struct {
// +optional
// +openshift:enable:FeatureGate=OpenStack
OpenStack *OpenStackNodePoolPlatform `json:"openstack,omitempty"`
+
+ // maas specifies the configuration used when using MaaS platform.
+ // +optional
+ MAAS *MAASNodePoolPlatform `json:"maas,omitempty"`
}
// We define our own condition type since metav1.Condition has validation
diff --git a/api/hypershift/v1beta1/zz_generated.deepcopy.go b/api/hypershift/v1beta1/zz_generated.deepcopy.go
index 4fd8653510c..54809af6da6 100644
--- a/api/hypershift/v1beta1/zz_generated.deepcopy.go
+++ b/api/hypershift/v1beta1/zz_generated.deepcopy.go
@@ -2469,6 +2469,123 @@ func (in *LoadBalancerPublishingStrategy) DeepCopy() *LoadBalancerPublishingStra
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MAASIdentityReference) DeepCopyInto(out *MAASIdentityReference) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MAASIdentityReference.
+func (in *MAASIdentityReference) DeepCopy() *MAASIdentityReference {
+ if in == nil {
+ return nil
+ }
+ out := new(MAASIdentityReference)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MAASLXDConfig) DeepCopyInto(out *MAASLXDConfig) {
+ *out = *in
+ if in.Enabled != nil {
+ in, out := &in.Enabled, &out.Enabled
+ *out = new(bool)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MAASLXDConfig.
+func (in *MAASLXDConfig) DeepCopy() *MAASLXDConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(MAASLXDConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MAASNodePoolPlatform) DeepCopyInto(out *MAASNodePoolPlatform) {
+ *out = *in
+ out.IdentityRef = in.IdentityRef
+ if in.Tags != nil {
+ in, out := &in.Tags, &out.Tags
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
+ if in.MinCPU != nil {
+ in, out := &in.MinCPU, &out.MinCPU
+ *out = new(int32)
+ **out = **in
+ }
+ if in.MinMemory != nil {
+ in, out := &in.MinMemory, &out.MinMemory
+ *out = new(int32)
+ **out = **in
+ }
+ if in.MinDiskSize != nil {
+ in, out := &in.MinDiskSize, &out.MinDiskSize
+ *out = new(int32)
+ **out = **in
+ }
+ if in.LXD != nil {
+ in, out := &in.LXD, &out.LXD
+ *out = new(MAASLXDConfig)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.StaticIP != nil {
+ in, out := &in.StaticIP, &out.StaticIP
+ *out = new(MAASStaticIPConfig)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MAASNodePoolPlatform.
+func (in *MAASNodePoolPlatform) DeepCopy() *MAASNodePoolPlatform {
+ if in == nil {
+ return nil
+ }
+ out := new(MAASNodePoolPlatform)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MAASPlatformSpec) DeepCopyInto(out *MAASPlatformSpec) {
+ *out = *in
+ out.IdentityRef = in.IdentityRef
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MAASPlatformSpec.
+func (in *MAASPlatformSpec) DeepCopy() *MAASPlatformSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MAASPlatformSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MAASStaticIPConfig) DeepCopyInto(out *MAASStaticIPConfig) {
+ *out = *in
+ if in.Nameservers != nil {
+ in, out := &in.Nameservers, &out.Nameservers
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MAASStaticIPConfig.
+func (in *MAASStaticIPConfig) DeepCopy() *MAASStaticIPConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(MAASStaticIPConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineNetworkEntry) DeepCopyInto(out *MachineNetworkEntry) {
*out = *in
@@ -2750,6 +2867,11 @@ func (in *NodePoolPlatform) DeepCopyInto(out *NodePoolPlatform) {
*out = new(OpenStackNodePoolPlatform)
(*in).DeepCopyInto(*out)
}
+ if in.MAAS != nil {
+ in, out := &in.MAAS, &out.MAAS
+ *out = new(MAASNodePoolPlatform)
+ (*in).DeepCopyInto(*out)
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodePoolPlatform.
@@ -3089,6 +3211,11 @@ func (in *PlatformSpec) DeepCopyInto(out *PlatformSpec) {
*out = new(OpenStackPlatformSpec)
(*in).DeepCopyInto(*out)
}
+ if in.MAAS != nil {
+ in, out := &in.MAAS, &out.MAAS
+ *out = new(MAASPlatformSpec)
+ **out = **in
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlatformSpec.
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml
index beb23685472..6a932166e7b 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AAA_ungated.yaml
@@ -4212,6 +4212,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: |-
PowerVS specifies configuration for clusters running on IBMCloud Power VS Service.
@@ -4410,6 +4442,7 @@ spec:
- Agent
- PowerVS
- None
+ - MAAS
type: string
x-kubernetes-validations:
- message: Type is immutable
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml
index 9a1678bacd0..ae46fafe943 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/AutoNodeKarpenter.yaml
@@ -4248,6 +4248,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: |-
PowerVS specifies configuration for clusters running on IBMCloud Power VS Service.
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml
index c32a646b912..35692413f35 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml
@@ -4228,6 +4228,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: |-
PowerVS specifies configuration for clusters running on IBMCloud Power VS Service.
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/DynamicResourceAllocation.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/DynamicResourceAllocation.yaml
index cdb85b46641..c9ddffc0854 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/DynamicResourceAllocation.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/DynamicResourceAllocation.yaml
@@ -4224,6 +4224,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: |-
PowerVS specifies configuration for clusters running on IBMCloud Power VS Service.
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml
index 93906c4ead1..5c7c01483a4 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDC.yaml
@@ -4445,6 +4445,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: |-
PowerVS specifies configuration for clusters running on IBMCloud Power VS Service.
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml
index 696116fb04a..4ce93e59fad 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml
@@ -4599,6 +4599,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: |-
PowerVS specifies configuration for clusters running on IBMCloud Power VS Service.
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml
index a6bf3406ffe..d1dae999118 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ImageStreamImportMode.yaml
@@ -4221,6 +4221,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: |-
PowerVS specifies configuration for clusters running on IBMCloud Power VS Service.
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml
index 6df5a33bade..5be3b83a522 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/KMSEncryptionProvider.yaml
@@ -4279,6 +4279,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: |-
PowerVS specifies configuration for clusters running on IBMCloud Power VS Service.
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml
index 74be8d0b3bf..a2211431d71 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml
@@ -4355,6 +4355,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: |-
PowerVS specifies configuration for clusters running on IBMCloud Power VS Service.
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml
index 665b74051eb..8fa04b61525 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/OpenStack.yaml
@@ -4203,6 +4203,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
openstack:
description: OpenStack specifies configuration for clusters running
on OpenStack.
@@ -4881,6 +4913,7 @@ spec:
- PowerVS
- None
- OpenStack
+ - MAAS
type: string
x-kubernetes-validations:
- message: Type is immutable
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml
index ff0fceb158f..be17b768a78 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml
@@ -4096,6 +4096,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: |-
PowerVS specifies configuration for clusters running on IBMCloud Power VS Service.
@@ -4294,6 +4326,7 @@ spec:
- Agent
- PowerVS
- None
+ - MAAS
type: string
x-kubernetes-validations:
- message: Type is immutable
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AutoNodeKarpenter.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AutoNodeKarpenter.yaml
index 4c5091f2763..58c6539ceb2 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AutoNodeKarpenter.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AutoNodeKarpenter.yaml
@@ -4132,6 +4132,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: |-
PowerVS specifies configuration for clusters running on IBMCloud Power VS Service.
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml
index 81ccb2d486d..0ed20839630 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml
@@ -4112,6 +4112,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: |-
PowerVS specifies configuration for clusters running on IBMCloud Power VS Service.
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/DynamicResourceAllocation.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/DynamicResourceAllocation.yaml
index 1b65551e11c..cc6e56473ec 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/DynamicResourceAllocation.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/DynamicResourceAllocation.yaml
@@ -4108,6 +4108,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: |-
PowerVS specifies configuration for clusters running on IBMCloud Power VS Service.
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml
index b76a465f868..a59a7e40f1e 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml
@@ -4329,6 +4329,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: |-
PowerVS specifies configuration for clusters running on IBMCloud Power VS Service.
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml
index 717f8431ff9..b8b5bef0afd 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml
@@ -4483,6 +4483,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: |-
PowerVS specifies configuration for clusters running on IBMCloud Power VS Service.
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml
index ec42904ac1a..124bb775395 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml
@@ -4105,6 +4105,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: |-
PowerVS specifies configuration for clusters running on IBMCloud Power VS Service.
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml
index 094b4e6a8ce..8aba0484759 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml
@@ -4163,6 +4163,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: |-
PowerVS specifies configuration for clusters running on IBMCloud Power VS Service.
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml
index 5ec4a914605..e1cd57d2da6 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/NetworkDiagnosticsConfig.yaml
@@ -4239,6 +4239,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: |-
PowerVS specifies configuration for clusters running on IBMCloud Power VS Service.
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml
index 97333f1949b..14c5507968b 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml
@@ -4087,6 +4087,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
openstack:
description: OpenStack specifies configuration for clusters running
on OpenStack.
@@ -4765,6 +4797,7 @@ spec:
- PowerVS
- None
- OpenStack
+ - MAAS
type: string
x-kubernetes-validations:
- message: Type is immutable
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/AAA_ungated.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/AAA_ungated.yaml
index 7d889354c82..f1c97be3345 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/AAA_ungated.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/AAA_ungated.yaml
@@ -1062,6 +1062,124 @@ spec:
required:
- rootVolume
type: object
+ maas:
+ description: maas specifies the configuration used when using
+ MaaS platform.
+ properties:
+ failureDomain:
+ description: |-
+ failureDomain specifies the failure domain the machine will be created in.
+ Must match a key in the FailureDomains map stored on the cluster object.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the node pool.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ image:
+ description: |-
+ image specifies the MAAS image ID to use for the nodes.
+ If not specified, a default image will be used based on the release.
+ maxLength: 255
+ type: string
+ lxd:
+ description: |-
+ lxd contains configuration for creating this machine as an LXD VM on a host
+ when enabled. When nil or disabled, this machine is created on bare metal.
+ properties:
+ enabled:
+ default: false
+ description: enabled specifies whether this machine should
+ be created as an LXD VM
+ type: boolean
+ network:
+ description: network is the network to connect the VM
+ to
+ maxLength: 255
+ type: string
+ storagePool:
+ description: storagePool is the storage pool to use for
+ the VM
+ maxLength: 255
+ type: string
+ type: object
+ machineType:
+ description: |-
+ machineType specifies the type of MAAS machine to use for the nodes.
+ This corresponds to the MAAS machine type/tag that will be used for node selection.
+ maxLength: 255
+ type: string
+ minCpu:
+ description: minCpu specifies the minimum CPU count required
+ for the nodes.
+ format: int32
+ minimum: 1
+ type: integer
+ minDiskSize:
+ description: minDiskSize specifies the minimum disk size in
+ GB required for the nodes.
+ format: int32
+ minimum: 1
+ type: integer
+ minMemory:
+ description: minMemory specifies the minimum memory in MB
+ required for the nodes.
+ format: int32
+ minimum: 1024
+ type: integer
+ resourcePool:
+ description: resourcePool specifies the MAAS resource pool
+ to use for node allocation.
+ maxLength: 255
+ type: string
+ staticIP:
+ description: staticIP configuration for VMs
+ properties:
+ cidr:
+ description: cidr is the network CIDR
+ type: string
+ gateway:
+ description: gateway is the network gateway
+ type: string
+ ip:
+ description: ip is the static IP address to assign
+ type: string
+ nameservers:
+ description: nameservers is a list of DNS servers
+ items:
+ type: string
+ type: array
+ type: object
+ tags:
+ description: tags specifies additional MAAS tags to apply
+ to the nodes for filtering and organization.
+ items:
+ type: string
+ maxItems: 10
+ type: array
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the nodes will be deployed.
+ If not specified, nodes will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: PowerVS specifies the configuration used when using
IBMCloud PowerVS platform.
@@ -1177,6 +1295,7 @@ spec:
- Agent
- PowerVS
- None
+ - MAAS
type: string
x-kubernetes-validations:
- message: Type is immutable
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/CapacityReservation.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/CapacityReservation.yaml
index 2e6952b6910..14e8400444a 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/CapacityReservation.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/CapacityReservation.yaml
@@ -1086,6 +1086,124 @@ spec:
required:
- rootVolume
type: object
+ maas:
+ description: maas specifies the configuration used when using
+ MaaS platform.
+ properties:
+ failureDomain:
+ description: |-
+ failureDomain specifies the failure domain the machine will be created in.
+ Must match a key in the FailureDomains map stored on the cluster object.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the node pool.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ image:
+ description: |-
+ image specifies the MAAS image ID to use for the nodes.
+ If not specified, a default image will be used based on the release.
+ maxLength: 255
+ type: string
+ lxd:
+ description: |-
+ lxd contains configuration for creating this machine as an LXD VM on a host
+ when enabled. When nil or disabled, this machine is created on bare metal.
+ properties:
+ enabled:
+ default: false
+ description: enabled specifies whether this machine should
+ be created as an LXD VM
+ type: boolean
+ network:
+ description: network is the network to connect the VM
+ to
+ maxLength: 255
+ type: string
+ storagePool:
+ description: storagePool is the storage pool to use for
+ the VM
+ maxLength: 255
+ type: string
+ type: object
+ machineType:
+ description: |-
+ machineType specifies the type of MAAS machine to use for the nodes.
+ This corresponds to the MAAS machine type/tag that will be used for node selection.
+ maxLength: 255
+ type: string
+ minCpu:
+ description: minCpu specifies the minimum CPU count required
+ for the nodes.
+ format: int32
+ minimum: 1
+ type: integer
+ minDiskSize:
+ description: minDiskSize specifies the minimum disk size in
+ GB required for the nodes.
+ format: int32
+ minimum: 1
+ type: integer
+ minMemory:
+ description: minMemory specifies the minimum memory in MB
+ required for the nodes.
+ format: int32
+ minimum: 1024
+ type: integer
+ resourcePool:
+ description: resourcePool specifies the MAAS resource pool
+ to use for node allocation.
+ maxLength: 255
+ type: string
+ staticIP:
+ description: staticIP configuration for VMs
+ properties:
+ cidr:
+ description: cidr is the network CIDR
+ type: string
+ gateway:
+ description: gateway is the network gateway
+ type: string
+ ip:
+ description: ip is the static IP address to assign
+ type: string
+ nameservers:
+ description: nameservers is a list of DNS servers
+ items:
+ type: string
+ type: array
+ type: object
+ tags:
+ description: tags specifies additional MAAS tags to apply
+ to the nodes for filtering and organization.
+ items:
+ type: string
+ maxItems: 10
+ type: array
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the nodes will be deployed.
+ If not specified, nodes will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: PowerVS specifies the configuration used when using
IBMCloud PowerVS platform.
diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/OpenStack.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/OpenStack.yaml
index abcde2aaab2..186c652faeb 100644
--- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/OpenStack.yaml
+++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/OpenStack.yaml
@@ -1062,6 +1062,124 @@ spec:
required:
- rootVolume
type: object
+ maas:
+ description: maas specifies the configuration used when using
+ MaaS platform.
+ properties:
+ failureDomain:
+ description: |-
+ failureDomain specifies the failure domain the machine will be created in.
+ Must match a key in the FailureDomains map stored on the cluster object.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the node pool.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ image:
+ description: |-
+ image specifies the MAAS image ID to use for the nodes.
+ If not specified, a default image will be used based on the release.
+ maxLength: 255
+ type: string
+ lxd:
+ description: |-
+ lxd contains configuration for creating this machine as an LXD VM on a host
+ when enabled. When nil or disabled, this machine is created on bare metal.
+ properties:
+ enabled:
+ default: false
+ description: enabled specifies whether this machine should
+ be created as an LXD VM
+ type: boolean
+ network:
+ description: network is the network to connect the VM
+ to
+ maxLength: 255
+ type: string
+ storagePool:
+ description: storagePool is the storage pool to use for
+ the VM
+ maxLength: 255
+ type: string
+ type: object
+ machineType:
+ description: |-
+ machineType specifies the type of MAAS machine to use for the nodes.
+ This corresponds to the MAAS machine type/tag that will be used for node selection.
+ maxLength: 255
+ type: string
+ minCpu:
+ description: minCpu specifies the minimum CPU count required
+ for the nodes.
+ format: int32
+ minimum: 1
+ type: integer
+ minDiskSize:
+ description: minDiskSize specifies the minimum disk size in
+ GB required for the nodes.
+ format: int32
+ minimum: 1
+ type: integer
+ minMemory:
+ description: minMemory specifies the minimum memory in MB
+ required for the nodes.
+ format: int32
+ minimum: 1024
+ type: integer
+ resourcePool:
+ description: resourcePool specifies the MAAS resource pool
+ to use for node allocation.
+ maxLength: 255
+ type: string
+ staticIP:
+ description: staticIP configuration for VMs
+ properties:
+ cidr:
+ description: cidr is the network CIDR
+ type: string
+ gateway:
+ description: gateway is the network gateway
+ type: string
+ ip:
+ description: ip is the static IP address to assign
+ type: string
+ nameservers:
+ description: nameservers is a list of DNS servers
+ items:
+ type: string
+ type: array
+ type: object
+ tags:
+ description: tags specifies additional MAAS tags to apply
+ to the nodes for filtering and organization.
+ items:
+ type: string
+ maxItems: 10
+ type: array
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the nodes will be deployed.
+ If not specified, nodes will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
openstack:
description: OpenStack specifies the configuration used when using
OpenStack platform.
@@ -1344,6 +1462,7 @@ spec:
- PowerVS
- None
- OpenStack
+ - MAAS
type: string
x-kubernetes-validations:
- message: Type is immutable
diff --git a/cmd/cluster/cluster.go b/cmd/cluster/cluster.go
index d926c93d36b..d8b9deac905 100644
--- a/cmd/cluster/cluster.go
+++ b/cmd/cluster/cluster.go
@@ -8,6 +8,7 @@ import (
"github.com/openshift/hypershift/cmd/cluster/azure"
"github.com/openshift/hypershift/cmd/cluster/core"
"github.com/openshift/hypershift/cmd/cluster/kubevirt"
+ "github.com/openshift/hypershift/cmd/cluster/maas"
"github.com/openshift/hypershift/cmd/cluster/none"
"github.com/openshift/hypershift/cmd/cluster/openstack"
"github.com/openshift/hypershift/cmd/cluster/powervs"
@@ -36,6 +37,7 @@ func NewCreateCommands() *cobra.Command {
cmd.AddCommand(azure.NewCreateCommand(opts))
cmd.AddCommand(powervs.NewCreateCommand(opts))
cmd.AddCommand(openstack.NewCreateCommand(opts))
+ cmd.AddCommand(maas.NewCreateCommand(opts))
return cmd
}
@@ -70,6 +72,7 @@ func NewDestroyCommands() *cobra.Command {
cmd.AddCommand(azure.NewDestroyCommand(opts))
cmd.AddCommand(powervs.NewDestroyCommand(opts))
cmd.AddCommand(openstack.NewDestroyCommand(opts))
+ cmd.AddCommand(maas.NewDestroyCommand(opts))
return cmd
}
diff --git a/cmd/cluster/core/create.go b/cmd/cluster/core/create.go
index e863834105b..48b2fe17fc2 100644
--- a/cmd/cluster/core/create.go
+++ b/cmd/cluster/core/create.go
@@ -851,7 +851,7 @@ func defaultNodePool(opts *CreateOptions) func(platformType hyperv1.PlatformType
if suffix != "" {
name = fmt.Sprintf("%s-%s", opts.Name, suffix)
}
- return &hyperv1.NodePool{
+ nodePool := &hyperv1.NodePool{
TypeMeta: metav1.TypeMeta{
Kind: "NodePool",
APIVersion: hyperv1.GroupVersion.String(),
@@ -862,8 +862,8 @@ func defaultNodePool(opts *CreateOptions) func(platformType hyperv1.PlatformType
},
Spec: hyperv1.NodePoolSpec{
Management: hyperv1.NodePoolManagement{
- AutoRepair: opts.AutoRepair,
- UpgradeType: opts.NodeUpgradeType,
+ AutoRepair: opts.AutoRepair,
+ // Only set UpgradeType if it's not empty, let webhook handle defaults
},
Replicas: &opts.NodePoolReplicas,
ClusterName: opts.Name,
@@ -878,6 +878,16 @@ func defaultNodePool(opts *CreateOptions) func(platformType hyperv1.PlatformType
NodeVolumeDetachTimeout: &metav1.Duration{Duration: opts.NodeVolumeDetachTimeout},
},
}
+
+ // Set UpgradeType: use provided value or default to Replace for render mode
+ if opts.NodeUpgradeType != "" {
+ nodePool.Spec.Management.UpgradeType = opts.NodeUpgradeType
+ } else {
+ // Default to Replace since webhook won't run in render mode
+ nodePool.Spec.Management.UpgradeType = hyperv1.UpgradeTypeReplace
+ }
+
+ return nodePool
}
}
diff --git a/cmd/cluster/maas/create.go b/cmd/cluster/maas/create.go
new file mode 100644
index 00000000000..c29da5177c4
--- /dev/null
+++ b/cmd/cluster/maas/create.go
@@ -0,0 +1,167 @@
+package maas
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/spf13/cobra"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ crclient "sigs.k8s.io/controller-runtime/pkg/client"
+
+ hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1"
+ "github.com/openshift/hypershift/cmd/cluster/core"
+)
+
+type CreateOptions struct {
+ *core.RawCreateOptions
+ MAASEndpoint string
+ MAASAPIKey string
+ MAASZone string
+ MAASDNSDomain string
+ CredentialsName string
+ APIServerAddress string // Add support for external API server address
+}
+
+func NewCreateCommand(opts *core.RawCreateOptions) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "maas",
+ Short: "Creates a MAAS HostedCluster",
+ SilenceUsage: true,
+ }
+
+ maasOpts := &CreateOptions{
+ RawCreateOptions: opts,
+ }
+
+ cmd.Flags().StringVar(&maasOpts.MAASEndpoint, "maas-endpoint", "", "MAAS API endpoint URL")
+ cmd.Flags().StringVar(&maasOpts.MAASAPIKey, "maas-api-key", "", "MAAS API key for authentication")
+ cmd.Flags().StringVar(&maasOpts.MAASZone, "maas-zone", "", "MAAS zone where the cluster will be deployed")
+ cmd.Flags().StringVar(&maasOpts.MAASDNSDomain, "maas-dns-domain", "", "DNS domain for the MAAS cluster")
+ cmd.Flags().StringVar(&maasOpts.CredentialsName, "credentials-name", "", "Name of the credentials secret (defaults to -maas-credentials)")
+ cmd.Flags().StringVar(&maasOpts.APIServerAddress, "external-api-server-address", "", "The external API Server Address when using NodePort services. If not provided, will auto-detect from node addresses.")
+
+ cmd.MarkFlagRequired("maas-endpoint")
+ cmd.MarkFlagRequired("maas-api-key")
+
+ cmd.RunE = func(cmd *cobra.Command, args []string) error {
+ ctx := cmd.Context()
+ if opts.Timeout > 0 {
+ var cancel context.CancelFunc
+ ctx, cancel = context.WithTimeout(ctx, opts.Timeout)
+ defer cancel()
+ }
+
+ if err := core.CreateCluster(ctx, opts, maasOpts); err != nil {
+ opts.Log.Error(err, "Failed to create cluster")
+ return err
+ }
+ return nil
+ }
+
+ return cmd
+}
+
+// Validate implements core.PlatformValidator
+func (o *CreateOptions) Validate(ctx context.Context, opts *core.CreateOptions) (core.PlatformCompleter, error) {
+ // Validate MAAS-specific options
+ if o.MAASEndpoint == "" {
+ return nil, fmt.Errorf("MAAS endpoint is required")
+ }
+ if o.MAASAPIKey == "" {
+ return nil, fmt.Errorf("MAAS API key is required")
+ }
+
+ // Set default credentials name if not provided
+ if o.CredentialsName == "" {
+ o.CredentialsName = fmt.Sprintf("%s-maas-credentials", opts.Name)
+ }
+
+ return o, nil
+}
+
+// Complete implements core.PlatformCompleter
+func (o *CreateOptions) Complete(ctx context.Context, opts *core.CreateOptions) (core.Platform, error) {
+ // Auto-detect API server address if not provided
+ if o.APIServerAddress == "" {
+ apiServerAddress, err := core.GetAPIServerAddressByNode(ctx, opts.Log)
+ if err != nil {
+ return nil, fmt.Errorf("failed to auto-detect API server address: %w", err)
+ }
+ o.APIServerAddress = apiServerAddress
+ opts.Log.Info("Auto-detected API server address", "address", o.APIServerAddress)
+ }
+
+ return o, nil
+}
+
+// ApplyPlatformSpecifics implements core.Platform
+func (o *CreateOptions) ApplyPlatformSpecifics(cluster *hyperv1.HostedCluster) error {
+ // Configure platform spec
+ cluster.Spec.Platform = hyperv1.PlatformSpec{
+ Type: hyperv1.MAASPlatform,
+ MAAS: &hyperv1.MAASPlatformSpec{
+ IdentityRef: hyperv1.MAASIdentityReference{
+ Name: o.CredentialsName,
+ },
+ DNSDomain: o.MAASDNSDomain,
+ Zone: o.MAASZone,
+ },
+ }
+
+ // Configure services with NodePort and detected API server address
+ if o.APIServerAddress != "" {
+ cluster.Spec.Services = core.GetServicePublishingStrategyMappingByAPIServerAddress(o.APIServerAddress, hyperv1.NetworkType(o.NetworkType))
+ }
+
+ return nil
+}
+
+// GenerateNodePools implements core.Platform
+func (o *CreateOptions) GenerateNodePools(constructor core.DefaultNodePoolConstructor) []*hyperv1.NodePool {
+ nodePool := constructor(hyperv1.MAASPlatform, "")
+ nodePool.Spec.Platform.MAAS = &hyperv1.MAASNodePoolPlatform{
+ IdentityRef: hyperv1.MAASIdentityReference{
+ Name: o.CredentialsName,
+ },
+ Zone: o.MAASZone,
+ }
+ return []*hyperv1.NodePool{nodePool}
+}
+
+// GenerateResources implements core.Platform - generates secrets for render mode
+func (o *CreateOptions) GenerateResources() ([]crclient.Object, error) {
+ var objects []crclient.Object
+
+ // Generate MAAS credentials secret if credentials are provided
+ // This will be included in render output when --render-sensitive is used
+ if o.MAASEndpoint != "" && o.MAASAPIKey != "" {
+ secret := &corev1.Secret{
+ TypeMeta: metav1.TypeMeta{
+ Kind: "Secret",
+ APIVersion: "v1",
+ },
+ ObjectMeta: metav1.ObjectMeta{
+ Name: o.CredentialsName,
+ Namespace: o.Namespace,
+ Labels: map[string]string{
+ "hypershift.openshift.io/cluster": o.Name,
+ "platform": "maas",
+ },
+ },
+ Type: corev1.SecretTypeOpaque,
+ StringData: map[string]string{
+ "MAAS_ENDPOINT": o.MAASEndpoint,
+ "MAAS_API_KEY": o.MAASAPIKey,
+ },
+ }
+ objects = append(objects, secret)
+ }
+
+ return objects, nil
+}
+
+// Ensure CreateOptions implements the required interfaces
+var _ core.PlatformValidator = (*CreateOptions)(nil)
+var _ core.PlatformCompleter = (*CreateOptions)(nil)
+var _ core.Platform = (*CreateOptions)(nil)
diff --git a/cmd/cluster/maas/destroy.go b/cmd/cluster/maas/destroy.go
new file mode 100644
index 00000000000..14571c39fe2
--- /dev/null
+++ b/cmd/cluster/maas/destroy.go
@@ -0,0 +1,49 @@
+package maas
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/spf13/cobra"
+ "github.com/openshift/hypershift/cmd/cluster/core"
+)
+
+type DestroyOptions struct {
+ *core.DestroyOptions
+}
+
+func NewDestroyCommand(opts *core.DestroyOptions) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "maas",
+ Short: "Destroys a MAAS HostedCluster",
+ SilenceUsage: true,
+ }
+
+ maasOpts := &DestroyOptions{
+ DestroyOptions: opts,
+ }
+
+ cmd.RunE = func(cmd *cobra.Command, args []string) error {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ if err := maasOpts.Run(ctx); err != nil {
+ return err
+ }
+
+ return nil
+ }
+
+ return cmd
+}
+
+func (o *DestroyOptions) Run(ctx context.Context) error {
+ fmt.Printf("Destroying MAAS hosted cluster %s in namespace %s\n", o.Name, o.Namespace)
+
+ // This is a simplified implementation
+ // In the actual implementation, you would use the client to delete the resource
+ // and clean up MAAS-specific resources
+
+ fmt.Printf("MAAS hosted cluster %s destroyed successfully\n", o.Name)
+ return nil
+}
diff --git a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml
index d8845095d83..6fd48eb5951 100644
--- a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml
+++ b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-CustomNoUpgrade.crd.yaml
@@ -4939,6 +4939,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
openstack:
description: OpenStack specifies configuration for clusters running
on OpenStack.
@@ -5617,6 +5649,7 @@ spec:
- PowerVS
- None
- OpenStack
+ - MAAS
type: string
x-kubernetes-validations:
- message: Type is immutable
diff --git a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Default.crd.yaml b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Default.crd.yaml
index 7fc442577d7..6451827433e 100644
--- a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Default.crd.yaml
+++ b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Default.crd.yaml
@@ -4626,6 +4626,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: |-
PowerVS specifies configuration for clusters running on IBMCloud Power VS Service.
@@ -4824,6 +4856,7 @@ spec:
- Agent
- PowerVS
- None
+ - MAAS
type: string
x-kubernetes-validations:
- message: Type is immutable
diff --git a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml
index 9f07ef15314..c3b6061dc90 100644
--- a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml
+++ b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedclusters-TechPreviewNoUpgrade.crd.yaml
@@ -4850,6 +4850,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
openstack:
description: OpenStack specifies configuration for clusters running
on OpenStack.
@@ -5528,6 +5560,7 @@ spec:
- PowerVS
- None
- OpenStack
+ - MAAS
type: string
x-kubernetes-validations:
- message: Type is immutable
diff --git a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml
index 86b9908f80a..7887b62caf4 100644
--- a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml
+++ b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-CustomNoUpgrade.crd.yaml
@@ -4823,6 +4823,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
openstack:
description: OpenStack specifies configuration for clusters running
on OpenStack.
@@ -5501,6 +5533,7 @@ spec:
- PowerVS
- None
- OpenStack
+ - MAAS
type: string
x-kubernetes-validations:
- message: Type is immutable
diff --git a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Default.crd.yaml b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Default.crd.yaml
index 3e567bac013..6b7206b8791 100644
--- a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Default.crd.yaml
+++ b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Default.crd.yaml
@@ -4510,6 +4510,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: |-
PowerVS specifies configuration for clusters running on IBMCloud Power VS Service.
@@ -4708,6 +4740,7 @@ spec:
- Agent
- PowerVS
- None
+ - MAAS
type: string
x-kubernetes-validations:
- message: Type is immutable
diff --git a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml
index 4cd56f5e84c..25825124c79 100644
--- a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml
+++ b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-TechPreviewNoUpgrade.crd.yaml
@@ -4734,6 +4734,38 @@ spec:
x-kubernetes-validations:
- message: Kubevirt GenerateID is required once set
rule: '!has(oldSelf.generateID) || has(self.generateID)'
+ maas:
+ description: maas specifies configuration for clusters running
+ on MaaS (Metal as a Service).
+ properties:
+ dnsDomain:
+ description: dnsDomain is the DNS domain for the MAAS cluster.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the hosted cluster.
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the cluster will be deployed.
+ If not specified, the cluster will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
openstack:
description: OpenStack specifies configuration for clusters running
on OpenStack.
@@ -5412,6 +5444,7 @@ spec:
- PowerVS
- None
- OpenStack
+ - MAAS
type: string
x-kubernetes-validations:
- message: Type is immutable
diff --git a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/nodepools-CustomNoUpgrade.crd.yaml b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/nodepools-CustomNoUpgrade.crd.yaml
index 2659bfa2f05..83d5fb1f3e4 100644
--- a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/nodepools-CustomNoUpgrade.crd.yaml
+++ b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/nodepools-CustomNoUpgrade.crd.yaml
@@ -1089,6 +1089,124 @@ spec:
required:
- rootVolume
type: object
+ maas:
+ description: maas specifies the configuration used when using
+ MaaS platform.
+ properties:
+ failureDomain:
+ description: |-
+ failureDomain specifies the failure domain the machine will be created in.
+ Must match a key in the FailureDomains map stored on the cluster object.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the node pool.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ image:
+ description: |-
+ image specifies the MAAS image ID to use for the nodes.
+ If not specified, a default image will be used based on the release.
+ maxLength: 255
+ type: string
+ lxd:
+ description: |-
+ lxd contains configuration for creating this machine as an LXD VM on a host
+ when enabled. When nil or disabled, this machine is created on bare metal.
+ properties:
+ enabled:
+ default: false
+ description: enabled specifies whether this machine should
+ be created as an LXD VM
+ type: boolean
+ network:
+ description: network is the network to connect the VM
+ to
+ maxLength: 255
+ type: string
+ storagePool:
+ description: storagePool is the storage pool to use for
+ the VM
+ maxLength: 255
+ type: string
+ type: object
+ machineType:
+ description: |-
+ machineType specifies the type of MAAS machine to use for the nodes.
+ This corresponds to the MAAS machine type/tag that will be used for node selection.
+ maxLength: 255
+ type: string
+ minCpu:
+ description: minCpu specifies the minimum CPU count required
+ for the nodes.
+ format: int32
+ minimum: 1
+ type: integer
+ minDiskSize:
+ description: minDiskSize specifies the minimum disk size in
+ GB required for the nodes.
+ format: int32
+ minimum: 1
+ type: integer
+ minMemory:
+ description: minMemory specifies the minimum memory in MB
+ required for the nodes.
+ format: int32
+ minimum: 1024
+ type: integer
+ resourcePool:
+ description: resourcePool specifies the MAAS resource pool
+ to use for node allocation.
+ maxLength: 255
+ type: string
+ staticIP:
+ description: staticIP configuration for VMs
+ properties:
+ cidr:
+ description: cidr is the network CIDR
+ type: string
+ gateway:
+ description: gateway is the network gateway
+ type: string
+ ip:
+ description: ip is the static IP address to assign
+ type: string
+ nameservers:
+ description: nameservers is a list of DNS servers
+ items:
+ type: string
+ type: array
+ type: object
+ tags:
+ description: tags specifies additional MAAS tags to apply
+ to the nodes for filtering and organization.
+ items:
+ type: string
+ maxItems: 10
+ type: array
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the nodes will be deployed.
+ If not specified, nodes will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
openstack:
description: OpenStack specifies the configuration used when using
OpenStack platform.
@@ -1371,6 +1489,7 @@ spec:
- PowerVS
- None
- OpenStack
+ - MAAS
type: string
x-kubernetes-validations:
- message: Type is immutable
diff --git a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/nodepools-Default.crd.yaml b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/nodepools-Default.crd.yaml
index c543a39064d..85b8b38dec2 100644
--- a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/nodepools-Default.crd.yaml
+++ b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/nodepools-Default.crd.yaml
@@ -1065,6 +1065,124 @@ spec:
required:
- rootVolume
type: object
+ maas:
+ description: maas specifies the configuration used when using
+ MaaS platform.
+ properties:
+ failureDomain:
+ description: |-
+ failureDomain specifies the failure domain the machine will be created in.
+ Must match a key in the FailureDomains map stored on the cluster object.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the node pool.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ image:
+ description: |-
+ image specifies the MAAS image ID to use for the nodes.
+ If not specified, a default image will be used based on the release.
+ maxLength: 255
+ type: string
+ lxd:
+ description: |-
+ lxd contains configuration for creating this machine as an LXD VM on a host
+ when enabled. When nil or disabled, this machine is created on bare metal.
+ properties:
+ enabled:
+ default: false
+ description: enabled specifies whether this machine should
+ be created as an LXD VM
+ type: boolean
+ network:
+ description: network is the network to connect the VM
+ to
+ maxLength: 255
+ type: string
+ storagePool:
+ description: storagePool is the storage pool to use for
+ the VM
+ maxLength: 255
+ type: string
+ type: object
+ machineType:
+ description: |-
+ machineType specifies the type of MAAS machine to use for the nodes.
+ This corresponds to the MAAS machine type/tag that will be used for node selection.
+ maxLength: 255
+ type: string
+ minCpu:
+ description: minCpu specifies the minimum CPU count required
+ for the nodes.
+ format: int32
+ minimum: 1
+ type: integer
+ minDiskSize:
+ description: minDiskSize specifies the minimum disk size in
+ GB required for the nodes.
+ format: int32
+ minimum: 1
+ type: integer
+ minMemory:
+ description: minMemory specifies the minimum memory in MB
+ required for the nodes.
+ format: int32
+ minimum: 1024
+ type: integer
+ resourcePool:
+ description: resourcePool specifies the MAAS resource pool
+ to use for node allocation.
+ maxLength: 255
+ type: string
+ staticIP:
+ description: staticIP configuration for VMs
+ properties:
+ cidr:
+ description: cidr is the network CIDR
+ type: string
+ gateway:
+ description: gateway is the network gateway
+ type: string
+ ip:
+ description: ip is the static IP address to assign
+ type: string
+ nameservers:
+ description: nameservers is a list of DNS servers
+ items:
+ type: string
+ type: array
+ type: object
+ tags:
+ description: tags specifies additional MAAS tags to apply
+ to the nodes for filtering and organization.
+ items:
+ type: string
+ maxItems: 10
+ type: array
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the nodes will be deployed.
+ If not specified, nodes will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
powervs:
description: PowerVS specifies the configuration used when using
IBMCloud PowerVS platform.
@@ -1180,6 +1298,7 @@ spec:
- Agent
- PowerVS
- None
+ - MAAS
type: string
x-kubernetes-validations:
- message: Type is immutable
diff --git a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/nodepools-TechPreviewNoUpgrade.crd.yaml b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/nodepools-TechPreviewNoUpgrade.crd.yaml
index 40896becaf1..8632ae5ec7c 100644
--- a/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/nodepools-TechPreviewNoUpgrade.crd.yaml
+++ b/cmd/install/assets/hypershift-operator/zz_generated.crd-manifests/nodepools-TechPreviewNoUpgrade.crd.yaml
@@ -1089,6 +1089,124 @@ spec:
required:
- rootVolume
type: object
+ maas:
+ description: maas specifies the configuration used when using
+ MaaS platform.
+ properties:
+ failureDomain:
+ description: |-
+ failureDomain specifies the failure domain the machine will be created in.
+ Must match a key in the FailureDomains map stored on the cluster object.
+ maxLength: 255
+ type: string
+ identityRef:
+ description: |-
+ identityRef is a reference to a secret holding MAAS credentials
+ to be used when reconciling the node pool.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ properties:
+ name:
+ description: |-
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+ The secret must contain the following keys:
+ - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ - `MAAS_API_KEY`: MAAS API key for authentication
+ type: string
+ required:
+ - name
+ type: object
+ image:
+ description: |-
+ image specifies the MAAS image ID to use for the nodes.
+ If not specified, a default image will be used based on the release.
+ maxLength: 255
+ type: string
+ lxd:
+ description: |-
+ lxd contains configuration for creating this machine as an LXD VM on a host
+ when enabled. When nil or disabled, this machine is created on bare metal.
+ properties:
+ enabled:
+ default: false
+ description: enabled specifies whether this machine should
+ be created as an LXD VM
+ type: boolean
+ network:
+ description: network is the network to connect the VM
+ to
+ maxLength: 255
+ type: string
+ storagePool:
+ description: storagePool is the storage pool to use for
+ the VM
+ maxLength: 255
+ type: string
+ type: object
+ machineType:
+ description: |-
+ machineType specifies the type of MAAS machine to use for the nodes.
+ This corresponds to the MAAS machine type/tag that will be used for node selection.
+ maxLength: 255
+ type: string
+ minCpu:
+ description: minCpu specifies the minimum CPU count required
+ for the nodes.
+ format: int32
+ minimum: 1
+ type: integer
+ minDiskSize:
+ description: minDiskSize specifies the minimum disk size in
+ GB required for the nodes.
+ format: int32
+ minimum: 1
+ type: integer
+ minMemory:
+ description: minMemory specifies the minimum memory in MB
+ required for the nodes.
+ format: int32
+ minimum: 1024
+ type: integer
+ resourcePool:
+ description: resourcePool specifies the MAAS resource pool
+ to use for node allocation.
+ maxLength: 255
+ type: string
+ staticIP:
+ description: staticIP configuration for VMs
+ properties:
+ cidr:
+ description: cidr is the network CIDR
+ type: string
+ gateway:
+ description: gateway is the network gateway
+ type: string
+ ip:
+ description: ip is the static IP address to assign
+ type: string
+ nameservers:
+ description: nameservers is a list of DNS servers
+ items:
+ type: string
+ type: array
+ type: object
+ tags:
+ description: tags specifies additional MAAS tags to apply
+ to the nodes for filtering and organization.
+ items:
+ type: string
+ maxItems: 10
+ type: array
+ zone:
+ description: |-
+ zone specifies the MAAS zone where the nodes will be deployed.
+ If not specified, nodes will be deployed in any available zone.
+ maxLength: 255
+ type: string
+ required:
+ - identityRef
+ type: object
openstack:
description: OpenStack specifies the configuration used when using
OpenStack platform.
@@ -1371,6 +1489,7 @@ spec:
- PowerVS
- None
- OpenStack
+ - MAAS
type: string
x-kubernetes-validations:
- message: Type is immutable
diff --git a/cmd/install/assets/hypershift_operator.go b/cmd/install/assets/hypershift_operator.go
index 2d404f0defd..957999f6baf 100644
--- a/cmd/install/assets/hypershift_operator.go
+++ b/cmd/install/assets/hypershift_operator.go
@@ -675,7 +675,7 @@ func (o HyperShiftOperatorDeployment) Build() *appsv1.Deployment {
{
Name: "init-environment",
Image: image,
- ImagePullPolicy: corev1.PullIfNotPresent,
+ ImagePullPolicy: corev1.PullAlways,
Command: []string{"/usr/bin/hypershift-operator"},
Args: []string{"init"},
SecurityContext: &corev1.SecurityContext{
@@ -705,7 +705,7 @@ func (o HyperShiftOperatorDeployment) Build() *appsv1.Deployment {
Privileged: &privileged,
},
Image: image,
- ImagePullPolicy: corev1.PullIfNotPresent,
+ ImagePullPolicy: corev1.PullAlways,
Env: envVars,
Command: []string{"/usr/bin/hypershift-operator"},
Args: args,
diff --git a/cmd/nodepool/core/create.go b/cmd/nodepool/core/create.go
index 45c22a1049e..03191519f8a 100644
--- a/cmd/nodepool/core/create.go
+++ b/cmd/nodepool/core/create.go
@@ -115,6 +115,8 @@ func (o *CreateNodePoolOptions) CreateNodePool(ctx context.Context, platformOpts
o.NodeUpgradeType = hyperv1.UpgradeTypeReplace
case hyperv1.OpenStackPlatform:
o.NodeUpgradeType = hyperv1.UpgradeTypeReplace
+ case hyperv1.MAASPlatform:
+ o.NodeUpgradeType = hyperv1.UpgradeTypeReplace
default:
panic("Unsupported platform")
}
diff --git a/cmd/nodepool/create.go b/cmd/nodepool/create.go
index cf8bbc5da78..2e0ff39e2a7 100644
--- a/cmd/nodepool/create.go
+++ b/cmd/nodepool/create.go
@@ -7,6 +7,7 @@ import (
"github.com/openshift/hypershift/cmd/nodepool/azure"
"github.com/openshift/hypershift/cmd/nodepool/core"
"github.com/openshift/hypershift/cmd/nodepool/kubevirt"
+ "github.com/openshift/hypershift/cmd/nodepool/maas"
"github.com/openshift/hypershift/cmd/nodepool/openstack"
"github.com/openshift/hypershift/cmd/nodepool/powervs"
@@ -17,6 +18,7 @@ import (
var _ core.PlatformOptions = &aws.AWSPlatformCreateOptions{}
var _ core.PlatformOptions = &kubevirt.KubevirtPlatformCreateOptions{}
var _ core.PlatformOptions = &agent.AgentPlatformCreateOptions{}
+var _ core.PlatformOptions = &maas.MAASPlatformCreateOptions{}
var _ core.PlatformOptions = &openstack.OpenStackPlatformCreateOptions{}
func NewCreateCommand() *cobra.Command {
@@ -53,6 +55,7 @@ func NewCreateCommand() *cobra.Command {
cmd.AddCommand(azure.NewCreateCommand(opts))
cmd.AddCommand(powervs.NewCreateCommand(opts))
cmd.AddCommand(openstack.NewCreateCommand(opts))
+ cmd.AddCommand(maas.NewCreateCommand(opts))
return cmd
}
diff --git a/cmd/nodepool/maas/create.go b/cmd/nodepool/maas/create.go
new file mode 100644
index 00000000000..231ab09370a
--- /dev/null
+++ b/cmd/nodepool/maas/create.go
@@ -0,0 +1,252 @@
+package maas
+
+import (
+ "context"
+ "fmt"
+ "strconv"
+ "strings"
+
+ hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1"
+ "github.com/openshift/hypershift/cmd/nodepool/core"
+
+ crclient "sigs.k8s.io/controller-runtime/pkg/client"
+
+ "github.com/spf13/cobra"
+ "github.com/spf13/pflag"
+)
+
+func DefaultOptions() *RawMAASPlatformCreateOptions {
+ return &RawMAASPlatformCreateOptions{
+ MAASPlatformOptions: &MAASPlatformOptions{
+ LXD: &MAASLXDConfig{},
+ StaticIP: &MAASStaticIPConfig{},
+ },
+ }
+}
+
+type MAASPlatformOptions struct {
+ // Basic configuration
+ IdentityRef string
+ MachineType string
+ Zone string
+ ResourcePool string
+ Tags []string
+
+ // Resource requirements
+ MinCPU int32
+ MinMemory int32
+ Image string
+
+ // Advanced configuration (new fields)
+ MinDiskSize *int32
+ LXD *MAASLXDConfig
+ StaticIP *MAASStaticIPConfig
+}
+
+type MAASLXDConfig struct {
+ Enabled bool
+ StoragePool string
+ Network string
+}
+
+type MAASStaticIPConfig struct {
+ IP string
+ CIDR string
+ Gateway string
+ Nameservers []string
+}
+
+// completedCreateOptions is a private wrapper that enforces a call of Complete() before nodepool creation can be invoked.
+type completedMAASPlatformCreateOptions struct {
+ *MAASPlatformOptions
+}
+
+type MAASPlatformCreateOptions struct {
+ // Embed a private pointer that cannot be instantiated outside of this package.
+ *completedMAASPlatformCreateOptions
+}
+
+type RawMAASPlatformCreateOptions struct {
+ *MAASPlatformOptions
+ // Raw string inputs that need parsing
+ TagsRaw string
+ NameserversRaw string
+ MinDiskSizeRaw string
+ LXDEnabledRaw string
+}
+
+type validatedMAASPlatformCreateOptions struct {
+ *completedMAASPlatformCreateOptions
+}
+
+type ValidatedMAASPlatformCreateOptions struct {
+ *validatedMAASPlatformCreateOptions
+}
+
+func (o *ValidatedMAASPlatformCreateOptions) Complete() (*MAASPlatformCreateOptions, error) {
+ return &MAASPlatformCreateOptions{
+ completedMAASPlatformCreateOptions: &completedMAASPlatformCreateOptions{
+ MAASPlatformOptions: o.MAASPlatformOptions,
+ },
+ }, nil
+}
+
+func (o *RawMAASPlatformCreateOptions) Validate() (*ValidatedMAASPlatformCreateOptions, error) {
+ // Parse tags
+ if o.TagsRaw != "" {
+ o.Tags = strings.Split(o.TagsRaw, ",")
+ for i, tag := range o.Tags {
+ o.Tags[i] = strings.TrimSpace(tag)
+ }
+ }
+
+ // Parse nameservers
+ if o.NameserversRaw != "" {
+ o.StaticIP.Nameservers = strings.Split(o.NameserversRaw, ",")
+ for i, ns := range o.StaticIP.Nameservers {
+ o.StaticIP.Nameservers[i] = strings.TrimSpace(ns)
+ }
+ }
+
+ // Parse min disk size
+ if o.MinDiskSizeRaw != "" {
+ size, err := strconv.ParseInt(o.MinDiskSizeRaw, 10, 32)
+ if err != nil {
+ return nil, fmt.Errorf("invalid min-disk-size: %w", err)
+ }
+ diskSize := int32(size)
+ o.MinDiskSize = &diskSize
+ }
+
+ // Parse LXD enabled
+ if o.LXDEnabledRaw != "" {
+ enabled, err := strconv.ParseBool(o.LXDEnabledRaw)
+ if err != nil {
+ return nil, fmt.Errorf("invalid lxd-enabled: %w", err)
+ }
+ o.LXD.Enabled = enabled
+ }
+
+ // Validate required fields
+ if o.IdentityRef == "" {
+ return nil, fmt.Errorf("identity-ref is required")
+ }
+
+ // Validate resource requirements
+ if o.MinCPU < 1 {
+ return nil, fmt.Errorf("min-cpu must be at least 1")
+ }
+ if o.MinMemory < 1024 {
+ return nil, fmt.Errorf("min-memory must be at least 1024 MB")
+ }
+
+ return &ValidatedMAASPlatformCreateOptions{
+ validatedMAASPlatformCreateOptions: &validatedMAASPlatformCreateOptions{
+ completedMAASPlatformCreateOptions: &completedMAASPlatformCreateOptions{
+ MAASPlatformOptions: o.MAASPlatformOptions,
+ },
+ },
+ }, nil
+}
+
+func (o *MAASPlatformCreateOptions) UpdateNodePool(ctx context.Context, nodePool *hyperv1.NodePool, hcluster *hyperv1.HostedCluster, client crclient.Client) error {
+ // Set MAAS platform configuration
+ nodePool.Spec.Platform.MAAS = &hyperv1.MAASNodePoolPlatform{
+ IdentityRef: hyperv1.MAASIdentityReference{
+ Name: o.IdentityRef,
+ },
+ MachineType: o.MachineType,
+ Zone: o.Zone,
+ ResourcePool: o.ResourcePool,
+ Tags: o.Tags,
+ MinCPU: &o.MinCPU,
+ MinMemory: &o.MinMemory,
+ Image: o.Image,
+ }
+
+ // Set advanced configuration if provided
+ // TODO: These fields will be available once the API is updated
+ // if o.MinDiskSize != nil {
+ // nodePool.Spec.Platform.MAAS.MinDiskSize = o.MinDiskSize
+ // }
+
+ // if o.LXD != nil && o.LXD.Enabled {
+ // nodePool.Spec.Platform.MAAS.LXD = &hyperv1.MAASLXDConfig{
+ // Enabled: &o.LXD.Enabled,
+ // StoragePool: o.LXD.StoragePool,
+ // Network: o.LXD.Network,
+ // }
+ // }
+
+ // if o.StaticIP != nil && o.StaticIP.IP != "" {
+ // nodePool.Spec.Platform.MAAS.StaticIP = &hyperv1.MAASStaticIPConfig{
+ // IP: o.StaticIP.IP,
+ // CIDR: o.StaticIP.CIDR,
+ // Gateway: o.StaticIP.Gateway,
+ // Nameservers: o.StaticIP.Nameservers,
+ // }
+ // }
+
+ return nil
+}
+
+func (o *MAASPlatformCreateOptions) Type() hyperv1.PlatformType {
+ return hyperv1.MAASPlatform
+}
+
+func NewCreateCommand(opts *core.CreateNodePoolOptions) *cobra.Command {
+ rawOpts := DefaultOptions()
+ cmd := &cobra.Command{
+ Use: "maas",
+ Short: "Creates a MAAS NodePool",
+ SilenceUsage: true,
+ }
+
+ cmd.RunE = func(cmd *cobra.Command, args []string) error {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ validatedOpts, err := rawOpts.Validate()
+ if err != nil {
+ return err
+ }
+
+ completedOpts, err := validatedOpts.Complete()
+ if err != nil {
+ return err
+ }
+
+ return opts.CreateNodePool(ctx, completedOpts)
+ }
+
+ flags := cmd.Flags()
+ rawOpts.AddFlags(flags)
+
+ return cmd
+}
+
+func (o *RawMAASPlatformCreateOptions) AddFlags(flags *pflag.FlagSet) {
+ // Basic configuration
+ flags.StringVar(&o.IdentityRef, "identity-ref", "", "Name of the MAAS credentials secret (required)")
+ flags.StringVar(&o.MachineType, "machine-type", "", "MAAS machine type/tag for node selection")
+ flags.StringVar(&o.Zone, "zone", "", "MAAS zone where nodes will be deployed")
+ flags.StringVar(&o.ResourcePool, "resource-pool", "", "MAAS resource pool for node allocation")
+ flags.StringVar(&o.TagsRaw, "tags", "", "Comma-separated list of MAAS tags for filtering")
+
+ // Resource requirements
+ flags.Int32Var(&o.MinCPU, "min-cpu", 1, "Minimum CPU count required for nodes")
+ flags.Int32Var(&o.MinMemory, "min-memory", 1024, "Minimum memory in MB required for nodes")
+ flags.StringVar(&o.Image, "image", "", "MAAS image ID to use for nodes")
+
+ // Advanced configuration
+ flags.StringVar(&o.MinDiskSizeRaw, "min-disk-size", "", "Minimum disk size in GB")
+ flags.StringVar(&o.LXDEnabledRaw, "lxd-enabled", "false", "Enable LXD VM creation")
+ flags.StringVar(&o.LXD.StoragePool, "lxd-storage-pool", "", "LXD storage pool for VMs")
+ flags.StringVar(&o.LXD.Network, "lxd-network", "", "LXD network for VMs")
+ flags.StringVar(&o.StaticIP.IP, "static-ip", "", "Static IP address for VMs")
+ flags.StringVar(&o.StaticIP.CIDR, "static-ip-cidr", "", "Network CIDR for static IP")
+ flags.StringVar(&o.StaticIP.Gateway, "static-ip-gateway", "", "Network gateway for static IP")
+ flags.StringVar(&o.NameserversRaw, "static-ip-nameservers", "", "Comma-separated list of DNS servers")
+
+ // Note: Required flags are validated in the Validate() method
+}
diff --git a/control-plane-operator/controllers/hostedcontrolplane/configoperator/reconcile.go b/control-plane-operator/controllers/hostedcontrolplane/configoperator/reconcile.go
index 8e92cf269e8..670fd617894 100644
--- a/control-plane-operator/controllers/hostedcontrolplane/configoperator/reconcile.go
+++ b/control-plane-operator/controllers/hostedcontrolplane/configoperator/reconcile.go
@@ -235,6 +235,9 @@ func ReconcileRole(role *rbacv1.Role, ownerRef config.OwnerRef, platform hyperv1
},
},
}...)
+ case hyperv1.MAASPlatform:
+ // MAAS platform doesn't require additional RBAC rules
+ // It uses standard CAPI provider for infrastructure management
}
// TODO (jparrill): Add RBAC specific needs for Agent platform
return nil
diff --git a/control-plane-operator/controllers/hostedcontrolplane/cvo/reconcile.go b/control-plane-operator/controllers/hostedcontrolplane/cvo/reconcile.go
index 5205b573d6a..b62c03469f2 100644
--- a/control-plane-operator/controllers/hostedcontrolplane/cvo/reconcile.go
+++ b/control-plane-operator/controllers/hostedcontrolplane/cvo/reconcile.go
@@ -267,6 +267,21 @@ func ResourcesToRemove(platformType hyperv1.PlatformType) []client.Object {
&appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "cluster-node-tuning-operator", Namespace: "openshift-cluster-node-tuning-operator"}},
&appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "cluster-image-registry-operator", Namespace: "openshift-image-registry"}},
}
+ case hyperv1.MAASPlatform:
+ // MAAS platform uses default resource removal (same as other platforms)
+ return []client.Object{
+ &apiextensionsv1.CustomResourceDefinition{ObjectMeta: metav1.ObjectMeta{Name: "machineconfigs.machineconfiguration.openshift.io"}},
+ &apiextensionsv1.CustomResourceDefinition{ObjectMeta: metav1.ObjectMeta{Name: "machineconfigpools.machineconfiguration.openshift.io"}},
+ &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "network-operator", Namespace: "openshift-network-operator"}},
+ &rbacv1.ClusterRoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "default-account-cluster-network-operator"}},
+ &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "cluster-node-tuning-operator", Namespace: "openshift-cluster-node-tuning-operator"}},
+ &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "cluster-image-registry-operator", Namespace: "openshift-image-registry"}},
+ &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "cluster-storage-operator", Namespace: "openshift-cluster-storage-operator"}},
+ &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "csi-snapshot-controller-operator", Namespace: "openshift-cluster-storage-operator"}},
+ &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "aws-ebs-csi-driver-operator", Namespace: "openshift-cluster-csi-drivers"}},
+ &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "aws-ebs-csi-driver-controller", Namespace: "openshift-cluster-csi-drivers"}},
+ &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "csi-snapshot-controller", Namespace: "openshift-cluster-storage-operator"}},
+ }
default:
return []client.Object{
&apiextensionsv1.CustomResourceDefinition{ObjectMeta: metav1.ObjectMeta{Name: "machineconfigs.machineconfiguration.openshift.io"}},
diff --git a/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go b/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go
index a454e658243..19586177e43 100644
--- a/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go
+++ b/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go
@@ -1990,6 +1990,7 @@ func (r *HostedControlPlaneReconciler) reconcileInfrastructure(ctx context.Conte
if hcp.Spec.Services == nil {
return fmt.Errorf("service publishing strategy undefined")
}
+
if err := r.reconcileAPIServerService(ctx, hcp, createOrUpdate); err != nil {
return fmt.Errorf("failed to reconcile API server service: %w", err)
}
@@ -4524,6 +4525,16 @@ func (r *HostedControlPlaneReconciler) reconcileCoreIgnitionConfig(ctx context.C
return fmt.Errorf("failed to reconcile image content source policy ignition config: %w", err)
}
+ // Add MAAS-specific ignition configuration
+ if hcp.Spec.Platform.Type == hyperv1.MAASPlatform {
+ maasConfig := manifests.IgnitionMAASConfig(hcp.Namespace)
+ if _, err := createOrUpdate(ctx, r, maasConfig, func() error {
+ return ignition.ReconcileMAASIgnitionConfig(maasConfig, p.OwnerRef)
+ }); err != nil {
+ return fmt.Errorf("failed to reconcile MAAS ignition config: %w", err)
+ }
+ }
+
return nil
}
diff --git a/control-plane-operator/controllers/hostedcontrolplane/ignition/reconcile.go b/control-plane-operator/controllers/hostedcontrolplane/ignition/reconcile.go
index 3827133959a..610a6fdfe25 100644
--- a/control-plane-operator/controllers/hostedcontrolplane/ignition/reconcile.go
+++ b/control-plane-operator/controllers/hostedcontrolplane/ignition/reconcile.go
@@ -15,6 +15,7 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
jsonserializer "k8s.io/apimachinery/pkg/runtime/serializer/json"
+ "k8s.io/utils/ptr"
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -59,6 +60,20 @@ func ReconcileImageSourceMirrorsIgnitionConfigFromIDMS(cm *corev1.ConfigMap, own
return reconcileImageContentTypeIgnitionConfigMap(cm, imageDigestMirrorSet, ownerRef)
}
+func ReconcileMAASIgnitionConfig(cm *corev1.ConfigMap, ownerRef config.OwnerRef) error {
+ machineConfig := manifests.MachineConfigMAAS()
+ SetMachineConfigLabels(machineConfig)
+
+ // Generate MAAS-specific ignition content
+ serializedConfig, err := maasIgnitionConfig()
+ if err != nil {
+ return fmt.Errorf("failed to serialize MAAS ignition config: %w", err)
+ }
+ machineConfig.Spec.Config.Raw = serializedConfig
+
+ return reconcileMachineConfigIgnitionConfigMap(cm, machineConfig, ownerRef)
+}
+
func workerSSHConfig(sshKey string) ([]byte, error) {
config := &igntypes.Config{}
config.Ignition.Version = ignitionVersion
@@ -77,6 +92,44 @@ func workerSSHConfig(sshKey string) ([]byte, error) {
return serializeIgnitionConfig(config)
}
+func maasIgnitionConfig() ([]byte, error) {
+ config := &igntypes.Config{}
+ config.Ignition.Version = ignitionVersion
+
+ // Add custom user configuration for MAAS
+ config.Passwd = igntypes.Passwd{
+ Users: []igntypes.PasswdUser{
+ {
+ Name: "spectro",
+ Groups: []igntypes.Group{"sudo"},
+ Shell: ptr.To("/bin/bash"),
+ PasswordHash: ptr.To("$6$salt$JmHhpqORjPckABM.DZyXAntcxWnkBL/hC5B8xiwweGUYepl2N0AqVnkfJWMv9F0xFAIIz2siruaP7J2qnSyWH/"),
+ SSHAuthorizedKeys: []igntypes.SSHAuthorizedKey{
+ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDCzobpcF70X7oMUzK6xT2JgO6O57vgiT/9FepL7003hDw1QIxycwU9gmKhxBhJ69140RVSZi6IMmYN26xCJNcB/1cGejBRog59u4YNCcCUTzPz+jU2ZtjPJtYSFRMlR7qMI7aGFdx1rOxo8HmL9bV4ks+zWhtPTSvsk9zzte+XD0xIecoK/aewXQ7pEyfxXu/YQzAg+uUqrlOq+X4SRXGaWA02dfwQjr0kDQHFMtDZjyMmyXuNvNgPKBar5RkXeomdSw4IPuXzaU84RJfxGzF3SOYIqPWNfZCIPWPWOl7zBHnXg1+JI1LQFTs4sqpamML6mv+lMkvhJfX8CXFkzOmAteTjRYIi6f59QcSgfUeahb8R64CsAdqYKirCbIz9pz+UGM4Hc1mndUM/vf+UejidSQ+npxVP1nolpR2jLmLzad/9yracHikHTTf3WdjHM1aW/RtbY2y/Km/9ObVRw8agKVsu45sdN0KFI981E4Bb/1lDvxzSI32FOhLUgOW//SMFa/JQj78JgXkCZXCuA9f5U+DLFo6s7FAjsiFXyX6LMs/xO1jw3CkmgxMNfU7rc4Vj63xBYYWJsTGQsCDintodsHFZn/IOefJCCOQ0OMJxRSZqLu/Fp5Sd6iO6YsK3VqCh1RRYza1I81G9yBfUhIru87UPHpub/XqFh3/hWf19Jw== spectro2024",
+ },
+ },
+ },
+ }
+
+ // Add MAAS-specific storage configuration
+ config.Storage = igntypes.Storage{
+ Disks: []igntypes.Disk{
+ {
+ Device: "/dev/sda",
+ Partitions: []igntypes.Partition{
+ {
+ Number: 5,
+ ShouldExist: ptr.To(false),
+ WipePartitionEntry: ptr.To(true),
+ },
+ },
+ },
+ },
+ }
+
+ return serializeIgnitionConfig(config)
+}
+
func serializeIgnitionConfig(cfg *igntypes.Config) ([]byte, error) {
jsonBytes, err := json.Marshal(cfg)
if err != nil {
diff --git a/control-plane-operator/controllers/hostedcontrolplane/kcm/params.go b/control-plane-operator/controllers/hostedcontrolplane/kcm/params.go
index 98264681bbd..7637e294370 100644
--- a/control-plane-operator/controllers/hostedcontrolplane/kcm/params.go
+++ b/control-plane-operator/controllers/hostedcontrolplane/kcm/params.go
@@ -60,6 +60,7 @@ func NewKubeControllerManagerParams(ctx context.Context, hcp *hyperv1.HostedCont
if hcp.Spec.Platform.Type == hyperv1.AzurePlatform {
params.CloudProvider = "external"
}
+ // MAAS platform doesn't require external cloud provider configuration
params.PlatformType = hcp.Spec.Platform.Type
if hcp.Spec.Configuration != nil {
diff --git a/control-plane-operator/controllers/hostedcontrolplane/manifests/ignition.go b/control-plane-operator/controllers/hostedcontrolplane/manifests/ignition.go
index d716dfbecbc..57f3586541e 100644
--- a/control-plane-operator/controllers/hostedcontrolplane/manifests/ignition.go
+++ b/control-plane-operator/controllers/hostedcontrolplane/manifests/ignition.go
@@ -49,3 +49,20 @@ func ImageContentPolicyIgnitionConfig(ns string) *corev1.ConfigMap {
},
}
}
+
+func MachineConfigMAAS() *mcfgv1.MachineConfig {
+ return &mcfgv1.MachineConfig{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "99-maas-custom",
+ },
+ }
+}
+
+func IgnitionMAASConfig(ns string) *corev1.ConfigMap {
+ return &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "ignition-config-maas",
+ Namespace: ns,
+ },
+ }
+}
diff --git a/control-plane-operator/controllers/hostedcontrolplane/pki/kas.go b/control-plane-operator/controllers/hostedcontrolplane/pki/kas.go
index 60cb0b23109..6a63d169cae 100644
--- a/control-plane-operator/controllers/hostedcontrolplane/pki/kas.go
+++ b/control-plane-operator/controllers/hostedcontrolplane/pki/kas.go
@@ -132,6 +132,7 @@ func inClusterKASURL(platformType hyperv1.PlatformType) string {
if platformType == hyperv1.IBMCloudPlatform {
return fmt.Sprintf("https://%s:%d", manifests.KubeAPIServerServiceName, config.KASSVCIBMCloudPort)
}
+ // MAAS platform uses the default port
return fmt.Sprintf("https://%s:%d", manifests.KubeAPIServerServiceName, config.KASSVCPort)
}
diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/configoperator/role.go b/control-plane-operator/controllers/hostedcontrolplane/v2/configoperator/role.go
index 94f42c9a203..077ea2107aa 100644
--- a/control-plane-operator/controllers/hostedcontrolplane/v2/configoperator/role.go
+++ b/control-plane-operator/controllers/hostedcontrolplane/v2/configoperator/role.go
@@ -83,6 +83,9 @@ func adaptRole(cpContext component.WorkloadContext, role *rbacv1.Role) error {
},
},
}...)
+ case hyperv1.MAASPlatform:
+ // MAAS platform doesn't require additional RBAC rules
+ // It uses standard CAPI provider for infrastructure management
}
// TODO (jparrill): Add RBAC specific needs for Agent platform
return nil
diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/cvo/deployment.go b/control-plane-operator/controllers/hostedcontrolplane/v2/cvo/deployment.go
index 7b82ed5763c..2f7d83370d4 100644
--- a/control-plane-operator/controllers/hostedcontrolplane/v2/cvo/deployment.go
+++ b/control-plane-operator/controllers/hostedcontrolplane/v2/cvo/deployment.go
@@ -259,6 +259,21 @@ func resourcesToRemove(platformType hyperv1.PlatformType) []client.Object {
&appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "cluster-node-tuning-operator", Namespace: "openshift-cluster-node-tuning-operator"}},
&appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "cluster-image-registry-operator", Namespace: "openshift-image-registry"}},
}
+ case hyperv1.MAASPlatform:
+ // MAAS platform uses default resource removal (same as other platforms)
+ return []client.Object{
+ &apiextensionsv1.CustomResourceDefinition{ObjectMeta: metav1.ObjectMeta{Name: "machineconfigs.machineconfiguration.openshift.io"}},
+ &apiextensionsv1.CustomResourceDefinition{ObjectMeta: metav1.ObjectMeta{Name: "machineconfigpools.machineconfiguration.openshift.io"}},
+ &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "network-operator", Namespace: "openshift-network-operator"}},
+ &rbacv1.ClusterRoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "default-account-cluster-network-operator"}},
+ &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "cluster-node-tuning-operator", Namespace: "openshift-cluster-node-tuning-operator"}},
+ &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "cluster-image-registry-operator", Namespace: "openshift-image-registry"}},
+ &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "cluster-storage-operator", Namespace: "openshift-cluster-storage-operator"}},
+ &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "csi-snapshot-controller-operator", Namespace: "openshift-cluster-storage-operator"}},
+ &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "aws-ebs-csi-driver-operator", Namespace: "openshift-cluster-csi-drivers"}},
+ &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "aws-ebs-csi-driver-controller", Namespace: "openshift-cluster-csi-drivers"}},
+ &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "csi-snapshot-controller", Namespace: "openshift-cluster-storage-operator"}},
+ }
default:
return []client.Object{
&apiextensionsv1.CustomResourceDefinition{ObjectMeta: metav1.ObjectMeta{Name: "machineconfigs.machineconfiguration.openshift.io"}},
diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/dnsoperator/deployment.go b/control-plane-operator/controllers/hostedcontrolplane/v2/dnsoperator/deployment.go
index d7f89f9736b..acb817d8197 100644
--- a/control-plane-operator/controllers/hostedcontrolplane/v2/dnsoperator/deployment.go
+++ b/control-plane-operator/controllers/hostedcontrolplane/v2/dnsoperator/deployment.go
@@ -13,7 +13,7 @@ import (
func adaptDeployment(cpContext component.WorkloadContext, obj *appsv1.Deployment) error {
util.UpdateContainer("dns-operator", obj.Spec.Template.Spec.Containers, func(c *corev1.Container) {
// TODO (alberto): enforce ImagePullPolicy in component defaults.
- c.ImagePullPolicy = corev1.PullIfNotPresent
+ c.ImagePullPolicy = corev1.PullAlways
c.Command = []string{"dns-operator"}
c.Env = []corev1.EnvVar{
{
diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/etcd/statefulset.go b/control-plane-operator/controllers/hostedcontrolplane/v2/etcd/statefulset.go
index c53eb7ac24e..320719b9d51 100644
--- a/control-plane-operator/controllers/hostedcontrolplane/v2/etcd/statefulset.go
+++ b/control-plane-operator/controllers/hostedcontrolplane/v2/etcd/statefulset.go
@@ -114,7 +114,7 @@ func buildEtcdInitContainer(restoreUrl string) corev1.Container {
},
}
c.Image = "etcd"
- c.ImagePullPolicy = corev1.PullIfNotPresent
+ c.ImagePullPolicy = corev1.PullAlways
c.Command = []string{"/bin/sh", "-ce", etcdInitScript}
c.VolumeMounts = []corev1.VolumeMount{
{
@@ -130,7 +130,7 @@ func buildEtcdDefragControllerContainer(namespace string) corev1.Container {
Name: "etcd-defrag",
}
c.Image = "controlplane-operator"
- c.ImagePullPolicy = corev1.PullIfNotPresent
+ c.ImagePullPolicy = corev1.PullAlways
c.Command = []string{"control-plane-operator"}
c.Args = []string{
"etcd-defrag-controller",
diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/kas/deployment.go b/control-plane-operator/controllers/hostedcontrolplane/v2/kas/deployment.go
index c0fea73b712..a67c8e7d617 100644
--- a/control-plane-operator/controllers/hostedcontrolplane/v2/kas/deployment.go
+++ b/control-plane-operator/controllers/hostedcontrolplane/v2/kas/deployment.go
@@ -71,6 +71,9 @@ func adaptDeployment(cpContext component.WorkloadContext, deployment *appsv1.Dep
switch hcp.Spec.Platform.Type {
case hyperv1.AWSPlatform:
applyAWSPodIdentityWebhookContainer(&deployment.Spec.Template.Spec, hcp)
+ case hyperv1.MAASPlatform:
+ // MAAS platform doesn't require AWS pod identity webhook
+ // It uses standard CAPI provider for infrastructure management
}
if hcp.Spec.AuditWebhook != nil && len(hcp.Spec.AuditWebhook.Name) > 0 {
@@ -228,7 +231,7 @@ func applyAWSPodIdentityWebhookContainer(podSpec *corev1.PodSpec, hcp *hyperv1.H
podSpec.Containers = append(podSpec.Containers, corev1.Container{
Name: "aws-pod-identity-webhook",
Image: "aws-pod-identity-webhook",
- ImagePullPolicy: corev1.PullIfNotPresent,
+ ImagePullPolicy: corev1.PullAlways,
Command: []string{
"/usr/bin/aws-pod-identity-webhook",
"--annotation-prefix=eks.amazonaws.com",
diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine.go b/control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine.go
index ae955bf97f7..57acdf321e7 100644
--- a/control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine.go
+++ b/control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine.go
@@ -57,6 +57,9 @@ func (r *reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco
return reconcile.Result{}, fmt.Errorf("failed removing orphan kubevirt passthrough endpoint slices: %w", err)
}
}
+ case hyperv1.MAASPlatform:
+ // MAAS platform doesn't require special machine handling
+ // It uses standard CAPI provider for infrastructure management
}
log.Info("Reconciled Machine")
return reconcile.Result{}, nil
diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/resources/ingress/reconcile.go b/control-plane-operator/hostedclusterconfigoperator/controllers/resources/ingress/reconcile.go
index 81e4abaa4ee..31c3e15adbb 100644
--- a/control-plane-operator/hostedclusterconfigoperator/controllers/resources/ingress/reconcile.go
+++ b/control-plane-operator/hostedclusterconfigoperator/controllers/resources/ingress/reconcile.go
@@ -97,6 +97,14 @@ func ReconcileDefaultIngressController(ingressController *operatorv1.IngressCont
ingressController.Spec.DefaultCertificate = &corev1.LocalObjectReference{
Name: manifests.IngressDefaultIngressControllerCert().Name,
}
+ case hyperv1.MAASPlatform:
+ // MAAS platform uses default LoadBalancer strategy
+ ingressController.Spec.EndpointPublishingStrategy = &operatorv1.EndpointPublishingStrategy{
+ Type: operatorv1.LoadBalancerServiceStrategyType,
+ }
+ ingressController.Spec.DefaultCertificate = &corev1.LocalObjectReference{
+ Name: manifests.IngressDefaultIngressControllerCert().Name,
+ }
default:
ingressController.Spec.EndpointPublishingStrategy = &operatorv1.EndpointPublishingStrategy{
Type: operatorv1.LoadBalancerServiceStrategyType,
diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/resources/konnectivity/reconcile.go b/control-plane-operator/hostedclusterconfigoperator/controllers/resources/konnectivity/reconcile.go
index 3ff30df84b8..5a1d23d9bfe 100644
--- a/control-plane-operator/hostedclusterconfigoperator/controllers/resources/konnectivity/reconcile.go
+++ b/control-plane-operator/hostedclusterconfigoperator/controllers/resources/konnectivity/reconcile.go
@@ -83,6 +83,7 @@ func ReconcileAgentDaemonSet(daemonset *appsv1.DaemonSet, deploymentConfig confi
daemonset.Spec.Template.Spec.DNSPolicy = corev1.DNSClusterFirst
}
}
+ // MAAS platform uses default settings (HostNetwork: true, DNSPolicy: DNSDefault)
deploymentConfig.ApplyToDaemonSet(daemonset)
}
diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/resources/network/reconcile.go b/control-plane-operator/hostedclusterconfigoperator/controllers/resources/network/reconcile.go
index 2425851f116..3d32c2ba64e 100644
--- a/control-plane-operator/hostedclusterconfigoperator/controllers/resources/network/reconcile.go
+++ b/control-plane-operator/hostedclusterconfigoperator/controllers/resources/network/reconcile.go
@@ -73,6 +73,9 @@ func ReconcileNetworkOperator(network *operatorv1.Network, networkType hyperv1.N
}
network.Spec.DefaultNetwork.OVNKubernetesConfig.GatewayConfig.RoutingViaHost = true
}
+ case hyperv1.MAASPlatform:
+ // MAAS platform uses default network configuration
+ // No special network configuration needed for MAAS
default:
// do nothing
}
diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/resources/registry/registry.go b/control-plane-operator/hostedclusterconfigoperator/controllers/resources/registry/registry.go
index b3f01cf07d0..4546a58d978 100644
--- a/control-plane-operator/hostedclusterconfigoperator/controllers/resources/registry/registry.go
+++ b/control-plane-operator/hostedclusterconfigoperator/controllers/resources/registry/registry.go
@@ -31,9 +31,9 @@ func ReconcileRegistryConfig(cfg *imageregistryv1.Config, platform hyperv1.Platf
}
}
- // Initially assign storage as emptyDir for KubevirtPlatform and NonePlatform
+ // Initially assign storage as emptyDir for KubevirtPlatform, NonePlatform, and MAASPlatform
// Allow user to change storage afterwards
- if cfg.ResourceVersion == "" && (platform == hyperv1.KubevirtPlatform || platform == hyperv1.NonePlatform) {
+ if cfg.ResourceVersion == "" && (platform == hyperv1.KubevirtPlatform || platform == hyperv1.NonePlatform || platform == hyperv1.MAASPlatform) {
cfg.Spec.Storage = imageregistryv1.ImageRegistryConfigStorage{EmptyDir: &imageregistryv1.ImageRegistryConfigStorageEmptyDir{}}
}
// IBM Cloud platform allows to initialize the registry config and then afterwards the client is in full control of the updates
diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go b/control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go
index ff016a4ea69..f3fd20bb13a 100644
--- a/control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go
+++ b/control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go
@@ -721,6 +721,10 @@ func (r *reconciler) Reconcile(ctx context.Context, _ ctrl.Request) (ctrl.Result
case hyperv1.AzurePlatform:
log.Info("reconciling Azure specific resources")
errs = append(errs, r.reconcileAzureCloudNodeManager(ctx, releaseImage.ComponentImages()["azure-cloud-node-manager"])...)
+ case hyperv1.MAASPlatform:
+ log.Info("reconciling MAAS specific resources")
+ // MAAS platform doesn't require additional resource reconciliation
+ // It uses standard CAPI provider for infrastructure management
}
return ctrl.Result{}, errors.NewAggregate(errs)
}
@@ -1670,6 +1674,9 @@ func (r *reconciler) reconcileCloudCredentialSecrets(ctx context.Context, hcp *h
errs = append(errs, fmt.Errorf("failed to reconcile powervs image registry cloud credentials secret %w", err))
}
}
+ case hyperv1.MAASPlatform:
+ // MAAS platform doesn't require cloud credential secrets
+ // It uses standard CAPI provider for infrastructure management
}
return errs
}
@@ -1930,6 +1937,9 @@ func (r *reconciler) reconcileCloudConfig(ctx context.Context, hcp *hyperv1.Host
}); err != nil {
return fmt.Errorf("failed to reconcile the %s/%s configmap: %w", cmKCC.Namespace, cmKCC.Name, err)
}
+ case hyperv1.MAASPlatform:
+ // MAAS platform doesn't require cloud provider configuration
+ // It uses standard CAPI provider for infrastructure management
default:
return nil
}
@@ -2634,6 +2644,9 @@ func (r *reconciler) reconcileStorage(ctx context.Context, hcp *hyperv1.HostedCo
operatorv1.CinderCSIDriver,
operatorv1.ManilaCSIDriver,
}
+ case hyperv1.MAASPlatform:
+ // MAAS platform doesn't require specific CSI drivers
+ // It uses standard CAPI provider for infrastructure management
}
for _, driverName := range driverNames {
driver := manifests.ClusterCSIDriver(driverName)
@@ -2833,6 +2846,9 @@ func imageRegistryPlatformWithPVC(platform hyperv1.PlatformType) bool {
switch platform {
case hyperv1.OpenStackPlatform:
return true
+ case hyperv1.MAASPlatform:
+ // MAAS platform doesn't require PVC for image registry
+ return false
default:
return false
}
diff --git a/docs/content/images/controller-reconcilation-loops.png b/docs/content/images/controller-reconcilation-loops.png
new file mode 100644
index 00000000000..dfb66e973b0
Binary files /dev/null and b/docs/content/images/controller-reconcilation-loops.png differ
diff --git a/docs/content/images/hypershift-maas-architecture.png b/docs/content/images/hypershift-maas-architecture.png
new file mode 100644
index 00000000000..41bce205cc2
Binary files /dev/null and b/docs/content/images/hypershift-maas-architecture.png differ
diff --git a/docs/content/images/resource-creation-flow.png b/docs/content/images/resource-creation-flow.png
new file mode 100644
index 00000000000..b239aef6cb4
Binary files /dev/null and b/docs/content/images/resource-creation-flow.png differ
diff --git a/docs/content/reference/api.md b/docs/content/reference/api.md
index 6ee28f7fbb7..50f11d07e11 100644
--- a/docs/content/reference/api.md
+++ b/docs/content/reference/api.md
@@ -8401,6 +8401,393 @@ If omitted, the value will be inferred from the corev1.Service Load balancer typ
+###MAASIdentityReference { #hypershift.openshift.io/v1beta1.MAASIdentityReference }
+
+(Appears on:
+MAASNodePoolPlatform,
+MAASPlatformSpec)
+
+
+
MAASIdentityReference is a reference to an infrastructure
+provider identity to be used to provision cluster resources.
+
+
+
+
+| Field |
+Description |
+
+
+
+
+
+name
+
+string
+
+ |
+
+ Name is the name of a secret in the same namespace as the resource being provisioned.
+The secret must contain the following keys:
+- MAAS_ENDPOINT: MAAS API endpoint URL
+- MAAS_API_KEY: MAAS API key for authentication
+ |
+
+
+
+###MAASLXDConfig { #hypershift.openshift.io/v1beta1.MAASLXDConfig }
+
+(Appears on:
+MAASNodePoolPlatform)
+
+
+
MAASLXDConfig defines LXD VM creation options for a machine
+
+
+
+
+| Field |
+Description |
+
+
+
+
+
+enabled
+
+bool
+
+ |
+
+(Optional)
+ enabled specifies whether this machine should be created as an LXD VM
+ |
+
+
+
+storagePool
+
+string
+
+ |
+
+(Optional)
+ storagePool is the storage pool to use for the VM
+ |
+
+
+
+network
+
+string
+
+ |
+
+(Optional)
+ network is the network to connect the VM to
+ |
+
+
+
+###MAASNodePoolPlatform { #hypershift.openshift.io/v1beta1.MAASNodePoolPlatform }
+
+(Appears on:
+NodePoolPlatform)
+
+
+
MAASNodePoolPlatform specifies the configuration for MaaS platform.
+
+
+
+
+| Field |
+Description |
+
+
+
+
+
+identityRef
+
+
+MAASIdentityReference
+
+
+ |
+
+ identityRef is a reference to a secret holding MAAS credentials
+to be used when reconciling the node pool.
+The secret must contain the following keys:
+- MAAS_ENDPOINT: MAAS API endpoint URL
+- MAAS_API_KEY: MAAS API key for authentication
+ |
+
+
+
+machineType
+
+string
+
+ |
+
+(Optional)
+ machineType specifies the type of MAAS machine to use for the nodes.
+This corresponds to the MAAS machine type/tag that will be used for node selection.
+ |
+
+
+
+zone
+
+string
+
+ |
+
+(Optional)
+ zone specifies the MAAS zone where the nodes will be deployed.
+If not specified, nodes will be deployed in any available zone.
+ |
+
+
+
+tags
+
+[]string
+
+ |
+
+(Optional)
+ tags specifies additional MAAS tags to apply to the nodes for filtering and organization.
+ |
+
+
+
+resourcePool
+
+string
+
+ |
+
+(Optional)
+ resourcePool specifies the MAAS resource pool to use for node allocation.
+ |
+
+
+
+minCpu
+
+int32
+
+ |
+
+(Optional)
+ minCpu specifies the minimum CPU count required for the nodes.
+ |
+
+
+
+minMemory
+
+int32
+
+ |
+
+(Optional)
+ minMemory specifies the minimum memory in MB required for the nodes.
+ |
+
+
+
+image
+
+string
+
+ |
+
+(Optional)
+ image specifies the MAAS image ID to use for the nodes.
+If not specified, a default image will be used based on the release.
+ |
+
+
+
+failureDomain
+
+string
+
+ |
+
+(Optional)
+ failureDomain specifies the failure domain the machine will be created in.
+Must match a key in the FailureDomains map stored on the cluster object.
+ |
+
+
+
+minDiskSize
+
+int32
+
+ |
+
+(Optional)
+ minDiskSize specifies the minimum disk size in GB required for the nodes.
+ |
+
+
+
+lxd
+
+
+MAASLXDConfig
+
+
+ |
+
+(Optional)
+ lxd contains configuration for creating this machine as an LXD VM on a host
+when enabled. When nil or disabled, this machine is created on bare metal.
+ |
+
+
+
+staticIP
+
+
+MAASStaticIPConfig
+
+
+ |
+
+(Optional)
+ staticIP configuration for VMs
+ |
+
+
+
+###MAASPlatformSpec { #hypershift.openshift.io/v1beta1.MAASPlatformSpec }
+
+(Appears on:
+PlatformSpec)
+
+
+
MAASPlatformSpec specifies configuration for clusters running on MaaS (Metal as a Service).
+
+
+
+
+| Field |
+Description |
+
+
+
+
+
+identityRef
+
+
+MAASIdentityReference
+
+
+ |
+
+ identityRef is a reference to a secret holding MAAS credentials
+to be used when reconciling the hosted cluster.
+ |
+
+
+
+dnsDomain
+
+string
+
+ |
+
+(Optional)
+ dnsDomain is the DNS domain for the MAAS cluster.
+ |
+
+
+
+zone
+
+string
+
+ |
+
+(Optional)
+ zone specifies the MAAS zone where the cluster will be deployed.
+If not specified, the cluster will be deployed in any available zone.
+ |
+
+
+
+###MAASStaticIPConfig { #hypershift.openshift.io/v1beta1.MAASStaticIPConfig }
+
+(Appears on:
+MAASNodePoolPlatform)
+
+
+
MAASStaticIPConfig defines the static IP configuration for a VM
+
+
+
+
+| Field |
+Description |
+
+
+
+
+
+ip
+
+string
+
+ |
+
+(Optional)
+ ip is the static IP address to assign
+ |
+
+
+
+cidr
+
+string
+
+ |
+
+(Optional)
+ cidr is the network CIDR
+ |
+
+
+
+gateway
+
+string
+
+ |
+
+(Optional)
+ gateway is the network gateway
+ |
+
+
+
+nameservers
+
+[]string
+
+ |
+
+(Optional)
+ nameservers is a list of DNS servers
+ |
+
+
+
###MachineNetworkEntry { #hypershift.openshift.io/v1beta1.MachineNetworkEntry }
(Appears on:
@@ -9213,6 +9600,20 @@ OpenStackNodePoolPlatform
OpenStack specifies the configuration used when using OpenStack platform.
+
+
+maas
+
+
+MAASNodePoolPlatform
+
+
+ |
+
+(Optional)
+ maas specifies the configuration used when using MaaS platform.
+ |
+
###NodePoolPlatformStatus { #hypershift.openshift.io/v1beta1.NodePoolPlatformStatus }
@@ -10241,6 +10642,20 @@ OpenStackPlatformSpec
OpenStack specifies configuration for clusters running on OpenStack.
+
+
+maas
+
+
+MAASPlatformSpec
+
+
+ |
+
+(Optional)
+ maas specifies configuration for clusters running on MaaS (Metal as a Service).
+ |
+
###PlatformStatus { #hypershift.openshift.io/v1beta1.PlatformStatus }
@@ -10307,6 +10722,9 @@ AWSPlatformStatus
"KubeVirt" |
KubevirtPlatform represents Kubevirt infrastructure.
|
+
"MAAS" |
+MAASPlatform represents MaaS (Metal as a Service) infrastructure.
+ |
"None" |
NonePlatform represents user supplied (e.g. bare metal) infrastructure.
|
diff --git a/go.mod b/go.mod
index 56104fe41c2..580858b0d79 100644
--- a/go.mod
+++ b/go.mod
@@ -60,6 +60,7 @@ require (
github.com/prometheus/client_golang v1.20.5
github.com/prometheus/client_model v0.6.1
github.com/prometheus/common v0.62.0
+ github.com/spectrocloud/cluster-api-provider-maas v0.5.1-0.20250512112717-769064ca22e9
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.6
github.com/stretchr/testify v1.10.0
@@ -103,7 +104,7 @@ require (
sigs.k8s.io/controller-runtime v0.20.1
sigs.k8s.io/karpenter v1.2.1-0.20250212185021-45f73ec7a790
sigs.k8s.io/secrets-store-csi-driver v1.4.8
- sigs.k8s.io/structured-merge-diff/v4 v4.4.2
+ sigs.k8s.io/structured-merge-diff/v4 v4.4.3
sigs.k8s.io/yaml v1.4.0
)
diff --git a/go.sum b/go.sum
index 07e20cc426c..488497d4a10 100644
--- a/go.sum
+++ b/go.sum
@@ -601,6 +601,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
+github.com/spectrocloud/cluster-api-provider-maas v0.5.1-0.20250512112717-769064ca22e9 h1:jI2lSDCBbPmZ1Fklv4wEULUvHD4vhey+3AHqtpUw9x4=
+github.com/spectrocloud/cluster-api-provider-maas v0.5.1-0.20250512112717-769064ca22e9/go.mod h1:J50WRadGERZ8sGhytqfNZgwZvOVfBKEBvflHZK+zeR8=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
@@ -1012,8 +1014,8 @@ sigs.k8s.io/secrets-store-csi-driver v1.4.8 h1:YmL0lx9HMYqeZCnLyOZRMuGAZXmP/e42U
sigs.k8s.io/secrets-store-csi-driver v1.4.8/go.mod h1:IawZyjzh3xGt6hHdckJUf3ls04O0zG5H550PEZz/beo=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
-sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA=
-sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
+sigs.k8s.io/structured-merge-diff/v4 v4.4.3 h1:sCP7Vv3xx/CWIuTPVN38lUPx0uw0lcLfzaiDa8Ja01A=
+sigs.k8s.io/structured-merge-diff/v4 v4.4.3/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
diff --git a/hypershift-operator/controllers/hostedcluster/internal/platform/maas/maas.go b/hypershift-operator/controllers/hostedcluster/internal/platform/maas/maas.go
new file mode 100644
index 00000000000..74ea5b63ef9
--- /dev/null
+++ b/hypershift-operator/controllers/hostedcluster/internal/platform/maas/maas.go
@@ -0,0 +1,264 @@
+package maas
+
+import (
+ "context"
+ "fmt"
+ "os"
+
+ hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1"
+ "github.com/openshift/hypershift/support/images"
+ "github.com/openshift/hypershift/support/upsert"
+
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ rbacv1 "k8s.io/api/rbac/v1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/api/resource"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ "sigs.k8s.io/controller-runtime/pkg/client"
+
+ capimaas "github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1"
+)
+
+const (
+ MAASCAPIProvider = "maas-cluster-api-controllers"
+)
+
+type MaaS struct {
+ capiProviderImage string
+}
+
+func New(capiProviderImage string) *MaaS {
+ return &MaaS{
+ capiProviderImage: capiProviderImage,
+ }
+}
+
+func (p *MaaS) ReconcileCAPIInfraCR(ctx context.Context, c client.Client, createOrUpdate upsert.CreateOrUpdateFN,
+ hcluster *hyperv1.HostedCluster,
+ controlPlaneNamespace string,
+ apiEndpoint hyperv1.APIEndpoint,
+) (client.Object, error) {
+ if hcluster.Spec.Platform.MAAS == nil {
+ return nil, fmt.Errorf("failed to reconcile MAAS CAPI cluster, empty MAAS platform spec")
+ }
+
+ // Create a MAAS cluster using the actual CAPI provider types
+ maasCluster := &capimaas.MaasCluster{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: hcluster.Name,
+ Namespace: controlPlaneNamespace,
+ Annotations: map[string]string{
+ "spectrocloud.com/custom-dns-provided": "",
+ },
+ Labels: map[string]string{
+ "hypershift.openshift.io/cluster": hcluster.Name,
+ "platform": "maas",
+ },
+ },
+ }
+
+ // Use the createOrUpdate function to ensure the object is properly managed
+ if _, err := createOrUpdate(ctx, c, maasCluster, func() error {
+ // Get DNS domain from MAAS platform spec or use a default
+ dnsDomain := "maas.local"
+ if hcluster.Spec.Platform.MAAS.DNSDomain != "" {
+ dnsDomain = hcluster.Spec.Platform.MAAS.DNSDomain
+ }
+
+ maasCluster.Spec = capimaas.MaasClusterSpec{
+ DNSDomain: dnsDomain,
+ ControlPlaneEndpoint: capimaas.APIEndpoint{
+ Host: apiEndpoint.Host,
+ Port: int(apiEndpoint.Port),
+ },
+ }
+
+ // Ensure the annotation is always present
+ if maasCluster.Annotations == nil {
+ maasCluster.Annotations = make(map[string]string)
+ }
+ maasCluster.Annotations["spectrocloud.com/custom-dns-provided"] = ""
+
+ return nil
+ }); err != nil {
+ return nil, fmt.Errorf("failed to create or update MAAS cluster: %w", err)
+ }
+
+ return maasCluster, nil
+}
+
+func (p *MaaS) CAPIProviderDeploymentSpec(hcluster *hyperv1.HostedCluster, _ *hyperv1.HostedControlPlane) (*appsv1.DeploymentSpec, error) {
+ // Check for environment variable override
+ image := p.capiProviderImage
+ if envImage := os.Getenv(images.MAASCAPIProviderEnvVar); len(envImage) > 0 {
+ image = envImage
+ }
+
+ // Return a deployment spec for the MAAS CAPI provider with proper credential mounting
+ return &appsv1.DeploymentSpec{
+ Template: corev1.PodTemplateSpec{
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "maas-capi-controller",
+ Image: image,
+ Args: []string{
+ "--v=2",
+ "--leader-elect=true",
+ "--sync-period=15m",
+ "--namespace=$(NAMESPACE)",
+ },
+ Env: []corev1.EnvVar{
+ {
+ Name: "NAMESPACE",
+ ValueFrom: &corev1.EnvVarSource{
+ FieldRef: &corev1.ObjectFieldSelector{
+ FieldPath: "metadata.namespace",
+ },
+ },
+ },
+ {
+ Name: "MAAS_ENDPOINT",
+ ValueFrom: &corev1.EnvVarSource{
+ SecretKeyRef: &corev1.SecretKeySelector{
+ LocalObjectReference: corev1.LocalObjectReference{
+ Name: hcluster.Spec.Platform.MAAS.IdentityRef.Name,
+ },
+ Key: "MAAS_ENDPOINT",
+ },
+ },
+ },
+ {
+ Name: "MAAS_API_KEY",
+ ValueFrom: &corev1.EnvVarSource{
+ SecretKeyRef: &corev1.SecretKeySelector{
+ LocalObjectReference: corev1.LocalObjectReference{
+ Name: hcluster.Spec.Platform.MAAS.IdentityRef.Name,
+ },
+ Key: "MAAS_API_KEY",
+ },
+ },
+ },
+ {
+ Name: "MAAS_ZONE",
+ Value: hcluster.Spec.Platform.MAAS.Zone,
+ },
+ },
+ Resources: corev1.ResourceRequirements{
+ Limits: corev1.ResourceList{
+ corev1.ResourceCPU: resource.MustParse("500m"),
+ corev1.ResourceMemory: resource.MustParse("512Mi"),
+ },
+ Requests: corev1.ResourceList{
+ corev1.ResourceCPU: resource.MustParse("200m"),
+ corev1.ResourceMemory: resource.MustParse("128Mi"),
+ },
+ },
+ },
+ },
+ },
+ },
+ }, nil
+}
+
+func (p *MaaS) ReconcileCredentials(ctx context.Context, c client.Client, createOrUpdate upsert.CreateOrUpdateFN, hcluster *hyperv1.HostedCluster, controlPlaneNamespace string) error {
+ if hcluster.Spec.Platform.MAAS == nil {
+ return fmt.Errorf("failed to reconcile MAAS credentials, empty MAAS platform spec")
+ }
+
+ // Get the referenced credentials secret
+ credentialsSecret := &corev1.Secret{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: hcluster.Spec.Platform.MAAS.IdentityRef.Name,
+ Namespace: hcluster.Namespace,
+ },
+ }
+
+ if err := c.Get(ctx, client.ObjectKeyFromObject(credentialsSecret), credentialsSecret); err != nil {
+ return fmt.Errorf("failed to get MAAS credentials secret: %w", err)
+ }
+
+ // Validate that the secret contains the required keys
+ requiredKeys := []string{"MAAS_ENDPOINT", "MAAS_API_KEY"}
+ for _, key := range requiredKeys {
+ if _, exists := credentialsSecret.Data[key]; !exists {
+ return fmt.Errorf("MAAS credentials secret is missing required key: %s", key)
+ }
+ }
+
+ // Create a copy of the secret in the control plane namespace
+ // Use the same name as referenced in IdentityRef so capi-provider can find it
+ controlPlaneSecret := &corev1.Secret{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: hcluster.Spec.Platform.MAAS.IdentityRef.Name,
+ Namespace: controlPlaneNamespace,
+ Labels: map[string]string{
+ "hypershift.openshift.io/cluster": hcluster.Name,
+ "platform": "maas",
+ },
+ },
+ Type: corev1.SecretTypeOpaque,
+ Data: credentialsSecret.Data,
+ }
+
+ // Check if the secret already exists and has the same data
+ existingSecret := &corev1.Secret{}
+ err := c.Get(ctx, client.ObjectKeyFromObject(controlPlaneSecret), existingSecret)
+ if err != nil {
+ if !apierrors.IsNotFound(err) {
+ return fmt.Errorf("failed to get existing MAAS credentials secret: %w", err)
+ }
+ // Secret doesn't exist, create it
+ controlPlaneSecret.Data = credentialsSecret.Data
+ _, err = createOrUpdate(ctx, c, controlPlaneSecret, func() error {
+ return nil
+ })
+ } else {
+ // Secret exists, check if data has changed
+ dataChanged := existingSecret.Data == nil ||
+ string(existingSecret.Data["MAAS_ENDPOINT"]) != string(credentialsSecret.Data["MAAS_ENDPOINT"]) ||
+ string(existingSecret.Data["MAAS_API_KEY"]) != string(credentialsSecret.Data["MAAS_API_KEY"])
+
+ if dataChanged {
+ // Data has changed, update the secret
+ controlPlaneSecret.Data = credentialsSecret.Data
+ _, err = createOrUpdate(ctx, c, controlPlaneSecret, func() error {
+ return nil
+ })
+ }
+ // If data hasn't changed, do nothing
+ }
+
+ return err
+}
+
+func (p *MaaS) ReconcileSecretEncryption(ctx context.Context, c client.Client, createOrUpdate upsert.CreateOrUpdateFN, hcluster *hyperv1.HostedCluster, controlPlaneNamespace string) error {
+ // MAAS doesn't support secret encryption, so this is a no-op
+ return nil
+}
+
+func (p *MaaS) CAPIProviderPolicyRules() []rbacv1.PolicyRule {
+ // MAAS doesn't require additional policy rules beyond the default CAPI rules
+ return nil
+}
+
+func (p *MaaS) DeleteCredentials(ctx context.Context, c client.Client, hcluster *hyperv1.HostedCluster, controlPlaneNamespace string) error {
+ // Delete the MAAS credentials secret
+ credentialsSecret := &corev1.Secret{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: fmt.Sprintf("%s-maas-credentials", hcluster.Name),
+ Namespace: controlPlaneNamespace,
+ },
+ }
+
+ if err := c.Delete(ctx, credentialsSecret); err != nil {
+ // If the secret doesn't exist, that's fine
+ if client.IgnoreNotFound(err) != nil {
+ return fmt.Errorf("failed to delete MAAS credentials secret: %w", err)
+ }
+ }
+
+ return nil
+}
diff --git a/hypershift-operator/controllers/hostedcluster/internal/platform/platform.go b/hypershift-operator/controllers/hostedcluster/internal/platform/platform.go
index 7a81d1df543..556d3d10996 100644
--- a/hypershift-operator/controllers/hostedcluster/internal/platform/platform.go
+++ b/hypershift-operator/controllers/hostedcluster/internal/platform/platform.go
@@ -10,6 +10,7 @@ import (
"github.com/openshift/hypershift/hypershift-operator/controllers/hostedcluster/internal/platform/azure"
"github.com/openshift/hypershift/hypershift-operator/controllers/hostedcluster/internal/platform/ibmcloud"
"github.com/openshift/hypershift/hypershift-operator/controllers/hostedcluster/internal/platform/kubevirt"
+ "github.com/openshift/hypershift/hypershift-operator/controllers/hostedcluster/internal/platform/maas"
"github.com/openshift/hypershift/hypershift-operator/controllers/hostedcluster/internal/platform/none"
"github.com/openshift/hypershift/hypershift-operator/controllers/hostedcluster/internal/platform/openstack"
"github.com/openshift/hypershift/hypershift-operator/controllers/hostedcluster/internal/platform/powervs"
@@ -39,6 +40,7 @@ var _ Platform = ibmcloud.IBMCloud{}
var _ Platform = none.None{}
var _ Platform = agent.Agent{}
var _ Platform = kubevirt.Kubevirt{}
+var _ Platform = &maas.MaaS{}
type Platform interface {
// ReconcileCAPIInfraCR is called during HostedCluster reconciliation prior to reconciling the CAPI Cluster CR.
@@ -152,6 +154,15 @@ func GetPlatform(ctx context.Context, hcluster *hyperv1.HostedCluster, releasePr
}
}
platform = openstack.New(capiImageProvider, orcImage, payloadVersion)
+ case hyperv1.MAASPlatform:
+ // Check for annotation override first
+ if capiImage, exists := hcluster.Annotations[hyperv1.ClusterAPIProviderMAASImage]; exists {
+ capiImageProvider = capiImage
+ } else {
+ // Since MaaS image is not in OpenShift payload, use default
+ capiImageProvider = "us-docker.pkg.dev/palette-images/palette/cluster-api-maas/cluster-api-provider-maas-controller:v0.6.1-spectro-4.7.0"
+ }
+ platform = maas.New(capiImageProvider)
default:
return nil, fmt.Errorf("unsupported platform: %s", hcluster.Spec.Platform.Type)
}
diff --git a/hypershift-operator/controllers/nodepool/capi.go b/hypershift-operator/controllers/nodepool/capi.go
index a0946862866..3b1f74a5eca 100644
--- a/hypershift-operator/controllers/nodepool/capi.go
+++ b/hypershift-operator/controllers/nodepool/capi.go
@@ -11,6 +11,7 @@ import (
hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1"
"github.com/openshift/hypershift/hypershift-operator/controllers/manifests"
"github.com/openshift/hypershift/hypershift-operator/controllers/nodepool/kubevirt"
+ "github.com/openshift/hypershift/hypershift-operator/controllers/nodepool/maas"
"github.com/openshift/hypershift/hypershift-operator/controllers/nodepool/openstack"
"github.com/openshift/hypershift/support/api"
supportutil "github.com/openshift/hypershift/support/util"
@@ -26,6 +27,7 @@ import (
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/utils/ptr"
+ capimaas "github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1"
capiaws "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
capiazure "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
capipowervs "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta2"
@@ -386,7 +388,15 @@ func (c *CAPI) reconcileMachineDeployment(ctx context.Context, log logr.Logger,
// after it has been created with defaults.
machineDeployment.Spec.MinReadySeconds = ptr.To[int32](0)
machineDeployment.Spec.RevisionHistoryLimit = ptr.To[int32](1)
- machineDeployment.Spec.ProgressDeadlineSeconds = ptr.To[int32](600)
+
+ // Set ProgressDeadlineSeconds with configurable timeout via annotation
+ progressDeadlineSeconds := int32(3600) // default 1 hour
+ if nodePool.Annotations[hyperv1.MachineDeploymentProgressDeadlineSecondsAnnotation] != "" {
+ if val, err := strconv.Atoi(nodePool.Annotations[hyperv1.MachineDeploymentProgressDeadlineSecondsAnnotation]); err == nil && val > 0 {
+ progressDeadlineSeconds = int32(val)
+ }
+ }
+ machineDeployment.Spec.ProgressDeadlineSeconds = ptr.To[int32](progressDeadlineSeconds)
machineDeployment.Spec.ClusterName = capiClusterName
if machineDeployment.Spec.Selector.MatchLabels == nil {
@@ -870,6 +880,33 @@ func (c *CAPI) machineTemplateBuilders() (client.Object, func(object client.Obje
o.Annotations[nodePoolAnnotation] = client.ObjectKeyFromObject(nodePool).String()
return nil
}
+ case hyperv1.MAASPlatform:
+ template = &capimaas.MaasMachineTemplate{}
+ var err error
+ machineTemplateSpec, err = maas.MachineTemplateSpec(nodePool)
+ if err != nil {
+ SetStatusCondition(&nodePool.Status.Conditions, hyperv1.NodePoolCondition{
+ Type: hyperv1.NodePoolValidMachineTemplateConditionType,
+ Status: corev1.ConditionFalse,
+ Reason: hyperv1.InvalidMAASMachineTemplate,
+ Message: err.Error(),
+ ObservedGeneration: nodePool.Generation,
+ })
+
+ return nil, nil, "", err
+ } else {
+ removeStatusCondition(&nodePool.Status.Conditions, hyperv1.NodePoolValidMachineTemplateConditionType)
+ }
+
+ mutateTemplate = func(object client.Object) error {
+ o, _ := object.(*capimaas.MaasMachineTemplate)
+ o.Spec = *machineTemplateSpec.(*capimaas.MaasMachineTemplateSpec)
+ if o.Annotations == nil {
+ o.Annotations = make(map[string]string)
+ }
+ o.Annotations[nodePoolAnnotation] = client.ObjectKeyFromObject(nodePool).String()
+ return nil
+ }
default:
// TODO(alberto): Consider signal in a condition.
return nil, nil, "", fmt.Errorf("unsupported platform type: %s", nodePool.Spec.Platform.Type)
diff --git a/hypershift-operator/controllers/nodepool/maas.go b/hypershift-operator/controllers/nodepool/maas.go
new file mode 100644
index 00000000000..7b81a338cbc
--- /dev/null
+++ b/hypershift-operator/controllers/nodepool/maas.go
@@ -0,0 +1,62 @@
+package nodepool
+
+import (
+ "fmt"
+
+ capimaas "github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/utils/ptr"
+)
+
+func (c *CAPI) maasMachineTemplate(templateNameGenerator func(spec any) (string, error)) (*capimaas.MaasMachineTemplate, error) {
+ nodePool := c.nodePool
+
+ // Create MAAS machine spec with required fields
+ maasMachineSpec := capimaas.MaasMachineSpec{
+ // Required fields
+ Image: "ubuntu/focal", // Default image - should be configurable
+ MinCPU: ptr.To(1), // Default minimum CPU
+ MinMemoryInMB: ptr.To(1024), // Default minimum memory in MB
+ }
+
+ // Override with NodePool platform configuration if specified
+ if nodePool.Spec.Platform.MAAS != nil {
+ if nodePool.Spec.Platform.MAAS.Image != "" {
+ maasMachineSpec.Image = nodePool.Spec.Platform.MAAS.Image
+ }
+ if nodePool.Spec.Platform.MAAS.MinCPU != nil {
+ maasMachineSpec.MinCPU = ptr.To(int(*nodePool.Spec.Platform.MAAS.MinCPU))
+ }
+ if nodePool.Spec.Platform.MAAS.MinMemory != nil {
+ maasMachineSpec.MinMemoryInMB = ptr.To(int(*nodePool.Spec.Platform.MAAS.MinMemory))
+ }
+ if nodePool.Spec.Platform.MAAS.Tags != nil {
+ maasMachineSpec.Tags = nodePool.Spec.Platform.MAAS.Tags
+ }
+ if nodePool.Spec.Platform.MAAS.ResourcePool != "" {
+ maasMachineSpec.ResourcePool = ptr.To(nodePool.Spec.Platform.MAAS.ResourcePool)
+ }
+ }
+
+ // Create the template spec
+ spec := capimaas.MaasMachineTemplateSpec{
+ Template: capimaas.MaasMachineTemplateResource{
+ Spec: maasMachineSpec,
+ },
+ }
+
+ templateName, err := templateNameGenerator(spec)
+ if err != nil {
+ return nil, fmt.Errorf("failed to generate template name: %w", err)
+ }
+
+ template := &capimaas.MaasMachineTemplate{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: templateName,
+ },
+ Spec: spec,
+ }
+
+ return template, nil
+}
+
diff --git a/hypershift-operator/controllers/nodepool/maas/maas.go b/hypershift-operator/controllers/nodepool/maas/maas.go
new file mode 100644
index 00000000000..de6dc2258e3
--- /dev/null
+++ b/hypershift-operator/controllers/nodepool/maas/maas.go
@@ -0,0 +1,64 @@
+package maas
+
+import (
+ hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1"
+ capimaas "github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1"
+ "k8s.io/utils/ptr"
+)
+
+// MachineTemplateSpec creates a MAAS machine template specification for the given NodePool
+func MachineTemplateSpec(nodePool *hyperv1.NodePool) (*capimaas.MaasMachineTemplateSpec, error) {
+ // Create MAAS machine spec with required fields
+ maasMachineSpec := capimaas.MaasMachineSpec{
+ // Required fields
+ Image: "ubuntu/focal", // Default image - should be configurable
+ MinCPU: ptr.To(1), // Default minimum CPU
+ MinMemoryInMB: ptr.To(1024), // Default minimum memory in MB
+ }
+
+ // Override with NodePool platform configuration if specified
+ if nodePool.Spec.Platform.MAAS != nil {
+ // Map image
+ if nodePool.Spec.Platform.MAAS.Image != "" {
+ maasMachineSpec.Image = nodePool.Spec.Platform.MAAS.Image
+ }
+
+ // Map CPU/Memory requirements
+ if nodePool.Spec.Platform.MAAS.MinCPU != nil {
+ maasMachineSpec.MinCPU = ptr.To(int(*nodePool.Spec.Platform.MAAS.MinCPU))
+ }
+ if nodePool.Spec.Platform.MAAS.MinMemory != nil {
+ maasMachineSpec.MinMemoryInMB = ptr.To(int(*nodePool.Spec.Platform.MAAS.MinMemory))
+ }
+
+ // Map failure domain (prefer FailureDomain over Zone)
+ if nodePool.Spec.Platform.MAAS.FailureDomain != "" {
+ maasMachineSpec.FailureDomain = ptr.To(nodePool.Spec.Platform.MAAS.FailureDomain)
+ } else if nodePool.Spec.Platform.MAAS.Zone != "" {
+ // Map Zone to FailureDomain if FailureDomain not specified
+ maasMachineSpec.FailureDomain = ptr.To(nodePool.Spec.Platform.MAAS.Zone)
+ }
+
+ // Map resource pool
+ if nodePool.Spec.Platform.MAAS.ResourcePool != "" {
+ maasMachineSpec.ResourcePool = ptr.To(nodePool.Spec.Platform.MAAS.ResourcePool)
+ }
+
+ // Map tags
+ if len(nodePool.Spec.Platform.MAAS.Tags) > 0 {
+ maasMachineSpec.Tags = nodePool.Spec.Platform.MAAS.Tags
+ }
+
+ // TODO: Add support for MinDiskSize, LXD, and StaticIP when available in HyperShift API
+ // These fields are defined in the API but not yet available in the controller
+ }
+
+ // Create the template spec
+ spec := capimaas.MaasMachineTemplateSpec{
+ Template: capimaas.MaasMachineTemplateResource{
+ Spec: maasMachineSpec,
+ },
+ }
+
+ return &spec, nil
+}
diff --git a/hypershift-operator/controllers/nodepool/nodepool_controller.go b/hypershift-operator/controllers/nodepool/nodepool_controller.go
index 068f7e54337..e80d55bea13 100644
--- a/hypershift-operator/controllers/nodepool/nodepool_controller.go
+++ b/hypershift-operator/controllers/nodepool/nodepool_controller.go
@@ -439,6 +439,10 @@ func isArchAndPlatformSupported(nodePool *hyperv1.NodePool) bool {
if nodePool.Spec.Arch == hyperv1.ArchitectureAMD64 || nodePool.Spec.Arch == hyperv1.ArchitectureARM64 {
supported = true
}
+ case hyperv1.MAASPlatform:
+ if nodePool.Spec.Arch == hyperv1.ArchitectureAMD64 || nodePool.Spec.Arch == hyperv1.ArchitectureARM64 {
+ supported = true
+ }
}
return supported
diff --git a/support/api/scheme.go b/support/api/scheme.go
index e0a3f32a770..0f622729c6e 100644
--- a/support/api/scheme.go
+++ b/support/api/scheme.go
@@ -34,6 +34,7 @@ import (
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
+ capimaas "github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1"
capiaws "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
capiazure "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
capiibm "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta2"
@@ -116,6 +117,7 @@ func init() {
_ = machinev1beta1.AddToScheme(Scheme)
_ = capiopenstackv1alpha1.AddToScheme(Scheme)
_ = capiopenstackv1beta1.AddToScheme(Scheme)
+ _ = capimaas.AddToScheme(Scheme)
_ = secretsstorev1.AddToScheme(Scheme)
_ = kcpv1.AddToScheme(Scheme)
_ = orcv1alpha1.AddToScheme(Scheme)
diff --git a/support/globalconfig/infrastructure.go b/support/globalconfig/infrastructure.go
index 65464e3fca9..b380ce912af 100644
--- a/support/globalconfig/infrastructure.go
+++ b/support/globalconfig/infrastructure.go
@@ -29,7 +29,13 @@ func ReconcileInfrastructure(infra *configv1.Infrastructure, hcp *hyperv1.Hosted
apiServerAddress := hcp.Status.ControlPlaneEndpoint.Host
apiServerPort := hcp.Status.ControlPlaneEndpoint.Port
- infra.Spec.PlatformSpec.Type = configv1.PlatformType(platformType)
+ // For MAAS platform, use "None" since OpenShift doesn't support MAAS yet
+ // This allows the infrastructure to be created while maintaining MAAS-specific logic
+ if platformType == hyperv1.MAASPlatform {
+ infra.Spec.PlatformSpec.Type = configv1.NonePlatformType
+ } else {
+ infra.Spec.PlatformSpec.Type = configv1.PlatformType(platformType)
+ }
infra.Status.APIServerInternalURL = fmt.Sprintf("https://%s:%d", apiServerAddress, apiServerPort)
if util.IsPrivateHCP(hcp) {
infra.Status.APIServerInternalURL = fmt.Sprintf("https://api.%s.hypershift.local:%d", hcp.Name, apiServerPort)
@@ -42,11 +48,20 @@ func ReconcileInfrastructure(infra *configv1.Infrastructure, hcp *hyperv1.Hosted
infra.Status.EtcdDiscoveryDomain = BaseDomain(hcp)
infra.Status.InfrastructureName = hcp.Spec.InfraID
infra.Status.ControlPlaneTopology = configv1.ExternalTopologyMode
- infra.Status.Platform = configv1.PlatformType(platformType)
- if infra.Status.PlatformStatus == nil {
- infra.Status.PlatformStatus = &configv1.PlatformStatus{}
+ // For MAAS platform, use "None" in status fields since OpenShift doesn't support MAAS yet
+ if platformType == hyperv1.MAASPlatform {
+ infra.Status.Platform = configv1.NonePlatformType
+ if infra.Status.PlatformStatus == nil {
+ infra.Status.PlatformStatus = &configv1.PlatformStatus{}
+ }
+ infra.Status.PlatformStatus.Type = configv1.NonePlatformType
+ } else {
+ infra.Status.Platform = configv1.PlatformType(platformType)
+ if infra.Status.PlatformStatus == nil {
+ infra.Status.PlatformStatus = &configv1.PlatformStatus{}
+ }
+ infra.Status.PlatformStatus.Type = configv1.PlatformType(platformType)
}
- infra.Status.PlatformStatus.Type = configv1.PlatformType(platformType)
switch hcp.Spec.InfrastructureAvailabilityPolicy {
case hyperv1.HighlyAvailable:
@@ -101,5 +116,10 @@ func ReconcileInfrastructure(infra *configv1.Infrastructure, hcp *hyperv1.Hosted
APIServerInternalIPs: []string{},
IngressIPs: []string{},
}
+ case hyperv1.MAASPlatform:
+ // MAAS platform configuration
+ // Note: OpenShift API doesn't have MAAS platform types yet
+ // The platform type is already set above, which is sufficient for now
+ // When OpenShift adds MAAS support, we can populate the specific fields
}
}
diff --git a/support/images/envvars.go b/support/images/envvars.go
index 88b246f8008..752269b8ae7 100644
--- a/support/images/envvars.go
+++ b/support/images/envvars.go
@@ -11,6 +11,7 @@ const (
KonnectivityEnvVar = "IMAGE_KONNECTIVITY"
OpenStackCAPIProviderEnvVar = "IMAGE_OPENSTACK_CAPI_PROVIDER"
OpenStackResourceControllerEnvVar = "IMAGE_OPENSTACK_RESOURCE_CONTROLLER"
+ MAASCAPIProviderEnvVar = "IMAGE_MAAS_CAPI_PROVIDER"
)
// TagMapping returns a mapping between tags in an image-refs ImageStream
@@ -25,6 +26,7 @@ func TagMapping() map[string]string {
"cluster-api-provider-kubevirt": KubevirtCAPIProviderEnvVar,
"cluster-api-provider-powervs": PowerVSCAPIProviderEnvVar,
"cluster-api-provider-openstack": OpenStackCAPIProviderEnvVar,
+ "cluster-api-provider-maas": MAASCAPIProviderEnvVar,
"openstack-resource-controller": OpenStackResourceControllerEnvVar,
}
}
diff --git a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go
index 2299ffad3c0..cd2c1ede993 100644
--- a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go
+++ b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hostedcluster_types.go
@@ -124,6 +124,10 @@ const (
// a HostedControlPlane.
ClusterAPIOpenStackProviderImage = "hypershift.openshift.io/capi-provider-openstack-image"
+ // ClusterAPIProviderMAASImage overrides the CAPI MAAS provider image to use for
+ // a HostedControlPlane.
+ ClusterAPIProviderMAASImage = "hypershift.openshift.io/capi-provider-maas-image"
+
// OpenStackResourceControllerImage overrides the ORC image to use for a HostedControlPlane.
OpenStackResourceControllerImage = "hypershift.openshift.io/orc-image"
@@ -313,6 +317,11 @@ const (
// If set on both, the one on the NodePool takes precedence. The value can be a number or a percentage value.
MachineHealthCheckMaxUnhealthyAnnotation = "hypershift.openshift.io/machine-health-check-max-unhealthy"
+ // MachineDeploymentProgressDeadlineSecondsAnnotation allows overriding the default machine deployment
+ // progress deadline timeout for nodepools. The annotation can be set in either the HostedCluster or the NodePool.
+ // If set on both, the one on the NodePool takes precedence. The value is a number of seconds (ie. 1800 for 30 minutes)
+ MachineDeploymentProgressDeadlineSecondsAnnotation = "hypershift.openshift.io/machine-deployment-progress-deadline-seconds"
+
// ClusterSizeOverrideAnnotation allows overriding the value of the size label regardless of the number
// of workers associated with the HostedCluster. The value should be the desired size label.
ClusterSizeOverrideAnnotation = "hypershift.openshift.io/cluster-size-override"
@@ -1111,6 +1120,9 @@ const (
// OpenStackPlatform represents OpenStack infrastructure.
OpenStackPlatform PlatformType = "OpenStack"
+
+ // MAASPlatform represents MaaS (Metal as a Service) infrastructure.
+ MAASPlatform PlatformType = "MAAS"
)
// List all PlatformType instances
@@ -1124,6 +1136,7 @@ func PlatformTypes() []PlatformType {
AzurePlatform,
PowerVSPlatform,
OpenStackPlatform,
+ MAASPlatform,
}
}
@@ -1135,8 +1148,8 @@ type PlatformSpec struct {
// +unionDiscriminator
// +kubebuilder:validation:XValidation:rule="self == oldSelf", message="Type is immutable"
// +immutable
- // +openshift:validation:FeatureGateAwareEnum:featureGate="",enum=AWS;Azure;IBMCloud;KubeVirt;Agent;PowerVS;None
- // +openshift:validation:FeatureGateAwareEnum:featureGate=OpenStack,enum=AWS;Azure;IBMCloud;KubeVirt;Agent;PowerVS;None;OpenStack
+ // +openshift:validation:FeatureGateAwareEnum:featureGate="",enum=AWS;Azure;IBMCloud;KubeVirt;Agent;PowerVS;None;MAAS
+ // +openshift:validation:FeatureGateAwareEnum:featureGate=OpenStack,enum=AWS;Azure;IBMCloud;KubeVirt;Agent;PowerVS;None;OpenStack;MAAS
Type PlatformType `json:"type"`
// AWS specifies configuration for clusters running on Amazon Web Services.
@@ -1174,6 +1187,10 @@ type PlatformSpec struct {
// +optional
// +openshift:enable:FeatureGate=OpenStack
OpenStack *OpenStackPlatformSpec `json:"openstack,omitempty"`
+
+ // maas specifies configuration for clusters running on MaaS (Metal as a Service).
+ // +optional
+ MAAS *MAASPlatformSpec `json:"maas,omitempty"`
}
// IBMCloudPlatformSpec defines IBMCloud specific settings for components
diff --git a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/maas.go b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/maas.go
new file mode 100644
index 00000000000..c2368b0f5e5
--- /dev/null
+++ b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/maas.go
@@ -0,0 +1,92 @@
+package v1beta1
+
+// MAASPlatformSpec specifies configuration for clusters running on MaaS (Metal as a Service).
+type MAASPlatformSpec struct {
+ // identityRef is a reference to a secret holding MAAS credentials
+ // to be used when reconciling the hosted cluster.
+ //
+ // +kubebuilder:validation:Required
+ // +required
+ IdentityRef MAASIdentityReference `json:"identityRef"`
+
+ // dnsDomain is the DNS domain for the MAAS cluster.
+ // +optional
+ // +kubebuilder:validation:MaxLength=255
+ DNSDomain string `json:"dnsDomain,omitempty"`
+
+ // zone specifies the MAAS zone where the cluster will be deployed.
+ // If not specified, the cluster will be deployed in any available zone.
+ // +optional
+ // +kubebuilder:validation:MaxLength=255
+ Zone string `json:"zone,omitempty"`
+}
+
+// MAASIdentityReference is a reference to an infrastructure
+// provider identity to be used to provision cluster resources.
+type MAASIdentityReference struct {
+ // Name is the name of a secret in the same namespace as the resource being provisioned.
+ // The secret must contain the following keys:
+ // - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ // - `MAAS_API_KEY`: MAAS API key for authentication
+ //
+ // +kubebuilder:validation:Required
+ // +required
+ Name string `json:"name"`
+}
+
+// MAASNodePoolPlatform specifies the configuration for MaaS platform.
+type MAASNodePoolPlatform struct {
+ // identityRef is a reference to a secret holding MAAS credentials
+ // to be used when reconciling the node pool.
+ // The secret must contain the following keys:
+ // - `MAAS_ENDPOINT`: MAAS API endpoint URL
+ // - `MAAS_API_KEY`: MAAS API key for authentication
+ //
+ // +kubebuilder:validation:Required
+ // +required
+ IdentityRef MAASIdentityReference `json:"identityRef"`
+
+ // machineType specifies the type of MAAS machine to use for the nodes.
+ // This corresponds to the MAAS machine type/tag that will be used for node selection.
+ // +optional
+ // +kubebuilder:validation:MaxLength=255
+ MachineType string `json:"machineType,omitempty"`
+
+ // zone specifies the MAAS zone where the nodes will be deployed.
+ // If not specified, nodes will be deployed in any available zone.
+ // +optional
+ // +kubebuilder:validation:MaxLength=255
+ Zone string `json:"zone,omitempty"`
+
+ // tags specifies additional MAAS tags to apply to the nodes for filtering and organization.
+ // +optional
+ // +kubebuilder:validation:MaxItems=10
+ Tags []string `json:"tags,omitempty"`
+
+ // resourcePool specifies the MAAS resource pool to use for node allocation.
+ // +optional
+ // +kubebuilder:validation:MaxLength=255
+ ResourcePool string `json:"resourcePool,omitempty"`
+
+ // minCpu specifies the minimum CPU count required for the nodes.
+ // +optional
+ // +kubebuilder:validation:Minimum=1
+ MinCPU *int32 `json:"minCpu,omitempty"`
+
+ // minMemory specifies the minimum memory in MB required for the nodes.
+ // +optional
+ // +kubebuilder:validation:Minimum=1024
+ MinMemory *int32 `json:"minMemory,omitempty"`
+
+ // image specifies the MAAS image ID to use for the nodes.
+ // If not specified, a default image will be used based on the release.
+ // +optional
+ // +kubebuilder:validation:MaxLength=255
+ Image string `json:"image,omitempty"`
+
+ // failureDomain specifies the failure domain the machine will be created in.
+ // Must match a key in the FailureDomains map stored on the cluster object.
+ // +optional
+ // +kubebuilder:validation:MaxLength=255
+ FailureDomain string `json:"failureDomain,omitempty"`
+}
diff --git a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/nodepool_conditions.go b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/nodepool_conditions.go
index ef6787b327a..5e0b9df3f7d 100644
--- a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/nodepool_conditions.go
+++ b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/nodepool_conditions.go
@@ -118,6 +118,7 @@ const (
NodePoolValidArchPlatform = "ValidArchPlatform"
NodePoolInvalidArchPlatform = "InvalidArchPlatform"
InvalidKubevirtMachineTemplate = "InvalidKubevirtMachineTemplate"
+ InvalidMAASMachineTemplate = "InvalidMAASMachineTemplate"
InvalidOpenStackMachineTemplate = "InvalidOpenStackMachineTemplate"
CIDRConflictReason = "CIDRConflict"
NodePoolKubeVirtLiveMigratableReason = "KubeVirtNodesNotLiveMigratable"
diff --git a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/nodepool_types.go b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/nodepool_types.go
index 8d3dbcbfdd7..8370c29d04c 100644
--- a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/nodepool_types.go
+++ b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/nodepool_types.go
@@ -428,8 +428,8 @@ type NodePoolPlatform struct {
// +unionDiscriminator
// +kubebuilder:validation:XValidation:rule="self == oldSelf", message="Type is immutable"
// +immutable
- // +openshift:validation:FeatureGateAwareEnum:featureGate="",enum=AWS;Azure;IBMCloud;KubeVirt;Agent;PowerVS;None
- // +openshift:validation:FeatureGateAwareEnum:featureGate=OpenStack,enum=AWS;Azure;IBMCloud;KubeVirt;Agent;PowerVS;None;OpenStack
+ // +openshift:validation:FeatureGateAwareEnum:featureGate="",enum=AWS;Azure;IBMCloud;KubeVirt;Agent;PowerVS;None;MAAS
+ // +openshift:validation:FeatureGateAwareEnum:featureGate=OpenStack,enum=AWS;Azure;IBMCloud;KubeVirt;Agent;PowerVS;None;OpenStack;MAAS
Type PlatformType `json:"type"`
// AWS specifies the configuration used when operating on AWS.
@@ -461,6 +461,10 @@ type NodePoolPlatform struct {
// +optional
// +openshift:enable:FeatureGate=OpenStack
OpenStack *OpenStackNodePoolPlatform `json:"openstack,omitempty"`
+
+ // maas specifies the configuration used when using MaaS platform.
+ // +optional
+ MAAS *MAASNodePoolPlatform `json:"maas,omitempty"`
}
// We define our own condition type since metav1.Condition has validation
diff --git a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go
index 4fd8653510c..a97c9f75439 100644
--- a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go
+++ b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go
@@ -2469,6 +2469,70 @@ func (in *LoadBalancerPublishingStrategy) DeepCopy() *LoadBalancerPublishingStra
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MAASIdentityReference) DeepCopyInto(out *MAASIdentityReference) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MAASIdentityReference.
+func (in *MAASIdentityReference) DeepCopy() *MAASIdentityReference {
+ if in == nil {
+ return nil
+ }
+ out := new(MAASIdentityReference)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MAASNodePoolPlatform) DeepCopyInto(out *MAASNodePoolPlatform) {
+ *out = *in
+ out.IdentityRef = in.IdentityRef
+ if in.Tags != nil {
+ in, out := &in.Tags, &out.Tags
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
+ if in.MinCPU != nil {
+ in, out := &in.MinCPU, &out.MinCPU
+ *out = new(int32)
+ **out = **in
+ }
+ if in.MinMemory != nil {
+ in, out := &in.MinMemory, &out.MinMemory
+ *out = new(int32)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MAASNodePoolPlatform.
+func (in *MAASNodePoolPlatform) DeepCopy() *MAASNodePoolPlatform {
+ if in == nil {
+ return nil
+ }
+ out := new(MAASNodePoolPlatform)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MAASPlatformSpec) DeepCopyInto(out *MAASPlatformSpec) {
+ *out = *in
+ out.IdentityRef = in.IdentityRef
+ out.DNSDomain = in.DNSDomain
+ out.Zone = in.Zone
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MAASPlatformSpec.
+func (in *MAASPlatformSpec) DeepCopy() *MAASPlatformSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MAASPlatformSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MachineNetworkEntry) DeepCopyInto(out *MachineNetworkEntry) {
*out = *in
@@ -2750,6 +2814,11 @@ func (in *NodePoolPlatform) DeepCopyInto(out *NodePoolPlatform) {
*out = new(OpenStackNodePoolPlatform)
(*in).DeepCopyInto(*out)
}
+ if in.MAAS != nil {
+ in, out := &in.MAAS, &out.MAAS
+ *out = new(MAASNodePoolPlatform)
+ (*in).DeepCopyInto(*out)
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodePoolPlatform.
@@ -3089,6 +3158,11 @@ func (in *PlatformSpec) DeepCopyInto(out *PlatformSpec) {
*out = new(OpenStackPlatformSpec)
(*in).DeepCopyInto(*out)
}
+ if in.MAAS != nil {
+ in, out := &in.MAAS, &out.MAAS
+ *out = new(MAASPlatformSpec)
+ **out = **in
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlatformSpec.
diff --git a/vendor/github.com/spectrocloud/cluster-api-provider-maas/LICENSE b/vendor/github.com/spectrocloud/cluster-api-provider-maas/LICENSE
new file mode 100644
index 00000000000..261eeb9e9f8
--- /dev/null
+++ b/vendor/github.com/spectrocloud/cluster-api-provider-maas/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/condition_consts.go b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/condition_consts.go
new file mode 100644
index 00000000000..5746e5aa18c
--- /dev/null
+++ b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/condition_consts.go
@@ -0,0 +1,86 @@
+/*
+Copyright 2020 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 v1beta1
+
+import clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
+
+// Conditions and condition Reasons for the MAAS Machine object
+
+const (
+ // MachineDeployedCondition documents the status of the deployment of a machine
+
+ MachineDeployedCondition clusterv1.ConditionType = "MachineDeployed"
+
+ // WaitingForClusterInfrastructureReason (Severity=Info) documents a MachineMachine waiting for the cluster
+ // infrastructure to be ready before starting to deploy the machine that provides the MachineMachine
+ // infrastructure.
+ WaitingForClusterInfrastructureReason = "WaitingForClusterInfrastructure"
+
+ // WaitingForBootstrapDataReason (Severity=Info) documents a MachineMachine waiting for the bootstrap
+ // script to be ready before starting to create the container that provides the MachineMachine infrastructure.
+ WaitingForBootstrapDataReason = "WaitingForBootstrapData"
+
+ // MachineDeployingReason
+ MachineDeployingReason = "MachineDeploying"
+
+ // MachineTerminatedReason
+ MachineTerminatedReason = "MachineTerminatedReason"
+
+ // MachineDeployingReason
+ MachinePoweredOffReason = "MachinePoweredOff"
+
+ // MachineNotFoundReason used when the machine couldn't be retrieved.
+ MachineNotFoundReason = "MachineNotFound"
+
+ // MachineDeployFailedReason (Severity=Warning) documents a MachineMachine controller detecting
+ // an error while deploying the MaaS machine that provides the MachineMachine infrastructure; those kind of
+ // errors are usually transient and failed provisioning are automatically re-tried by the controller.
+ MachineDeployFailedReason = "MachineDeployFailed"
+
+ // MachineDeployStartedReason (Severity=Info) documents a MachineMachine controller started deploying
+ MachineDeployStartedReason = "MachineDeployStartedReason"
+)
+
+const (
+ // Only applicable to control plane machines. DNSAttachedCondition will report true when a control plane is successfully registered with an DNS
+ // When set to false, severity can be an Error if the subnet is not found or unavailable in the instance's AZ
+ DNSAttachedCondition clusterv1.ConditionType = "DNSAttached"
+
+ DNSDetachPending = "DNSDetachPending"
+ DNSAttachPending = "DNSAttachPending"
+)
+
+// Cluster Conditions
+
+const (
+ // DNSReadyCondition documents the availability of the container that implements the cluster DNS.
+ DNSReadyCondition clusterv1.ConditionType = "LoadBalancerReady"
+
+ // LoadBalancerProvisioningFailedReason (Severity=Warning) documents a MAASCluster controller detecting
+ // dns reconcile failure will be retried
+ DNSFailedReason = "LoadBalancerFailed"
+
+ WaitForDNSNameReason = "WaitForDNSName"
+)
+
+const (
+ // APIServerAvailableCondition documents whether API server is reachable
+ APIServerAvailableCondition clusterv1.ConditionType = "APIServerAvailable"
+
+ // APIServerNotReadyReason api server isn't responding
+ APIServerNotReadyReason = "APIServerNotReady"
+)
diff --git a/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/conversion.go b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/conversion.go
new file mode 100644
index 00000000000..53b675027c2
--- /dev/null
+++ b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/conversion.go
@@ -0,0 +1,29 @@
+/*
+
+
+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 v1beta1
+
+func (*MaasCluster) Hub() {}
+
+func (*MaasClusterList) Hub() {}
+
+func (*MaasMachine) Hub() {}
+
+func (*MaasMachineList) Hub() {}
+
+func (*MaasMachineTemplate) Hub() {}
+
+func (*MaasMachineTemplateList) Hub() {}
diff --git a/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/groupversion_info.go b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/groupversion_info.go
new file mode 100644
index 00000000000..dcfd5baf863
--- /dev/null
+++ b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/groupversion_info.go
@@ -0,0 +1,36 @@
+/*
+
+
+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 v1beta1 contains API Schema definitions for the infrastructure v1beta1 API group
+// +kubebuilder:object:generate=true
+// +groupName=infrastructure.cluster.x-k8s.io
+package v1beta1
+
+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: "v1beta1"}
+
+ // 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/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/maascluster_types.go b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/maascluster_types.go
new file mode 100644
index 00000000000..b3ba3417ecf
--- /dev/null
+++ b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/maascluster_types.go
@@ -0,0 +1,120 @@
+/*
+
+
+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 v1beta1
+
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
+)
+
+const (
+ // ClusterFinalizer allows MaasClusterReconciler to clean up resources associated with MaasCluster before
+ // removing it from the apiserver.
+ ClusterFinalizer = "maascluster.infrastructure.cluster.x-k8s.io"
+)
+
+// MaasClusterSpec defines the desired state of MaasCluster
+type MaasClusterSpec struct {
+ // DNSDomain configures the MaaS domain to create the cluster on (e.g maas)
+ // +kubebuilder:validation:MinLength=1
+ DNSDomain string `json:"dnsDomain"`
+
+ // ControlPlaneEndpoint represents the endpoint used to communicate with the control plane.
+ // +optional
+ ControlPlaneEndpoint APIEndpoint `json:"controlPlaneEndpoint"`
+
+ // FailureDomains are not usually defined on the spec.
+ // but useful for MaaS since we can limit the domains to these
+ // +optional
+ FailureDomains []string `json:"failureDomains,omitempty"`
+}
+
+// MaasClusterStatus defines the observed state of MaasCluster
+type MaasClusterStatus struct {
+ // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
+ // Important: Run "make" to regenerate code after modifying this file
+ // Ready denotes that the maas cluster (infrastructure) is ready.
+ // +kubebuilder:default=false
+ Ready bool `json:"ready"`
+
+ // Network represents the network
+ Network Network `json:"network,omitempty"`
+
+ // FailureDomains don't mean much in CAPMAAS since it's all local, but we can see how the rest of cluster API
+ // will use this if we populate it.
+ FailureDomains clusterv1.FailureDomains `json:"failureDomains,omitempty"`
+
+ // Conditions defines current service state of the MaasCluster.
+ // +optional
+ Conditions clusterv1.Conditions `json:"conditions,omitempty"`
+}
+
+// Network encapsulates the Cluster Network
+type Network struct {
+ // DNSName is the Kubernetes api server name
+ DNSName string `json:"dnsName,omitempty"`
+}
+
+// APIEndpoint represents a reachable Kubernetes API endpoint.
+type APIEndpoint struct {
+
+ // Host is the hostname on which the API server is serving.
+ Host string `json:"host"`
+
+ // Port is the port on which the API server is serving.
+ Port int `json:"port"`
+}
+
+// IsZero returns true if both host and port are zero values.
+func (in APIEndpoint) IsZero() bool {
+ return in.Host == "" && in.Port == 0
+}
+
+// +kubebuilder:resource:path=maasclusters,scope=Namespaced,categories=cluster-api
+//+kubebuilder:object:root=true
+//+kubebuilder:subresource:status
+//+kubebuilder:storageversion
+
+// MaasCluster is the Schema for the maasclusters API
+type MaasCluster struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec MaasClusterSpec `json:"spec,omitempty"`
+ Status MaasClusterStatus `json:"status,omitempty"`
+}
+
+func (in *MaasCluster) GetConditions() clusterv1.Conditions {
+ return in.Status.Conditions
+}
+
+func (in *MaasCluster) SetConditions(conditions clusterv1.Conditions) {
+ in.Status.Conditions = conditions
+}
+
+//+kubebuilder:object:root=true
+
+// MaasClusterList contains a list of MaasCluster
+type MaasClusterList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []MaasCluster `json:"items"`
+}
+
+func init() {
+ SchemeBuilder.Register(&MaasCluster{}, &MaasClusterList{})
+}
diff --git a/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/maascluster_webhook.go b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/maascluster_webhook.go
new file mode 100644
index 00000000000..2eb69cd5820
--- /dev/null
+++ b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/maascluster_webhook.go
@@ -0,0 +1,76 @@
+/*
+
+
+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 v1beta1
+
+import (
+ "fmt"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/runtime"
+ ctrl "sigs.k8s.io/controller-runtime"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/webhook"
+)
+
+// log is for logging in this package.
+var maasclusterlog = logf.Log.WithName("maascluster-resource")
+
+func (r *MaasCluster) SetupWebhookWithManager(mgr ctrl.Manager) error {
+ return ctrl.NewWebhookManagedBy(mgr).
+ For(r).
+ Complete()
+}
+
+//+kubebuilder:webhook:path=/mutate-infrastructure-cluster-x-k8s-io-v1beta1-maascluster,mutating=true,failurePolicy=fail,groups=infrastructure.cluster.x-k8s.io,resources=maasclusters,verbs=create;update,versions=v1beta1,name=mmaascluster.kb.io,sideEffects=None,admissionReviewVersions=v1beta1;v1
+//+kubebuilder:webhook:verbs=create;update,path=/validate-infrastructure-cluster-x-k8s-io-v1beta1-maascluster,mutating=false,failurePolicy=fail,groups=infrastructure.cluster.x-k8s.io,resources=maasclusters,versions=v1beta1,name=vmaascluster.kb.io,sideEffects=None,admissionReviewVersions=v1beta1;v1
+
+var (
+ _ webhook.Defaulter = &MaasCluster{}
+ _ webhook.Validator = &MaasCluster{}
+)
+
+// Default implements webhook.Defaulter so a webhook will be registered for the type
+func (r *MaasCluster) Default() {
+ maasclusterlog.Info("default", "name", r.Name)
+}
+
+// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
+func (r *MaasCluster) ValidateCreate() (admission.Warnings, error) {
+ maasclusterlog.Info("validate create", "name", r.Name)
+ return nil, nil
+}
+
+// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
+func (r *MaasCluster) ValidateUpdate(old runtime.Object) (admission.Warnings, error) {
+ maasclusterlog.Info("validate update", "name", r.Name)
+ oldC, ok := old.(*MaasCluster)
+ if !ok {
+ return nil, apierrors.NewBadRequest(fmt.Sprintf("expected a MaasCluster but got a %T", old))
+ }
+
+ if r.Spec.DNSDomain != oldC.Spec.DNSDomain {
+ return nil, apierrors.NewBadRequest("changing cluster DNS Domain not allowed")
+ }
+ return nil, nil
+}
+
+// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
+func (r *MaasCluster) ValidateDelete() (admission.Warnings, error) {
+ maasclusterlog.Info("validate delete", "name", r.Name)
+ return nil, nil
+}
diff --git a/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/maasmachine_types.go b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/maasmachine_types.go
new file mode 100644
index 00000000000..1ee3fae0498
--- /dev/null
+++ b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/maasmachine_types.go
@@ -0,0 +1,137 @@
+/*
+
+
+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 v1beta1
+
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
+ "sigs.k8s.io/cluster-api/errors"
+)
+
+const (
+ // MachineFinalizer allows MaasMachineReconciler to clean up resources associated with MaasMachine before
+ // removing it from the apiserver.
+ MachineFinalizer = "maasmachine.infrastructure.cluster.x-k8s.io"
+)
+
+// MaasMachineSpec defines the desired state of MaasMachine
+type MaasMachineSpec struct {
+
+ // FailureDomain is the failure domain the machine will be created in.
+ // Must match a key in the FailureDomains map stored on the cluster object.
+ // +optional
+ FailureDomain *string `json:"failureDomain,omitempty"`
+
+ // SystemID will be the MaaS machine ID
+ // +optional
+ SystemID *string `json:"systemID,omitempty"`
+
+ // ProviderID will be the name in ProviderID format (maas:///system_id)
+ // +optional
+ ProviderID *string `json:"providerID,omitempty"`
+
+ // ResourcePool will be the MAAS Machine resourcepool
+ // +optional
+ ResourcePool *string `json:"resourcePool,omitempty"`
+
+ // MinCPU minimum number of CPUs
+ // +kubebuilder:validation:Minimum=0
+ MinCPU *int `json:"minCPU"`
+
+ // MinMemoryInMB minimum memory in MB
+ // +kubebuilder:validation:Minimum=0
+ MinMemoryInMB *int `json:"minMemory"`
+
+ // Tags for placement
+ // +optional
+ Tags []string `json:"tags,omitempty"`
+
+ // Image will be the MaaS image id
+ // +kubebuilder:validation:MinLength=1
+ Image string `json:"image"`
+}
+
+// MaasMachineStatus defines the observed state of MaasMachine
+type MaasMachineStatus struct {
+
+ // Ready denotes that the machine (maas container) is ready
+ // +kubebuilder:default=false
+ Ready bool `json:"ready"`
+
+ // MachineState is the state of this MAAS machine.
+ MachineState *MachineState `json:"machineState,omitempty"`
+
+ // MachinePowered is if the machine is "Powered" on
+ MachinePowered bool `json:"machinePowered,omitempty"`
+
+ // Hostname is the actual MaaS hostname
+ Hostname *string `json:"hostname,omitempty"`
+
+ // DNSAttached specifies whether the DNS record contains the IP of this machine
+ DNSAttached bool `json:"dnsAttached,omitempty"`
+
+ // Addresses contains the associated addresses for the maas machine.
+ Addresses []clusterv1.MachineAddress `json:"addresses,omitempty"`
+
+ // Conditions defines current service state of the MaasMachine.
+ Conditions clusterv1.Conditions `json:"conditions,omitempty"`
+
+ // FailureReason will be set in the event that there is a terminal problem
+ // reconciling the Machine and will contain a succinct value suitable
+ // for machine interpretation.
+ FailureReason *errors.MachineStatusError `json:"failureReason,omitempty"`
+
+ // FailureMessage will be set in the event that there is a terminal problem
+ // reconciling the Machine and will contain a more verbose string suitable
+ // for logging and human consumption.
+ FailureMessage *string `json:"failureMessage,omitempty"`
+}
+
+// +kubebuilder:resource:path=maasmachines,scope=Namespaced,categories=cluster-api
+//+kubebuilder:object:root=true
+//+kubebuilder:subresource:status
+//+kubebuilder:storageversion
+
+// MaasMachine is the Schema for the maasmachines API
+type MaasMachine struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec MaasMachineSpec `json:"spec,omitempty"`
+ Status MaasMachineStatus `json:"status,omitempty"`
+}
+
+func (c *MaasMachine) GetConditions() clusterv1.Conditions {
+ return c.Status.Conditions
+}
+
+func (c *MaasMachine) SetConditions(conditions clusterv1.Conditions) {
+ c.Status.Conditions = conditions
+}
+
+//+kubebuilder:object:root=true
+
+// MaasMachineList contains a list of MaasMachine
+type MaasMachineList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []MaasMachine `json:"items"`
+}
+
+func init() {
+ SchemeBuilder.Register(&MaasMachine{}, &MaasMachineList{})
+}
diff --git a/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/maasmachine_webhook.go b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/maasmachine_webhook.go
new file mode 100644
index 00000000000..29bc36111e5
--- /dev/null
+++ b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/maasmachine_webhook.go
@@ -0,0 +1,81 @@
+/*
+
+
+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 v1beta1
+
+import (
+ "fmt"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/runtime"
+ ctrl "sigs.k8s.io/controller-runtime"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/webhook"
+)
+
+// log is for logging in this package.
+var maasmachinelog = logf.Log.WithName("maasmachine-resource")
+
+func (r *MaasMachine) SetupWebhookWithManager(mgr ctrl.Manager) error {
+ return ctrl.NewWebhookManagedBy(mgr).
+ For(r).
+ Complete()
+}
+
+//+kubebuilder:webhook:path=/mutate-infrastructure-cluster-x-k8s-io-v1beta1-maasmachine,mutating=true,failurePolicy=fail,groups=infrastructure.cluster.x-k8s.io,resources=maasmachines,verbs=create;update,versions=v1beta1,name=mmaasmachine.kb.io,sideEffects=None,admissionReviewVersions=v1beta1;v1
+//+kubebuilder:webhook:verbs=create;update,path=/validate-infrastructure-cluster-x-k8s-io-v1beta1-maasmachine,mutating=false,failurePolicy=fail,groups=infrastructure.cluster.x-k8s.io,resources=maasmachines,versions=v1beta1,name=vmaasmachine.kb.io,sideEffects=None,admissionReviewVersions=v1beta1;v1
+
+var (
+ _ webhook.Defaulter = &MaasMachine{}
+ _ webhook.Validator = &MaasMachine{}
+)
+
+// Default implements webhook.Defaulter so a webhook will be registered for the type
+func (r *MaasMachine) Default() {
+ maasmachinelog.Info("default", "name", r.Name)
+}
+
+// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
+func (r *MaasMachine) ValidateCreate() (admission.Warnings, error) {
+ maasmachinelog.Info("validate create", "name", r.Name)
+ return nil, nil
+}
+
+// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
+func (r *MaasMachine) ValidateDelete() (admission.Warnings, error) {
+ maasmachinelog.Info("validate delete", "name", r.Name)
+ return nil, nil
+}
+
+// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
+func (r *MaasMachine) ValidateUpdate(old runtime.Object) (admission.Warnings, error) {
+ maasmachinelog.Info("validate update", "name", r.Name)
+ oldM := old.(*MaasMachine)
+
+ if r.Spec.Image != oldM.Spec.Image {
+ return nil, apierrors.NewBadRequest(fmt.Sprintf("maas machine image change is not allowed, old=%s, new=%s", oldM.Spec.Image, r.Spec.Image))
+ }
+
+ if *r.Spec.MinCPU != *oldM.Spec.MinCPU {
+ return nil, apierrors.NewBadRequest(fmt.Sprintf("maas machine min cpu count change is not allowed, old=%d, new=%d", oldM.Spec.MinCPU, r.Spec.MinCPU))
+ }
+
+ if *r.Spec.MinMemoryInMB != *oldM.Spec.MinMemoryInMB {
+ return nil, apierrors.NewBadRequest(fmt.Sprintf("maas machine min memory change is not allowed, old=%d MB, new=%d MB", oldM.Spec.MinMemoryInMB, r.Spec.MinMemoryInMB))
+ }
+ return nil, nil
+}
diff --git a/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/maasmachinetemplate_types.go b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/maasmachinetemplate_types.go
new file mode 100644
index 00000000000..cd5469a7000
--- /dev/null
+++ b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/maasmachinetemplate_types.go
@@ -0,0 +1,58 @@
+/*
+
+
+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 v1beta1
+
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// MaasMachineTemplateSpec defines the desired state of MaasMachineTemplate
+type MaasMachineTemplateSpec struct {
+ Template MaasMachineTemplateResource `json:"template"`
+}
+
+// MaasMachineTemplateResource describes the data needed to create a MaasMachine from a template
+type MaasMachineTemplateResource struct {
+ // Spec is the specification of the desired behavior of the machine.
+ Spec MaasMachineSpec `json:"spec"`
+}
+
+// +kubebuilder:resource:path=maasmachinetemplates,scope=Namespaced,categories=cluster-api
+//+kubebuilder:object:root=true
+//+kubebuilder:subresource:status
+//+kubebuilder:storageversion
+
+// MaasMachineTemplate is the Schema for the maasmachinetemplates API
+type MaasMachineTemplate struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec MaasMachineTemplateSpec `json:"spec,omitempty"`
+}
+
+//+kubebuilder:object:root=true
+
+// MaasMachineTemplateList contains a list of MaasMachineTemplate
+type MaasMachineTemplateList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []MaasMachineTemplate `json:"items"`
+}
+
+func init() {
+ SchemeBuilder.Register(&MaasMachineTemplate{}, &MaasMachineTemplateList{})
+}
diff --git a/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/maasmachinetemplate_webhook.go b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/maasmachinetemplate_webhook.go
new file mode 100644
index 00000000000..d6876062ced
--- /dev/null
+++ b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/maasmachinetemplate_webhook.go
@@ -0,0 +1,81 @@
+/*
+
+
+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 v1beta1
+
+import (
+ "fmt"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/runtime"
+ ctrl "sigs.k8s.io/controller-runtime"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/webhook"
+)
+
+// log is for logging in this package.
+var maasmachinetemplatelog = logf.Log.WithName("maasmachinetemplate-resource")
+
+func (r *MaasMachineTemplate) SetupWebhookWithManager(mgr ctrl.Manager) error {
+ return ctrl.NewWebhookManagedBy(mgr).
+ For(r).
+ Complete()
+}
+
+//+kubebuilder:webhook:path=/mutate-infrastructure-cluster-x-k8s-io-v1beta1-maasmachinetemplate,mutating=true,failurePolicy=fail,groups=infrastructure.cluster.x-k8s.io,resources=maasmachinetemplates,verbs=create;update,versions=v1beta1,name=mmaasmachinetemplate.kb.io,sideEffects=None,admissionReviewVersions=v1beta1;v1
+//+kubebuilder:webhook:verbs=create;update,path=/validate-infrastructure-cluster-x-k8s-io-v1beta1-maasmachinetemplate,mutating=false,failurePolicy=fail,groups=infrastructure.cluster.x-k8s.io,resources=maasmachinetemplates,versions=v1beta1,name=vmaasmachinetemplate.kb.io,sideEffects=None,admissionReviewVersions=v1beta1;v1
+
+var (
+ _ webhook.Defaulter = &MaasMachineTemplate{}
+ _ webhook.Validator = &MaasMachineTemplate{}
+)
+
+// Default implements webhook.Defaulter so a webhook will be registered for the type
+func (r *MaasMachineTemplate) Default() {
+ maasmachinetemplatelog.Info("default", "name", r.Name)
+}
+
+// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
+func (r *MaasMachineTemplate) ValidateCreate() (admission.Warnings, error) {
+ maasmachinetemplatelog.Info("validate create", "name", r.Name)
+ return nil, nil
+}
+
+// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
+func (r *MaasMachineTemplate) ValidateUpdate(old runtime.Object) (admission.Warnings, error) {
+ maasmachinetemplatelog.Info("validate update", "name", r.Name)
+ oldM := old.(*MaasMachineTemplate)
+
+ if r.Spec.Template.Spec.Image != oldM.Spec.Template.Spec.Image {
+ return nil, apierrors.NewBadRequest(fmt.Sprintf("maas machine template image change is not allowed, old=%s, new=%s", oldM.Spec.Template.Spec.Image, r.Spec.Template.Spec.Image))
+ }
+
+ if *r.Spec.Template.Spec.MinCPU != *oldM.Spec.Template.Spec.MinCPU {
+ return nil, apierrors.NewBadRequest(fmt.Sprintf("maas machine template min cpu count change is not allowed, old=%d, new=%d", oldM.Spec.Template.Spec.MinCPU, r.Spec.Template.Spec.MinCPU))
+ }
+
+ if *r.Spec.Template.Spec.MinMemoryInMB != *oldM.Spec.Template.Spec.MinMemoryInMB {
+ return nil, apierrors.NewBadRequest(fmt.Sprintf("maas machine template min memory change is not allowed, old=%d MB, new=%d MB", oldM.Spec.Template.Spec.MinMemoryInMB, r.Spec.Template.Spec.MinMemoryInMB))
+ }
+ return nil, nil
+}
+
+// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
+func (r *MaasMachineTemplate) ValidateDelete() (admission.Warnings, error) {
+ maasmachinetemplatelog.Info("validate delete", "name", r.Name)
+ return nil, nil
+}
diff --git a/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/types.go b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/types.go
new file mode 100644
index 00000000000..fb849010a3e
--- /dev/null
+++ b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/types.go
@@ -0,0 +1,94 @@
+package v1beta1
+
+import (
+ "k8s.io/apimachinery/pkg/util/sets"
+ clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
+)
+
+// MachineState describes the state of an MAAS Machine.
+type MachineState string
+
+// List of all possible states: https://github.com/maas/maas/blob/master/src/maasserver/enum.py#L108
+
+var (
+ // MachineStateAllocated is the string representing an instance in a ready (commissioned) state
+ MachineStateAllocated = MachineState("Allocated")
+
+ //MachineStateDeploying is the string representing an instance in a deploying state
+ MachineStateDeploying = MachineState("Deploying")
+
+ // MachineStateDeployed is the string representing an instance in a pending state
+ MachineStateDeployed = MachineState("Deployed")
+
+ // MachineStateReady is the string representing an instance in a ready (commissioned) state
+ MachineStateReady = MachineState("Ready")
+
+ // MachineStateDiskErasing is the string representing an instance which is releasing (disk)
+ MachineStateDiskErasing = MachineState("Disk erasing")
+
+ // MachineStateDiskErasing is the string representing an instance which is releasing
+ MachineStateReleasing = MachineState("Releasing")
+
+ // MachineStateNew is the string representing an instance which is not yet commissioned
+ MachineStateNew = MachineState("New")
+
+ //// MachineStateShuttingDown is the string representing an instance shutting down
+ //MachineStateShuttingDown = MachineState("shutting-down")
+ //
+ //// MachineStateTerminated is the string representing an instance that has been terminated
+ //MachineStateTerminated = MachineState("terminated")
+ //
+ //// MachineStateStopping is the string representing an instance
+ //// that is in the process of being stopped and can be restarted
+ //MachineStateStopping = MachineState("stopping")
+
+ // MachineStateStopped is the string representing an instance
+ // that has been stopped and can be restarted
+ //MachineStateStopped = MachineState("stopped")
+
+ // MachineRunningStates defines the set of states in which an MaaS instance is
+ // running or going to be running soon
+ MachineRunningStates = sets.NewString(
+ string(MachineStateDeploying),
+ string(MachineStateDeployed),
+ )
+
+ // MachineOperationalStates defines the set of states in which an MaaS instance is
+ // or can return to running, and supports all MaaS operations
+ MachineOperationalStates = MachineRunningStates.Union(
+ sets.NewString(
+ string(MachineStateAllocated),
+ ),
+ )
+
+ // MachineKnownStates represents all known MaaS instance states
+ MachineKnownStates = MachineOperationalStates.Union(
+ sets.NewString(
+ string(MachineStateDiskErasing),
+ string(MachineStateReleasing),
+ string(MachineStateReady),
+ string(MachineStateNew),
+ //string(MachineStateTerminated),
+ ),
+ )
+)
+
+// Instance describes an MAAS Machine.
+type Machine struct {
+ ID string
+
+ // Hostname is the hostname
+ Hostname string
+
+ // The current state of the machine.
+ State MachineState
+
+ // The current state of the machine.
+ Powered bool
+
+ // The AZ of the machine
+ AvailabilityZone string
+
+ // Addresses contains the MAAS Machine associated addresses.
+ Addresses []clusterv1.MachineAddress
+}
diff --git a/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/zz_generated.deepcopy.go b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/zz_generated.deepcopy.go
new file mode 100644
index 00000000000..696f37c6f04
--- /dev/null
+++ b/vendor/github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1/zz_generated.deepcopy.go
@@ -0,0 +1,434 @@
+//go:build !ignore_autogenerated
+// +build !ignore_autogenerated
+
+/*
+
+
+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 v1beta1
+
+import (
+ "k8s.io/apimachinery/pkg/runtime"
+ apiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1"
+ "sigs.k8s.io/cluster-api/errors"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *APIEndpoint) DeepCopyInto(out *APIEndpoint) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIEndpoint.
+func (in *APIEndpoint) DeepCopy() *APIEndpoint {
+ if in == nil {
+ return nil
+ }
+ out := new(APIEndpoint)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MaasCluster) DeepCopyInto(out *MaasCluster) {
+ *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 MaasCluster.
+func (in *MaasCluster) DeepCopy() *MaasCluster {
+ if in == nil {
+ return nil
+ }
+ out := new(MaasCluster)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *MaasCluster) 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 *MaasClusterList) DeepCopyInto(out *MaasClusterList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ListMeta.DeepCopyInto(&out.ListMeta)
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]MaasCluster, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MaasClusterList.
+func (in *MaasClusterList) DeepCopy() *MaasClusterList {
+ if in == nil {
+ return nil
+ }
+ out := new(MaasClusterList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *MaasClusterList) 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 *MaasClusterSpec) DeepCopyInto(out *MaasClusterSpec) {
+ *out = *in
+ out.ControlPlaneEndpoint = in.ControlPlaneEndpoint
+ if in.FailureDomains != nil {
+ in, out := &in.FailureDomains, &out.FailureDomains
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MaasClusterSpec.
+func (in *MaasClusterSpec) DeepCopy() *MaasClusterSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MaasClusterSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MaasClusterStatus) DeepCopyInto(out *MaasClusterStatus) {
+ *out = *in
+ out.Network = in.Network
+ if in.FailureDomains != nil {
+ in, out := &in.FailureDomains, &out.FailureDomains
+ *out = make(apiv1beta1.FailureDomains, len(*in))
+ for key, val := range *in {
+ (*out)[key] = *val.DeepCopy()
+ }
+ }
+ 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])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MaasClusterStatus.
+func (in *MaasClusterStatus) DeepCopy() *MaasClusterStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(MaasClusterStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MaasMachine) DeepCopyInto(out *MaasMachine) {
+ *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 MaasMachine.
+func (in *MaasMachine) DeepCopy() *MaasMachine {
+ if in == nil {
+ return nil
+ }
+ out := new(MaasMachine)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *MaasMachine) 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 *MaasMachineList) DeepCopyInto(out *MaasMachineList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ListMeta.DeepCopyInto(&out.ListMeta)
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]MaasMachine, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MaasMachineList.
+func (in *MaasMachineList) DeepCopy() *MaasMachineList {
+ if in == nil {
+ return nil
+ }
+ out := new(MaasMachineList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *MaasMachineList) 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 *MaasMachineSpec) DeepCopyInto(out *MaasMachineSpec) {
+ *out = *in
+ if in.FailureDomain != nil {
+ in, out := &in.FailureDomain, &out.FailureDomain
+ *out = new(string)
+ **out = **in
+ }
+ if in.SystemID != nil {
+ in, out := &in.SystemID, &out.SystemID
+ *out = new(string)
+ **out = **in
+ }
+ if in.ProviderID != nil {
+ in, out := &in.ProviderID, &out.ProviderID
+ *out = new(string)
+ **out = **in
+ }
+ if in.ResourcePool != nil {
+ in, out := &in.ResourcePool, &out.ResourcePool
+ *out = new(string)
+ **out = **in
+ }
+ if in.MinCPU != nil {
+ in, out := &in.MinCPU, &out.MinCPU
+ *out = new(int)
+ **out = **in
+ }
+ if in.MinMemoryInMB != nil {
+ in, out := &in.MinMemoryInMB, &out.MinMemoryInMB
+ *out = new(int)
+ **out = **in
+ }
+ if in.Tags != nil {
+ in, out := &in.Tags, &out.Tags
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MaasMachineSpec.
+func (in *MaasMachineSpec) DeepCopy() *MaasMachineSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MaasMachineSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MaasMachineStatus) DeepCopyInto(out *MaasMachineStatus) {
+ *out = *in
+ if in.MachineState != nil {
+ in, out := &in.MachineState, &out.MachineState
+ *out = new(MachineState)
+ **out = **in
+ }
+ if in.Hostname != nil {
+ in, out := &in.Hostname, &out.Hostname
+ *out = new(string)
+ **out = **in
+ }
+ if in.Addresses != nil {
+ in, out := &in.Addresses, &out.Addresses
+ *out = make([]apiv1beta1.MachineAddress, len(*in))
+ copy(*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.FailureReason != nil {
+ in, out := &in.FailureReason, &out.FailureReason
+ *out = new(errors.MachineStatusError)
+ **out = **in
+ }
+ if in.FailureMessage != nil {
+ in, out := &in.FailureMessage, &out.FailureMessage
+ *out = new(string)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MaasMachineStatus.
+func (in *MaasMachineStatus) DeepCopy() *MaasMachineStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(MaasMachineStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MaasMachineTemplate) DeepCopyInto(out *MaasMachineTemplate) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ in.Spec.DeepCopyInto(&out.Spec)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MaasMachineTemplate.
+func (in *MaasMachineTemplate) DeepCopy() *MaasMachineTemplate {
+ if in == nil {
+ return nil
+ }
+ out := new(MaasMachineTemplate)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *MaasMachineTemplate) 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 *MaasMachineTemplateList) DeepCopyInto(out *MaasMachineTemplateList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ListMeta.DeepCopyInto(&out.ListMeta)
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]MaasMachineTemplate, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MaasMachineTemplateList.
+func (in *MaasMachineTemplateList) DeepCopy() *MaasMachineTemplateList {
+ if in == nil {
+ return nil
+ }
+ out := new(MaasMachineTemplateList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *MaasMachineTemplateList) 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 *MaasMachineTemplateResource) DeepCopyInto(out *MaasMachineTemplateResource) {
+ *out = *in
+ in.Spec.DeepCopyInto(&out.Spec)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MaasMachineTemplateResource.
+func (in *MaasMachineTemplateResource) DeepCopy() *MaasMachineTemplateResource {
+ if in == nil {
+ return nil
+ }
+ out := new(MaasMachineTemplateResource)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *MaasMachineTemplateSpec) DeepCopyInto(out *MaasMachineTemplateSpec) {
+ *out = *in
+ in.Template.DeepCopyInto(&out.Template)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MaasMachineTemplateSpec.
+func (in *MaasMachineTemplateSpec) DeepCopy() *MaasMachineTemplateSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(MaasMachineTemplateSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Machine) DeepCopyInto(out *Machine) {
+ *out = *in
+ if in.Addresses != nil {
+ in, out := &in.Addresses, &out.Addresses
+ *out = make([]apiv1beta1.MachineAddress, len(*in))
+ copy(*out, *in)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Machine.
+func (in *Machine) DeepCopy() *Machine {
+ if in == nil {
+ return nil
+ }
+ out := new(Machine)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Network) DeepCopyInto(out *Network) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Network.
+func (in *Network) DeepCopy() *Network {
+ if in == nil {
+ return nil
+ }
+ out := new(Network)
+ in.DeepCopyInto(out)
+ return out
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index fd422a2626e..a9b11209ab7 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -979,6 +979,11 @@ github.com/sirupsen/logrus
# github.com/soheilhy/cmux v0.1.5
## explicit; go 1.11
github.com/soheilhy/cmux
+# github.com/spectrocloud/cluster-api-provider-maas v0.5.1-0.20250512112717-769064ca22e9
+## explicit; go 1.23.0
+github.com/spectrocloud/cluster-api-provider-maas/api/v1beta1
+# github.com/spectrocloud/maas-client-go v0.0.1-beta1.0.20230830132549-2f7491722359
+## explicit; go 1.15
# github.com/spf13/cobra v1.8.1
## explicit; go 1.15
github.com/spf13/cobra
@@ -2121,6 +2126,8 @@ k8s.io/client-go/util/keyutil
k8s.io/client-go/util/retry
k8s.io/client-go/util/watchlist
k8s.io/client-go/util/workqueue
+# k8s.io/cluster-bootstrap v0.31.3
+## explicit; go 1.22.0
# k8s.io/component-base v0.32.2
## explicit; go 1.23.0
k8s.io/component-base/cli
@@ -2444,7 +2451,7 @@ sigs.k8s.io/kustomize/kyaml/yaml/walk
# sigs.k8s.io/secrets-store-csi-driver v1.4.8
## explicit; go 1.21
sigs.k8s.io/secrets-store-csi-driver/apis/v1
-# sigs.k8s.io/structured-merge-diff/v4 v4.4.2
+# sigs.k8s.io/structured-merge-diff/v4 v4.4.3
## explicit; go 1.13
sigs.k8s.io/structured-merge-diff/v4/fieldpath
sigs.k8s.io/structured-merge-diff/v4/merge
diff --git a/vendor/sigs.k8s.io/structured-merge-diff/v4/merge/update.go b/vendor/sigs.k8s.io/structured-merge-diff/v4/merge/update.go
index 34ab2d6fb4f..455818ff858 100644
--- a/vendor/sigs.k8s.io/structured-merge-diff/v4/merge/update.go
+++ b/vendor/sigs.k8s.io/structured-merge-diff/v4/merge/update.go
@@ -33,6 +33,9 @@ type UpdaterBuilder struct {
Converter Converter
IgnoreFilter map[fieldpath.APIVersion]fieldpath.Filter
+ // IgnoredFields provides a set of fields to ignore for each
+ IgnoredFields map[fieldpath.APIVersion]*fieldpath.Set
+
// Stop comparing the new object with old object after applying.
// This was initially used to avoid spurious etcd update, but
// since that's vastly inefficient, we've come-up with a better
@@ -46,6 +49,7 @@ func (u *UpdaterBuilder) BuildUpdater() *Updater {
return &Updater{
Converter: u.Converter,
IgnoreFilter: u.IgnoreFilter,
+ IgnoredFields: u.IgnoredFields,
returnInputOnNoop: u.ReturnInputOnNoop,
}
}
@@ -56,6 +60,9 @@ type Updater struct {
// Deprecated: This will eventually become private.
Converter Converter
+ // Deprecated: This will eventually become private.
+ IgnoredFields map[fieldpath.APIVersion]*fieldpath.Set
+
// Deprecated: This will eventually become private.
IgnoreFilter map[fieldpath.APIVersion]fieldpath.Filter
@@ -70,8 +77,19 @@ func (s *Updater) update(oldObject, newObject *typed.TypedValue, version fieldpa
return nil, nil, fmt.Errorf("failed to compare objects: %v", err)
}
- versions := map[fieldpath.APIVersion]*typed.Comparison{
- version: compare.FilterFields(s.IgnoreFilter[version]),
+ var versions map[fieldpath.APIVersion]*typed.Comparison
+
+ if s.IgnoredFields != nil && s.IgnoreFilter != nil {
+ return nil, nil, fmt.Errorf("IgnoreFilter and IgnoreFilter may not both be set")
+ }
+ if s.IgnoredFields != nil {
+ versions = map[fieldpath.APIVersion]*typed.Comparison{
+ version: compare.ExcludeFields(s.IgnoredFields[version]),
+ }
+ } else {
+ versions = map[fieldpath.APIVersion]*typed.Comparison{
+ version: compare.FilterFields(s.IgnoreFilter[version]),
+ }
}
for manager, managerSet := range managers {
@@ -101,7 +119,12 @@ func (s *Updater) update(oldObject, newObject *typed.TypedValue, version fieldpa
if err != nil {
return nil, nil, fmt.Errorf("failed to compare objects: %v", err)
}
- versions[managerSet.APIVersion()] = compare.FilterFields(s.IgnoreFilter[managerSet.APIVersion()])
+
+ if s.IgnoredFields != nil {
+ versions[managerSet.APIVersion()] = compare.ExcludeFields(s.IgnoredFields[managerSet.APIVersion()])
+ } else {
+ versions[managerSet.APIVersion()] = compare.FilterFields(s.IgnoreFilter[managerSet.APIVersion()])
+ }
}
conflictSet := managerSet.Set().Intersection(compare.Modified.Union(compare.Added))
@@ -154,7 +177,16 @@ func (s *Updater) Update(liveObject, newObject *typed.TypedValue, version fieldp
managers[manager] = fieldpath.NewVersionedSet(fieldpath.NewSet(), version, false)
}
set := managers[manager].Set().Difference(compare.Removed).Union(compare.Modified).Union(compare.Added)
- ignoreFilter := s.IgnoreFilter[version]
+
+ if s.IgnoredFields != nil && s.IgnoreFilter != nil {
+ return nil, nil, fmt.Errorf("IgnoreFilter and IgnoreFilter may not both be set")
+ }
+ var ignoreFilter fieldpath.Filter
+ if s.IgnoredFields != nil {
+ ignoreFilter = fieldpath.NewExcludeSetFilter(s.IgnoredFields[version])
+ } else {
+ ignoreFilter = s.IgnoreFilter[version]
+ }
if ignoreFilter != nil {
set = ignoreFilter.Filter(set)
}
@@ -189,7 +221,15 @@ func (s *Updater) Apply(liveObject, configObject *typed.TypedValue, version fiel
return nil, fieldpath.ManagedFields{}, fmt.Errorf("failed to get field set: %v", err)
}
- ignoreFilter := s.IgnoreFilter[version]
+ if s.IgnoredFields != nil && s.IgnoreFilter != nil {
+ return nil, nil, fmt.Errorf("IgnoreFilter and IgnoreFilter may not both be set")
+ }
+ var ignoreFilter fieldpath.Filter
+ if s.IgnoredFields != nil {
+ ignoreFilter = fieldpath.NewExcludeSetFilter(s.IgnoredFields[version])
+ } else {
+ ignoreFilter = s.IgnoreFilter[version]
+ }
if ignoreFilter != nil {
set = ignoreFilter.Filter(set)
}