diff --git a/api/hypershift/v1beta1/azure.go b/api/hypershift/v1beta1/azure.go index c99523ceedfc..0c130111e1b8 100644 --- a/api/hypershift/v1beta1/azure.go +++ b/api/hypershift/v1beta1/azure.go @@ -653,7 +653,7 @@ const ( // AzurePrivateType specifies the type of private connectivity mechanism used for the Azure // hosted cluster's API server. This acts as the discriminator for the AzurePrivateSpec union. // -// +kubebuilder:validation:Enum=PrivateLink +// +kubebuilder:validation:Enum=PrivateLink;Swift type AzurePrivateType string const ( @@ -661,23 +661,30 @@ const ( // In this mode, the operator creates a Private Link Service backed by the management cluster's // internal load balancer, and a Private Endpoint in the guest VNet for private API server access. AzurePrivateTypePrivateLink AzurePrivateType = "PrivateLink" + + // AzurePrivateTypeSwift specifies private connectivity using Azure Swift pod networking. + // In this mode, Azure Swift assigns a private IP from the customer VNet directly + // to the hosted cluster's router pods, providing private API server access without a + // separate Private Link Service. This is used by ARO HCP managed clusters. + AzurePrivateTypeSwift AzurePrivateType = "Swift" ) // AzurePrivateSpec configures private connectivity to an Azure hosted cluster's API server. // It is a discriminated union keyed on the type field, which selects the private connectivity -// mechanism. Currently only PrivateLink is supported; additional mechanisms (e.g., Swift) may -// be added in the future. +// mechanism. // -// +kubebuilder:validation:XValidation:rule="self.type != 'PrivateLink' ? !has(self.privateLink) : true",message="privateLink is forbidden when type is not PrivateLink" +// +kubebuilder:validation:XValidation:rule="!has(oldSelf.type) || self.type == oldSelf.type",message="type is immutable" +// +kubebuilder:validation:XValidation:rule="self.type == 'PrivateLink' ? has(self.privateLink) : !has(self.privateLink)",message="privateLink is required when type is PrivateLink, and forbidden otherwise" +// +kubebuilder:validation:XValidation:rule="self.type == 'Swift' ? has(self.swift) : !has(self.swift)",message="swift is required when type is Swift, and forbidden otherwise" // +union type AzurePrivateSpec struct { // type specifies the private connectivity mechanism used for the hosted cluster's API server. // "PrivateLink" selects Azure Private Link Service for private API server access. + // "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. // This field is immutable once set. // // +unionDiscriminator // +required - // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="type is immutable" Type AzurePrivateType `json:"type,omitempty"` // privateLink configures Azure Private Link Service for private API server access. @@ -686,6 +693,15 @@ type AzurePrivateSpec struct { // +optional // +unionMember PrivateLink AzurePrivateLinkSpec `json:"privateLink,omitzero"` + + // swift configures Azure Swift pod networking for private API server access. + // Swift networking requires the management cluster to be pre-configured with + // Azure Swift support; this is not provisioned by HyperShift automatically. + // This field is required when type is "Swift" and must not be set otherwise. + // + // +optional + // +unionMember + Swift AzureSwiftSpec `json:"swift,omitzero"` } // AzurePrivateLinkSpec configures Azure Private Link Service connectivity. @@ -716,6 +732,26 @@ type AzurePrivateLinkSpec struct { AdditionalAllowedSubscriptions []AzureSubscriptionID `json:"additionalAllowedSubscriptions,omitempty"` } +// AzureSwiftSpec configures Azure Swift pod networking for private API server access. +// Swift assigns a private IP from the customer VNet directly to the hosted cluster's +// router pods, providing private connectivity without a separate Private Link Service. +// +// +kubebuilder:validation:XValidation:rule="self.podNetworkInstance == oldSelf.podNetworkInstance",message="podNetworkInstance is immutable" +type AzureSwiftSpec struct { + // podNetworkInstance is the name of a PodNetworkInstance custom resource in the + // hosted control plane namespace. This resource configures Azure Swift pod networking + // for private connectivity to the hosted cluster's router pods. + // The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + // alphanumeric characters or hyphens, must start and end with an alphanumeric character. + // This field is immutable once set. + // + // +required + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=63 + // +kubebuilder:validation:XValidation:rule="self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$')",message="podNetworkInstance must be a valid DNS label: lowercase alphanumeric characters or hyphens, must start and end with an alphanumeric character" + PodNetworkInstance string `json:"podNetworkInstance,omitempty"` +} + // ControlPlaneManagedIdentities contains the managed identities on the HCP control plane needing to authenticate with // Azure's API. type ControlPlaneManagedIdentities struct { diff --git a/api/hypershift/v1beta1/zz_generated.deepcopy.go b/api/hypershift/v1beta1/zz_generated.deepcopy.go index 558be0746f8f..80f9062b9ee0 100644 --- a/api/hypershift/v1beta1/zz_generated.deepcopy.go +++ b/api/hypershift/v1beta1/zz_generated.deepcopy.go @@ -857,6 +857,7 @@ func (in *AzurePrivateLinkSpec) DeepCopy() *AzurePrivateLinkSpec { func (in *AzurePrivateSpec) DeepCopyInto(out *AzurePrivateSpec) { *out = *in in.PrivateLink.DeepCopyInto(&out.PrivateLink) + out.Swift = in.Swift } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzurePrivateSpec. @@ -886,6 +887,21 @@ func (in *AzureResourceManagedIdentities) DeepCopy() *AzureResourceManagedIdenti return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureSwiftSpec) DeepCopyInto(out *AzureSwiftSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureSwiftSpec. +func (in *AzureSwiftSpec) DeepCopy() *AzureSwiftSpec { + if in == nil { + return nil + } + out := new(AzureSwiftSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AzureVMImage) DeepCopyInto(out *AzureVMImage) { *out = *in 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 44e56e67fd53..14902a5fddf3 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 @@ -5047,24 +5047,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- 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 636b4970874f..7a0e2481e33b 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 @@ -5174,24 +5174,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml index 70f2a9b3530e..9907f86cac94 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml @@ -5038,24 +5038,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- 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 f5ba9fa38267..50cb6f4a85fb 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 @@ -5058,24 +5058,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- 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 cc29eaa6e790..05d38511ba88 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 @@ -5371,24 +5371,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- 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 3665db71b154..5d0c725ce29e 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 @@ -5511,24 +5511,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml index 3019a14066a9..1c70daa127e8 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml @@ -5492,24 +5492,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml index 687a2f7d807a..e6a377855333 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/GCPPlatform.yaml @@ -5038,24 +5038,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HCPEtcdBackup.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HCPEtcdBackup.yaml index 63e6335ed762..916d8a7708eb 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HCPEtcdBackup.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HCPEtcdBackup.yaml @@ -5103,24 +5103,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml index 5a2781e38557..471d759bacdb 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedclusters.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml @@ -5060,24 +5060,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- 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 512eb0c50882..747bf83d3a7c 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 @@ -5056,24 +5056,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- 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 06a178dccd48..8a9cc38c6b28 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 @@ -5114,24 +5114,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- 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 079a6c48dcd5..562fba91eb44 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 @@ -5038,24 +5038,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- 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 9a49d67f9eda..585b4ed58254 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 @@ -4925,24 +4925,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- 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 04be6dd42570..9b3e0f48dea3 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 @@ -5054,24 +5054,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml index 4181eaa306c3..05a9407f4595 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml @@ -4916,24 +4916,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- 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 e6615973f4b7..d8cd7aa0d372 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 @@ -4936,24 +4936,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- 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 5fbcb4772f82..6ec8a4609e2b 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 @@ -5249,24 +5249,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- 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 84fef65195b8..c08138168ee1 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 @@ -5389,24 +5389,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml index 5a85ccca1e67..d4b5329ea0fa 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml @@ -5370,24 +5370,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml index c859a25b2c1d..8da049404855 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml @@ -4916,24 +4916,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HCPEtcdBackup.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HCPEtcdBackup.yaml index 1d9fa278fff6..10789422c97e 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HCPEtcdBackup.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HCPEtcdBackup.yaml @@ -4981,24 +4981,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- diff --git a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml index d1aea3cc45ae..b7a3000b5f71 100644 --- a/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml +++ b/api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml @@ -4938,24 +4938,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- 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 4594af147b5a..3422180e0b5a 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 @@ -4934,24 +4934,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- 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 d252df9539c9..5c85c3ddf346 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 @@ -4992,24 +4992,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- 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 c5516bc62f51..dc850fb39e81 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 @@ -4916,24 +4916,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- diff --git a/client/applyconfiguration/hypershift/v1beta1/azureprivatespec.go b/client/applyconfiguration/hypershift/v1beta1/azureprivatespec.go index 3fe2eae5bc01..5d65112e28d7 100644 --- a/client/applyconfiguration/hypershift/v1beta1/azureprivatespec.go +++ b/client/applyconfiguration/hypershift/v1beta1/azureprivatespec.go @@ -26,6 +26,7 @@ import ( type AzurePrivateSpecApplyConfiguration struct { Type *hypershiftv1beta1.AzurePrivateType `json:"type,omitempty"` PrivateLink *AzurePrivateLinkSpecApplyConfiguration `json:"privateLink,omitempty"` + Swift *AzureSwiftSpecApplyConfiguration `json:"swift,omitempty"` } // AzurePrivateSpecApplyConfiguration constructs a declarative configuration of the AzurePrivateSpec type for use with @@ -49,3 +50,11 @@ func (b *AzurePrivateSpecApplyConfiguration) WithPrivateLink(value *AzurePrivate b.PrivateLink = value return b } + +// WithSwift sets the Swift field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Swift field is set to the value of the last call. +func (b *AzurePrivateSpecApplyConfiguration) WithSwift(value *AzureSwiftSpecApplyConfiguration) *AzurePrivateSpecApplyConfiguration { + b.Swift = value + return b +} diff --git a/client/applyconfiguration/hypershift/v1beta1/azureswiftspec.go b/client/applyconfiguration/hypershift/v1beta1/azureswiftspec.go new file mode 100644 index 000000000000..d328964e02bb --- /dev/null +++ b/client/applyconfiguration/hypershift/v1beta1/azureswiftspec.go @@ -0,0 +1,38 @@ +/* + + +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 applyconfiguration-gen. DO NOT EDIT. + +package v1beta1 + +// AzureSwiftSpecApplyConfiguration represents a declarative configuration of the AzureSwiftSpec type for use +// with apply. +type AzureSwiftSpecApplyConfiguration struct { + PodNetworkInstance *string `json:"podNetworkInstance,omitempty"` +} + +// AzureSwiftSpecApplyConfiguration constructs a declarative configuration of the AzureSwiftSpec type for use with +// apply. +func AzureSwiftSpec() *AzureSwiftSpecApplyConfiguration { + return &AzureSwiftSpecApplyConfiguration{} +} + +// WithPodNetworkInstance sets the PodNetworkInstance field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the PodNetworkInstance field is set to the value of the last call. +func (b *AzureSwiftSpecApplyConfiguration) WithPodNetworkInstance(value string) *AzureSwiftSpecApplyConfiguration { + b.PodNetworkInstance = &value + return b +} diff --git a/client/applyconfiguration/utils.go b/client/applyconfiguration/utils.go index b89bca7ed49c..7b1658d828e9 100644 --- a/client/applyconfiguration/utils.go +++ b/client/applyconfiguration/utils.go @@ -133,6 +133,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &hypershiftv1beta1.AzurePrivateSpecApplyConfiguration{} case v1beta1.SchemeGroupVersion.WithKind("AzureResourceManagedIdentities"): return &hypershiftv1beta1.AzureResourceManagedIdentitiesApplyConfiguration{} + case v1beta1.SchemeGroupVersion.WithKind("AzureSwiftSpec"): + return &hypershiftv1beta1.AzureSwiftSpecApplyConfiguration{} case v1beta1.SchemeGroupVersion.WithKind("AzureVMImage"): return &hypershiftv1beta1.AzureVMImageApplyConfiguration{} case v1beta1.SchemeGroupVersion.WithKind("AzureWorkloadIdentities"): diff --git a/cmd/install/assets/crds/hypershift-operator/tests/hostedclusters.hypershift.openshift.io/stable.hostedclusters.azure.testsuite.yaml b/cmd/install/assets/crds/hypershift-operator/tests/hostedclusters.hypershift.openshift.io/stable.hostedclusters.azure.testsuite.yaml index ed9896396e96..b47bb2199e4f 100644 --- a/cmd/install/assets/crds/hypershift-operator/tests/hostedclusters.hypershift.openshift.io/stable.hostedclusters.azure.testsuite.yaml +++ b/cmd/install/assets/crds/hypershift-operator/tests/hostedclusters.hypershift.openshift.io/stable.hostedclusters.azure.testsuite.yaml @@ -548,7 +548,7 @@ tests: route: {} # --- Azure PrivateLink CEL validation --- - - name: When Azure PrivateLink type is set without privateLink config it should pass + - name: When Azure PrivateLink type is set without privateLink config it should fail initial: | apiVersion: hypershift.openshift.io/v1beta1 kind: HostedCluster @@ -613,6 +613,7 @@ tests: servicePublishingStrategy: type: Route route: {} + expectedError: "privateLink is required when type is PrivateLink, and forbidden otherwise" - name: When Azure PrivateLink type is set with privateLink config it should pass initial: | @@ -703,6 +704,8 @@ tests: topology: Private private: type: PrivateLink + privateLink: + natSubnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/nat-subnet" azureAuthenticationConfig: azureAuthenticationConfigType: WorkloadIdentities workloadIdentities: @@ -769,6 +772,8 @@ tests: topology: Private private: type: PrivateLink + privateLink: + natSubnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/nat-subnet" azureAuthenticationConfig: azureAuthenticationConfigType: WorkloadIdentities workloadIdentities: @@ -813,3 +818,1019 @@ tests: type: Route route: {} expectedError: "workloadIdentities.controlPlaneOperator is required when Private Link is configured with WorkloadIdentities authentication" + # --- Azure Swift private networking validation --- + - name: When Private.Type is Swift with valid Swift spec it should pass + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + topology: PublicAndPrivate + private: + type: Swift + swift: + podNetworkInstance: "test-pni" + azureAuthenticationConfig: + azureAuthenticationConfigType: WorkloadIdentities + workloadIdentities: + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + file: + clientID: "12345678-1234-5678-9012-123456789012" + disk: + clientID: "12345678-1234-5678-9012-123456789012" + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + network: + clientID: "12345678-1234-5678-9012-123456789012" + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + + - name: When Private.Type is Swift but privateLink is also set it should fail + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + topology: PublicAndPrivate + private: + type: Swift + swift: + podNetworkInstance: "test-pni" + privateLink: + natSubnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/nat-subnet" + azureAuthenticationConfig: + azureAuthenticationConfigType: WorkloadIdentities + workloadIdentities: + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + file: + clientID: "12345678-1234-5678-9012-123456789012" + disk: + clientID: "12345678-1234-5678-9012-123456789012" + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + network: + clientID: "12345678-1234-5678-9012-123456789012" + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + expectedError: "privateLink is required when type is PrivateLink, and forbidden otherwise" + + - name: When Private.Type is Swift but swift spec is missing it should fail + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + topology: PublicAndPrivate + private: + type: Swift + azureAuthenticationConfig: + azureAuthenticationConfigType: WorkloadIdentities + workloadIdentities: + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + file: + clientID: "12345678-1234-5678-9012-123456789012" + disk: + clientID: "12345678-1234-5678-9012-123456789012" + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + network: + clientID: "12345678-1234-5678-9012-123456789012" + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + expectedError: "swift is required when type is Swift, and forbidden otherwise" + + - name: When Private.Type is PrivateLink but swift is also set it should fail + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + topology: Private + private: + type: PrivateLink + privateLink: + natSubnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/nat-subnet" + swift: + podNetworkInstance: "test-pni" + azureAuthenticationConfig: + azureAuthenticationConfigType: WorkloadIdentities + workloadIdentities: + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + file: + clientID: "12345678-1234-5678-9012-123456789012" + disk: + clientID: "12345678-1234-5678-9012-123456789012" + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + network: + clientID: "12345678-1234-5678-9012-123456789012" + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + expectedError: "swift is required when type is Swift, and forbidden otherwise" + + - name: When Topology is Private with Private.Type Swift it should pass + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + topology: Private + private: + type: Swift + swift: + podNetworkInstance: "test-pni" + azureAuthenticationConfig: + azureAuthenticationConfigType: WorkloadIdentities + workloadIdentities: + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + file: + clientID: "12345678-1234-5678-9012-123456789012" + disk: + clientID: "12345678-1234-5678-9012-123456789012" + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + network: + clientID: "12345678-1234-5678-9012-123456789012" + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + + onUpdate: + # --- Azure Swift private networking immutability --- + - name: When Private.Type changes from PrivateLink to Swift it should fail + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + topology: Private + private: + type: PrivateLink + privateLink: + natSubnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/nat-subnet" + azureAuthenticationConfig: + azureAuthenticationConfigType: WorkloadIdentities + workloadIdentities: + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + file: + clientID: "12345678-1234-5678-9012-123456789012" + disk: + clientID: "12345678-1234-5678-9012-123456789012" + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + network: + clientID: "12345678-1234-5678-9012-123456789012" + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + updated: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + topology: Private + private: + type: Swift + swift: + podNetworkInstance: "test-pni" + azureAuthenticationConfig: + azureAuthenticationConfigType: WorkloadIdentities + workloadIdentities: + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + file: + clientID: "12345678-1234-5678-9012-123456789012" + disk: + clientID: "12345678-1234-5678-9012-123456789012" + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + network: + clientID: "12345678-1234-5678-9012-123456789012" + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + expectedError: "type is immutable" + + - name: When Swift.PodNetworkInstance changes it should fail + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + topology: PublicAndPrivate + private: + type: Swift + swift: + podNetworkInstance: "pni-old" + azureAuthenticationConfig: + azureAuthenticationConfigType: WorkloadIdentities + workloadIdentities: + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + file: + clientID: "12345678-1234-5678-9012-123456789012" + disk: + clientID: "12345678-1234-5678-9012-123456789012" + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + network: + clientID: "12345678-1234-5678-9012-123456789012" + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + updated: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + topology: PublicAndPrivate + private: + type: Swift + swift: + podNetworkInstance: "pni-new" + azureAuthenticationConfig: + azureAuthenticationConfigType: WorkloadIdentities + workloadIdentities: + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + file: + clientID: "12345678-1234-5678-9012-123456789012" + disk: + clientID: "12345678-1234-5678-9012-123456789012" + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + network: + clientID: "12345678-1234-5678-9012-123456789012" + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + expectedError: "podNetworkInstance is immutable" + + - name: When Topology changes from PublicAndPrivate to Private it should pass + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + topology: PublicAndPrivate + private: + type: Swift + swift: + podNetworkInstance: "test-pni" + azureAuthenticationConfig: + azureAuthenticationConfigType: WorkloadIdentities + workloadIdentities: + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + file: + clientID: "12345678-1234-5678-9012-123456789012" + disk: + clientID: "12345678-1234-5678-9012-123456789012" + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + network: + clientID: "12345678-1234-5678-9012-123456789012" + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + updated: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + topology: Private + private: + type: Swift + swift: + podNetworkInstance: "test-pni" + azureAuthenticationConfig: + azureAuthenticationConfigType: WorkloadIdentities + workloadIdentities: + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + file: + clientID: "12345678-1234-5678-9012-123456789012" + disk: + clientID: "12345678-1234-5678-9012-123456789012" + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + network: + clientID: "12345678-1234-5678-9012-123456789012" + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + + - name: When Topology changes from Private to PublicAndPrivate it should pass + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + topology: Private + private: + type: Swift + swift: + podNetworkInstance: "test-pni" + azureAuthenticationConfig: + azureAuthenticationConfigType: WorkloadIdentities + workloadIdentities: + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + file: + clientID: "12345678-1234-5678-9012-123456789012" + disk: + clientID: "12345678-1234-5678-9012-123456789012" + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + network: + clientID: "12345678-1234-5678-9012-123456789012" + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + updated: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + topology: PublicAndPrivate + private: + type: Swift + swift: + podNetworkInstance: "test-pni" + azureAuthenticationConfig: + azureAuthenticationConfigType: WorkloadIdentities + workloadIdentities: + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + file: + clientID: "12345678-1234-5678-9012-123456789012" + disk: + clientID: "12345678-1234-5678-9012-123456789012" + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + network: + clientID: "12345678-1234-5678-9012-123456789012" + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + + - name: When Topology changes from Private to Public it should fail + initial: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + topology: Private + private: + type: Swift + swift: + podNetworkInstance: "test-pni" + azureAuthenticationConfig: + azureAuthenticationConfigType: WorkloadIdentities + workloadIdentities: + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + file: + clientID: "12345678-1234-5678-9012-123456789012" + disk: + clientID: "12345678-1234-5678-9012-123456789012" + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + network: + clientID: "12345678-1234-5678-9012-123456789012" + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + updated: | + apiVersion: hypershift.openshift.io/v1beta1 + kind: HostedCluster + spec: + dns: + baseDomain: example.com + platform: + type: Azure + azure: + location: eastus + resourceGroupName: test-rg + vnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet" + subnetID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/virtualNetworks/test-vnet/subnets/test-subnet" + subscriptionID: "12345678-1234-5678-9012-123456789012" + securityGroupID: "/subscriptions/12345678-1234-5678-9012-123456789012/resourceGroups/test-rg/providers/Microsoft.Network/networkSecurityGroups/test-nsg" + tenantID: "87654321-4321-8765-2109-876543210987" + topology: Public + azureAuthenticationConfig: + azureAuthenticationConfigType: WorkloadIdentities + workloadIdentities: + imageRegistry: + clientID: "12345678-1234-5678-9012-123456789012" + ingress: + clientID: "12345678-1234-5678-9012-123456789012" + file: + clientID: "12345678-1234-5678-9012-123456789012" + disk: + clientID: "12345678-1234-5678-9012-123456789012" + nodePoolManagement: + clientID: "12345678-1234-5678-9012-123456789012" + cloudProvider: + clientID: "12345678-1234-5678-9012-123456789012" + network: + clientID: "12345678-1234-5678-9012-123456789012" + controlPlaneOperator: + clientID: "12345678-1234-5678-9012-123456789012" + pullSecret: + name: secret + release: + image: quay.io/openshift-release-dev/ocp-release:4.15.11-x86_64 + secretEncryption: + aescbc: + activeKey: + name: key + type: aescbc + services: + - service: APIServer + servicePublishingStrategy: + type: Route + route: {} + - service: OAuthServer + servicePublishingStrategy: + type: Route + route: {} + - service: Konnectivity + servicePublishingStrategy: + type: Route + route: {} + - service: Ignition + servicePublishingStrategy: + type: Route + route: {} + expectedError: "transitions between Public and non-Public topology are not supported" diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml index 87eef962d99d..e2278f17ce1b 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-CustomNoUpgrade.crd.yaml @@ -5976,24 +5976,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml index 35463dc73c2f..3016e9611ff8 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-Default.crd.yaml @@ -5540,24 +5540,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml index 1f1c2e804183..b12bcdfd6c47 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedclusters-Hypershift-TechPreviewNoUpgrade.crd.yaml @@ -5887,24 +5887,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml index 67a307c95f3a..aa97073c3fa0 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml @@ -5856,24 +5856,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml index 7207fcca0821..4f923112afbc 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml @@ -5418,24 +5418,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- diff --git a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yaml b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yaml index 42063effc660..8b5e987200c2 100644 --- a/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yaml +++ b/cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yaml @@ -5767,24 +5767,58 @@ spec: (e.g., /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet}) rule: self.matches('^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Network/virtualNetworks/[^/]+/subnets/[^/]+$') type: object + swift: + description: |- + swift configures Azure Swift pod networking for private API server access. + Swift networking requires the management cluster to be pre-configured with + Azure Swift support; this is not provisioned by HyperShift automatically. + This field is required when type is "Swift" and must not be set otherwise. + properties: + podNetworkInstance: + description: |- + podNetworkInstance is the name of a PodNetworkInstance custom resource in the + hosted control plane namespace. This resource configures Azure Swift pod networking + for private connectivity to the hosted cluster's router pods. + The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + alphanumeric characters or hyphens, must start and end with an alphanumeric character. + This field is immutable once set. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: 'podNetworkInstance must be a valid DNS + label: lowercase alphanumeric characters or hyphens, + must start and end with an alphanumeric character' + rule: self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + required: + - podNetworkInstance + type: object + x-kubernetes-validations: + - message: podNetworkInstance is immutable + rule: self.podNetworkInstance == oldSelf.podNetworkInstance type: description: |- type specifies the private connectivity mechanism used for the hosted cluster's API server. "PrivateLink" selects Azure Private Link Service for private API server access. + "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set. enum: - PrivateLink + - Swift type: string - x-kubernetes-validations: - - message: type is immutable - rule: self == oldSelf required: - type type: object x-kubernetes-validations: - - message: privateLink is forbidden when type is not PrivateLink - rule: 'self.type != ''PrivateLink'' ? !has(self.privateLink) - : true' + - message: type is immutable + rule: '!has(oldSelf.type) || self.type == oldSelf.type' + - message: privateLink is required when type is PrivateLink, + and forbidden otherwise + rule: 'self.type == ''PrivateLink'' ? has(self.privateLink) + : !has(self.privateLink)' + - message: swift is required when type is Swift, and forbidden + otherwise + rule: 'self.type == ''Swift'' ? has(self.swift) : !has(self.swift)' resourceGroup: default: default description: |- diff --git a/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go b/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go index 2223c878193b..2c50ff2fa48c 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go +++ b/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go @@ -1022,7 +1022,7 @@ func (r *HostedControlPlaneReconciler) validateConfigAndClusterCapabilities(ctx } } - if hcp.Spec.Platform.Type == hyperv1.AzurePlatform && hyperazureutil.IsAroHCP() { + if hcp.Spec.Platform.Type == hyperv1.AzurePlatform && hyperazureutil.IsAroHCPByHCP(hcp) { if err := r.verifyResourceGroupLocationsMatch(ctx, hcp); err != nil { return err } @@ -2934,7 +2934,7 @@ func (r *HostedControlPlaneReconciler) validateAzureKMSConfig(ctx context.Contex } azureKmsSpec := hcp.Spec.SecretEncryption.KMS.Azure - if hyperazureutil.IsAroHCP() { + if hyperazureutil.IsAroHCPByHCP(hcp) { key := hcp.Namespace + kmsAzureCredentials // We need to only store the Azure credentials once and reuse them after that. diff --git a/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller_test.go b/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller_test.go index a5936e9c0454..9aab37fdc81f 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller_test.go +++ b/control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller_test.go @@ -1062,6 +1062,14 @@ func TestControlPlaneComponents(t *testing.T) { hyperv1.SwiftPodNetworkInstanceAnnotation: "swift-network-instance", }, mutateHCP: func(hcp *hyperv1.HostedControlPlane) { + // Configure Swift API fields for ARO-HCP + hcp.Spec.Platform.Azure.Private = hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "swift-network-instance", + }, + } + hcp.Spec.Platform.Azure.Topology = hyperv1.AzureTopologyPublicAndPrivate // Configure Azure KMS for ARO-HCP hcp.Spec.Platform.Azure.Cloud = "AzurePublicCloud" hcp.Spec.SecretEncryption = &hyperv1.SecretEncryptionSpec{ diff --git a/control-plane-operator/controllers/hostedcontrolplane/infra/infra.go b/control-plane-operator/controllers/hostedcontrolplane/infra/infra.go index 8d057cf7bd10..98f317cf6a71 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/infra/infra.go +++ b/control-plane-operator/controllers/hostedcontrolplane/infra/infra.go @@ -15,7 +15,6 @@ import ( "github.com/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/oauth" routerutil "github.com/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/v2/router/util" sharedingress "github.com/openshift/hypershift/hypershift-operator/controllers/sharedingress" - hyperazureutil "github.com/openshift/hypershift/support/azureutil" "github.com/openshift/hypershift/support/config" "github.com/openshift/hypershift/support/events" "github.com/openshift/hypershift/support/upsert" @@ -452,9 +451,9 @@ func (r *Reconciler) reconcileHCPRouterServices(ctx context.Context, hcp *hyperv return nil } - // ARO HCP doesn't need LB services; Swift handles connectivity. - // Only reconcile a ClusterIP private router service. - if hyperazureutil.IsAroHCP() { + // ARO HCP doesn't need LB services; shared ingress or Swift handles + // connectivity. Only reconcile a ClusterIP private router service. + if util.UseSwiftNetworkingHCP(hcp) || util.UseSharedIngressHCP(hcp) { if _, err := util.DeleteIfNeeded(ctx, r.Client, pubSvc); err != nil { return fmt.Errorf("failed to delete public router service: %w", err) } @@ -525,7 +524,7 @@ func (r *Reconciler) reconcileAPIServerServiceStatus(ctx context.Context, hcp *h return "", 0, "", errors.New("APIServer service strategy not specified") } - if sharedingress.UseSharedIngress() || (hcp.Spec.Platform.Type == hyperv1.IBMCloudPlatform && serviceStrategy.Type == hyperv1.Route) { + if util.UseSharedIngressHCP(hcp) || util.UseSwiftNetworkingHCP(hcp) || (hcp.Spec.Platform.Type == hyperv1.IBMCloudPlatform && serviceStrategy.Type == hyperv1.Route) { return sharedingress.KasRouteHostname(hcp), sharedingress.ExternalDNSLBPort, "", nil } @@ -682,15 +681,15 @@ func (r *Reconciler) reconcileClusterIPServiceStatus(ctx context.Context, svc *c } func (r *Reconciler) reconcileInternalRouterServiceStatus(ctx context.Context, hcp *hyperv1.HostedControlPlane) (host string, needed bool, message string, err error) { - // ARO is always private but there's no router service. Connection goes through swift. - if !util.IsPrivateHCP(hcp) || hyperazureutil.IsAroHCP() || hcp.Spec.Platform.Type == hyperv1.IBMCloudPlatform { + // Skip when not private, or when shared ingress / Swift handles connectivity, or IBM Cloud. + if !util.IsPrivateHCP(hcp) || util.UseSwiftNetworkingHCP(hcp) || util.UseSharedIngressHCP(hcp) || hcp.Spec.Platform.Type == hyperv1.IBMCloudPlatform { return } return r.reconcileRouterServiceStatus(ctx, manifests.PrivateRouterService(hcp.Namespace), events.NewMessageCollector(ctx, r.Client)) } func (r *Reconciler) reconcileExternalRouterServiceStatus(ctx context.Context, hcp *hyperv1.HostedControlPlane) (host string, needed bool, message string, err error) { - if !util.IsPublicHCP(hcp) || !util.LabelHCPRoutes(hcp) || sharedingress.UseSharedIngress() || hcp.Spec.Platform.Type == hyperv1.IBMCloudPlatform { + if !util.IsPublicHCP(hcp) || !util.LabelHCPRoutes(hcp) || util.UseSharedIngressHCP(hcp) || hcp.Spec.Platform.Type == hyperv1.IBMCloudPlatform { return } return r.reconcileRouterServiceStatus(ctx, manifests.RouterPublicService(hcp.Namespace), events.NewMessageCollector(ctx, r.Client)) diff --git a/control-plane-operator/controllers/hostedcontrolplane/infra/infra_test.go b/control-plane-operator/controllers/hostedcontrolplane/infra/infra_test.go index 55d9b5f8c723..725f2fcc7f80 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/infra/infra_test.go +++ b/control-plane-operator/controllers/hostedcontrolplane/infra/infra_test.go @@ -536,11 +536,17 @@ func TestReconcileInfrastructure(t *testing.T) { }, // ARO HCP test cases - use shared ingress { - name: "ARO_Route_SharedIngress", - hcp: withServices( - baseAzureHCP(), - allServicesRouteWithHostnames(), - ), + name: "ARO_Route_SharedIngress_AnnotationFallback", + hcp: func() *hyperv1.HostedControlPlane { + hcp := withServices(baseAzureHCP(), allServicesRouteWithHostnames()) + hcp.Annotations = map[string]string{ + hyperv1.SwiftPodNetworkInstanceAnnotation: "swift-network-instance", + } + hcp.Spec.Platform.Azure.AzureAuthenticationConfig = hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeManagedIdentities, + } + return hcp + }(), setupEnv: func(t *testing.T) { t.Setenv("MANAGED_SERVICE", hyperv1.AroHCP) }, @@ -562,23 +568,58 @@ func TestReconcileInfrastructure(t *testing.T) { }, }, { - name: "ARO_Route_SharedIngress_And_Swift", + name: "ARO_Route_Swift_PublicAndPrivate", + hcp: func() *hyperv1.HostedControlPlane { + hcp := withServices(baseAzureHCP(), allServicesRouteWithHostnames()) + hcp.Spec.Platform.Azure.Topology = hyperv1.AzureTopologyPublicAndPrivate + hcp.Spec.Platform.Azure.Private = hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "test-pni", + }, + } + hcp.Spec.Platform.Azure.AzureAuthenticationConfig = hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeManagedIdentities, + } + return hcp + }(), + expectError: false, + // New path: Swift detected via Private.Type=Swift API field with PublicAndPrivate topology. + // shared ingress for public access, internal router for private access. + expectedStatus: &InfrastructureStatus{ + APIHost: testKASHostname, + APIPort: 443, + OAuthEnabled: true, + OAuthHost: testOAuthHostname, + OAuthPort: 443, + KonnectivityHost: testKonnectivityHost, + KonnectivityPort: 443, + NeedInternalRouter: false, + NeedExternalRouter: false, + }, + }, + { + name: "ARO_Route_Swift_Private", hcp: func() *hyperv1.HostedControlPlane { hcp := withServices(baseAzureHCP(), allServicesRouteWithHostnames()) hcp.Annotations = map[string]string{ hyperv1.SwiftPodNetworkInstanceAnnotation: "swift-network-instance", } + hcp.Spec.Platform.Azure.Topology = hyperv1.AzureTopologyPrivate + hcp.Spec.Platform.Azure.Private = hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "swift-network-instance", + }, + } + hcp.Spec.Platform.Azure.AzureAuthenticationConfig = hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeManagedIdentities, + } return hcp }(), - setupEnv: func(t *testing.T) { - t.Setenv("MANAGED_SERVICE", hyperv1.AroHCP) - }, expectError: false, - // For ARO with Swift: - // - Swift handles pod networking, so no router services are needed - // - APIHost comes from shared ingress (KasRouteHostname) - // - Port is 443 (ExternalDNSLBPort) - // - Konnectivity (and ignition see v2/ignitionserver) Routes use hypershift.local, kas and auth use both hypershift.local and external routes + // Swift detected via Private.Type=Swift API field with Private topology. + // No shared ingress needed, internal router needed. expectedStatus: &InfrastructureStatus{ APIHost: testKASHostname, APIPort: 443, @@ -596,7 +637,7 @@ func TestReconcileInfrastructure(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { g := NewGomegaWithT(t) - ctx := context.Background() + ctx := t.Context() // Run optional environment setup if tc.setupEnv != nil { @@ -676,18 +717,26 @@ func TestReconcileInfrastructure(t *testing.T) { // It unconditionally tries to provision all possible services/routes, ignoring "not found" errors. func simulateInfraProvisioning(ctx context.Context, c client.Client, hcp *hyperv1.HostedControlPlane, externalRouterLBHost, internalRouterLBHost, kasLBHost string) error { // List of all LoadBalancer services that might need provisioning - lbServices := []struct { + type lbService struct { svc *corev1.Service hostname string - }{ - {manifests.RouterPublicService(hcp.Namespace), externalRouterLBHost}, - {manifests.PrivateRouterService(hcp.Namespace), internalRouterLBHost}, + } + lbServices := []lbService{ {manifests.KubeAPIServerService(hcp.Namespace), kasLBHost}, {manifests.KubeAPIServerPrivateService(hcp.Namespace), kasLBHost}, {manifests.KubeAPIServerServiceAzureLB(hcp.Namespace), kasLBHost}, {manifests.OauthServerService(hcp.Namespace), testOAuthLBHostname}, } + // If not using Swift or shared ingress, provision the public and private router services as LB services + // Otherwise, only private-router service is created as ClusterIP service. + if !util.UseSwiftNetworkingHCP(hcp) && !util.UseSharedIngressHCP(hcp) { + lbServices = append(lbServices, []lbService{ + {manifests.RouterPublicService(hcp.Namespace), externalRouterLBHost}, + {manifests.PrivateRouterService(hcp.Namespace), internalRouterLBHost}, + }...) + } + for _, lb := range lbServices { if err := simulateLBServiceProvisioned(ctx, c, lb.svc, lb.hostname); err != nil { if !apierrors.IsNotFound(err) { @@ -1560,20 +1609,84 @@ func TestReconcileHCPRouterServices(t *testing.T) { expectedServices: nil, }, { - name: "When ARO is enabled it should not create any services", + name: "When ARO with Swift annotation fallback it should create only a ClusterIP private router service", endpointAccess: hyperv1.Public, exposeAPIServerThroughRouter: true, - expectedServices: nil, + expectedServices: []corev1.Service{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "private-router", + Namespace: namespace, + Labels: map[string]string{"app": "private-router"}, + }, + Spec: corev1.ServiceSpec{ + Type: corev1.ServiceTypeClusterIP, + Selector: map[string]string{"app": "private-router"}, + Ports: []corev1.ServicePort{ + { + Name: "https", + Port: 443, + TargetPort: intstr.FromString("https"), + Protocol: corev1.ProtocolTCP, + }, + }, + }, + }, + }, setupEnv: func(t *testing.T) { t.Setenv("MANAGED_SERVICE", hyperv1.AroHCP) }, hcpModifier: func(hcp *hyperv1.HostedControlPlane) { hcp.Spec.Platform.Type = hyperv1.AzurePlatform hcp.Spec.Platform.AWS = nil + hcp.Annotations = map[string]string{ + hyperv1.SwiftPodNetworkInstanceAnnotation: "swift-network-instance", + } }, }, { - name: "When ARO with Swift is enabled it should create only a ClusterIP private router service", + name: "When ARO with Swift API fields it should create only a ClusterIP private router service", + endpointAccess: hyperv1.Public, + exposeAPIServerThroughRouter: true, + expectedServices: []corev1.Service{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "private-router", + Namespace: namespace, + Labels: map[string]string{"app": "private-router"}, + }, + Spec: corev1.ServiceSpec{ + Type: corev1.ServiceTypeClusterIP, + Selector: map[string]string{"app": "private-router"}, + Ports: []corev1.ServicePort{ + { + Name: "https", + Port: 443, + TargetPort: intstr.FromString("https"), + Protocol: corev1.ProtocolTCP, + }, + }, + }, + }, + }, + setupEnv: func(t *testing.T) { + t.Setenv("MANAGED_SERVICE", hyperv1.AroHCP) + }, + hcpModifier: func(hcp *hyperv1.HostedControlPlane) { + hcp.Spec.Platform.Type = hyperv1.AzurePlatform + hcp.Spec.Platform.AWS = nil + hcp.Spec.Platform.Azure = &hyperv1.AzurePlatformSpec{ + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "test-pni", + }, + }, + } + }, + }, + { + name: "When ARO with both Swift annotation and API fields it should create only a ClusterIP private router service", endpointAccess: hyperv1.Public, exposeAPIServerThroughRouter: true, expectedServices: []corev1.Service{ @@ -1606,6 +1719,14 @@ func TestReconcileHCPRouterServices(t *testing.T) { hcp.Annotations = map[string]string{ hyperv1.SwiftPodNetworkInstanceAnnotation: "swift-network-instance", } + hcp.Spec.Platform.Azure = &hyperv1.AzurePlatformSpec{ + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "swift-network-instance", + }, + }, + } }, }, } @@ -1774,7 +1895,58 @@ func TestReconcileInternalRouterServiceStatus(t *testing.T) { wantMsg string }{ { - name: "When ARO swift is enabled it should not need internal router", + name: "When ARO swift is enabled via annotation fallback it should not need internal router", + setup: func(t *testing.T) { + t.Setenv("MANAGED_SERVICE", hyperv1.AroHCP) + }, + hcp: &hyperv1.HostedControlPlane{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-hcp", + Namespace: "test-namespace", + Annotations: map[string]string{ + hyperv1.SwiftPodNetworkInstanceAnnotation: "swift-network-instance", + }, + }, + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + Location: "eastus", + }, + }, + }, + }, + wantNeeded: false, + }, + { + name: "When ARO swift is enabled via API field it should not need internal router", + setup: func(t *testing.T) { + t.Setenv("MANAGED_SERVICE", hyperv1.AroHCP) + }, + hcp: &hyperv1.HostedControlPlane{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-hcp", + Namespace: "test-namespace", + }, + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + Location: "eastus", + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "swift-network-instance", + }, + }, + }, + }, + }, + }, + wantNeeded: false, + }, + { + name: "When ARO swift is enabled via both annotation and API field it should not need internal router", setup: func(t *testing.T) { t.Setenv("MANAGED_SERVICE", hyperv1.AroHCP) }, @@ -1791,6 +1963,12 @@ func TestReconcileInternalRouterServiceStatus(t *testing.T) { Type: hyperv1.AzurePlatform, Azure: &hyperv1.AzurePlatformSpec{ Location: "eastus", + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "swift-network-instance", + }, + }, }, }, }, diff --git a/control-plane-operator/controllers/hostedcontrolplane/infra/testdata/zz_fixture_TestReconcileInfrastructure_ARO_Route_SharedIngress_And_Swift.yaml b/control-plane-operator/controllers/hostedcontrolplane/infra/testdata/zz_fixture_TestReconcileInfrastructure_ARO_Route_SharedIngress_AnnotationFallback.yaml similarity index 100% rename from control-plane-operator/controllers/hostedcontrolplane/infra/testdata/zz_fixture_TestReconcileInfrastructure_ARO_Route_SharedIngress_And_Swift.yaml rename to control-plane-operator/controllers/hostedcontrolplane/infra/testdata/zz_fixture_TestReconcileInfrastructure_ARO_Route_SharedIngress_AnnotationFallback.yaml diff --git a/control-plane-operator/controllers/hostedcontrolplane/infra/testdata/zz_fixture_TestReconcileInfrastructure_ARO_Route_Swift_Private.yaml b/control-plane-operator/controllers/hostedcontrolplane/infra/testdata/zz_fixture_TestReconcileInfrastructure_ARO_Route_Swift_Private.yaml new file mode 100644 index 000000000000..77f150075ce4 --- /dev/null +++ b/control-plane-operator/controllers/hostedcontrolplane/infra/testdata/zz_fixture_TestReconcileInfrastructure_ARO_Route_Swift_Private.yaml @@ -0,0 +1,284 @@ +routes: + items: + - metadata: + annotations: + haproxy.router.openshift.io/balance: roundrobin + labels: + hypershift.openshift.io/hosted-control-plane: test-namespace + hypershift.openshift.io/internal-route: "true" + name: konnectivity-server + namespace: test-namespace + ownerReferences: + - apiVersion: hypershift.openshift.io/v1beta1 + blockOwnerDeletion: true + controller: true + kind: HostedControlPlane + name: test-cluster + uid: "" + spec: + host: konnectivity-server.apps.test-cluster.hypershift.local + tls: + insecureEdgeTerminationPolicy: None + termination: passthrough + to: + kind: Service + name: konnectivity-server + weight: null + status: {} + - metadata: + labels: + hypershift.openshift.io/hosted-control-plane: test-namespace + hypershift.openshift.io/internal-route: "true" + name: kube-apiserver-internal + namespace: test-namespace + ownerReferences: + - apiVersion: hypershift.openshift.io/v1beta1 + blockOwnerDeletion: true + controller: true + kind: HostedControlPlane + name: test-cluster + uid: "" + spec: + host: api.test-cluster.hypershift.local + tls: + insecureEdgeTerminationPolicy: None + termination: passthrough + to: + kind: Service + name: kube-apiserver + weight: null + status: {} + - metadata: + labels: + hypershift.openshift.io/hosted-control-plane: test-namespace + hypershift.openshift.io/internal-route: "true" + hypershift.openshift.io/route-visibility: private + name: kube-apiserver-private + namespace: test-namespace + ownerReferences: + - apiVersion: hypershift.openshift.io/v1beta1 + blockOwnerDeletion: true + controller: true + kind: HostedControlPlane + name: test-cluster + uid: "" + spec: + host: api.test.example.com + tls: + insecureEdgeTerminationPolicy: None + termination: passthrough + to: + kind: Service + name: kube-apiserver + weight: null + status: {} + - metadata: + labels: + hypershift.openshift.io/hosted-control-plane: test-namespace + hypershift.openshift.io/internal-route: "true" + name: oauth-internal + namespace: test-namespace + ownerReferences: + - apiVersion: hypershift.openshift.io/v1beta1 + blockOwnerDeletion: true + controller: true + kind: HostedControlPlane + name: test-cluster + uid: "" + spec: + host: oauth.apps.test-cluster.hypershift.local + tls: + insecureEdgeTerminationPolicy: None + termination: passthrough + to: + kind: Service + name: oauth-openshift + weight: null + status: {} + - metadata: + labels: + hypershift.openshift.io/hosted-control-plane: test-namespace + hypershift.openshift.io/internal-route: "true" + hypershift.openshift.io/route-visibility: private + name: oauth-private + namespace: test-namespace + ownerReferences: + - apiVersion: hypershift.openshift.io/v1beta1 + blockOwnerDeletion: true + controller: true + kind: HostedControlPlane + name: test-cluster + uid: "" + spec: + host: oauth.test.example.com + tls: + insecureEdgeTerminationPolicy: None + termination: passthrough + to: + kind: Service + name: oauth-openshift + weight: null + status: {} + metadata: {} +services: + items: + - metadata: + name: konnectivity-server + namespace: test-namespace + ownerReferences: + - apiVersion: hypershift.openshift.io/v1beta1 + blockOwnerDeletion: true + controller: true + kind: HostedControlPlane + name: test-cluster + uid: "" + spec: + ports: + - port: 8091 + protocol: TCP + targetPort: 8091 + selector: + app: kube-apiserver + hypershift.openshift.io/control-plane-component: kube-apiserver + type: ClusterIP + status: + loadBalancer: {} + - metadata: + labels: + app: kube-apiserver + hypershift.openshift.io/control-plane-component: kube-apiserver + name: kube-apiserver + namespace: test-namespace + ownerReferences: + - apiVersion: hypershift.openshift.io/v1beta1 + blockOwnerDeletion: true + controller: true + kind: HostedControlPlane + name: test-cluster + uid: "" + spec: + ipFamilyPolicy: PreferDualStack + ports: + - port: 6443 + protocol: TCP + targetPort: client + selector: + app: kube-apiserver + hypershift.openshift.io/control-plane-component: kube-apiserver + type: ClusterIP + status: + loadBalancer: {} + - metadata: + name: oauth-openshift + namespace: test-namespace + ownerReferences: + - apiVersion: hypershift.openshift.io/v1beta1 + blockOwnerDeletion: true + controller: true + kind: HostedControlPlane + name: test-cluster + uid: "" + spec: + ipFamilyPolicy: PreferDualStack + ports: + - port: 6443 + protocol: TCP + targetPort: 6443 + selector: + app: oauth-openshift + hypershift.openshift.io/control-plane-component: oauth-openshift + type: ClusterIP + status: + loadBalancer: {} + - metadata: + labels: + app: openshift-apiserver + hypershift.openshift.io/control-plane-component: openshift-apiserver + name: openshift-apiserver + namespace: test-namespace + ownerReferences: + - apiVersion: hypershift.openshift.io/v1beta1 + blockOwnerDeletion: true + controller: true + kind: HostedControlPlane + name: test-cluster + uid: "" + spec: + ports: + - name: https + port: 443 + protocol: TCP + targetPort: 8443 + selector: + app: openshift-apiserver + hypershift.openshift.io/control-plane-component: openshift-apiserver + type: ClusterIP + status: + loadBalancer: {} + - metadata: + labels: + app: openshift-apiserver + hypershift.openshift.io/control-plane-component: openshift-apiserver + name: openshift-oauth-apiserver + namespace: test-namespace + ownerReferences: + - apiVersion: hypershift.openshift.io/v1beta1 + blockOwnerDeletion: true + controller: true + kind: HostedControlPlane + name: test-cluster + uid: "" + spec: + ports: + - name: https + port: 443 + protocol: TCP + targetPort: 8443 + selector: + app: openshift-oauth-apiserver + hypershift.openshift.io/control-plane-component: openshift-oauth-apiserver + type: ClusterIP + status: + loadBalancer: {} + - metadata: + labels: + app: openshift-apiserver + hypershift.openshift.io/control-plane-component: openshift-apiserver + name: packageserver + namespace: test-namespace + ownerReferences: + - apiVersion: hypershift.openshift.io/v1beta1 + blockOwnerDeletion: true + controller: true + kind: HostedControlPlane + name: test-cluster + uid: "" + spec: + ports: + - name: https + port: 443 + protocol: TCP + targetPort: 5443 + selector: + app: packageserver + hypershift.openshift.io/control-plane-component: packageserver + type: ClusterIP + status: + loadBalancer: {} + - metadata: + labels: + app: private-router + name: private-router + namespace: test-namespace + spec: + ports: + - name: https + port: 443 + protocol: TCP + targetPort: https + selector: + app: private-router + type: ClusterIP + status: + loadBalancer: {} + metadata: {} diff --git a/control-plane-operator/controllers/hostedcontrolplane/infra/testdata/zz_fixture_TestReconcileInfrastructure_ARO_Route_SharedIngress.yaml b/control-plane-operator/controllers/hostedcontrolplane/infra/testdata/zz_fixture_TestReconcileInfrastructure_ARO_Route_Swift_PublicAndPrivate.yaml similarity index 85% rename from control-plane-operator/controllers/hostedcontrolplane/infra/testdata/zz_fixture_TestReconcileInfrastructure_ARO_Route_SharedIngress.yaml rename to control-plane-operator/controllers/hostedcontrolplane/infra/testdata/zz_fixture_TestReconcileInfrastructure_ARO_Route_Swift_PublicAndPrivate.yaml index be61f3216991..b343e2bfb913 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/infra/testdata/zz_fixture_TestReconcileInfrastructure_ARO_Route_SharedIngress.yaml +++ b/control-plane-operator/controllers/hostedcontrolplane/infra/testdata/zz_fixture_TestReconcileInfrastructure_ARO_Route_Swift_PublicAndPrivate.yaml @@ -5,6 +5,7 @@ routes: haproxy.router.openshift.io/balance: roundrobin labels: hypershift.openshift.io/hosted-control-plane: test-namespace + hypershift.openshift.io/internal-route: "true" name: konnectivity-server namespace: test-namespace ownerReferences: @@ -15,7 +16,7 @@ routes: name: test-cluster uid: "" spec: - host: konnectivity.test.example.com + host: konnectivity-server.apps.test-cluster.hypershift.local tls: insecureEdgeTerminationPolicy: None termination: passthrough @@ -91,6 +92,29 @@ routes: name: oauth-openshift weight: null status: {} + - metadata: + labels: + hypershift.openshift.io/hosted-control-plane: test-namespace + hypershift.openshift.io/internal-route: "true" + name: oauth-internal + namespace: test-namespace + ownerReferences: + - apiVersion: hypershift.openshift.io/v1beta1 + blockOwnerDeletion: true + controller: true + kind: HostedControlPlane + name: test-cluster + uid: "" + spec: + host: oauth.apps.test-cluster.hypershift.local + tls: + insecureEdgeTerminationPolicy: None + termination: passthrough + to: + kind: Service + name: oauth-openshift + weight: null + status: {} metadata: {} services: items: @@ -237,4 +261,20 @@ services: type: ClusterIP status: loadBalancer: {} + - metadata: + labels: + app: private-router + name: private-router + namespace: test-namespace + spec: + ports: + - name: https + port: 443 + protocol: TCP + targetPort: https + selector: + app: private-router + type: ClusterIP + status: + loadBalancer: {} metadata: {} diff --git a/control-plane-operator/controllers/hostedcontrolplane/ingress/router.go b/control-plane-operator/controllers/hostedcontrolplane/ingress/router.go index f3bc157134de..8c7d624e570b 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/ingress/router.go +++ b/control-plane-operator/controllers/hostedcontrolplane/ingress/router.go @@ -45,7 +45,7 @@ func ReconcileRouterService(svc *corev1.Service, internal, crossZoneLoadBalancin } } - if hcp.Spec.Platform.Type == hyperv1.AzurePlatform && !azureutil.IsAroHCP() { + if hcp.Spec.Platform.Type == hyperv1.AzurePlatform && !azureutil.IsAroHCPByHCP(hcp) { if svc.Annotations == nil { svc.Annotations = map[string]string{} } @@ -85,7 +85,7 @@ func ReconcileRouterService(svc *corev1.Service, internal, crossZoneLoadBalancin // Apply LoadBalancerSourceRanges for external router services to restrict CIDR access // Only apply for external (non-internal) services and when not running on ARO HCP allowedCIDRBlocks := util.AllowedCIDRBlocks(hcp) - if !internal && !azureutil.IsAroHCP() { + if !internal && !azureutil.IsAroHCPByHCP(hcp) { svc.Spec.LoadBalancerSourceRanges = allowedCIDRBlocks } diff --git a/control-plane-operator/controllers/hostedcontrolplane/kas/healthcheck.go b/control-plane-operator/controllers/hostedcontrolplane/kas/healthcheck.go index 082bc4c48888..aecf59081d48 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/kas/healthcheck.go +++ b/control-plane-operator/controllers/hostedcontrolplane/kas/healthcheck.go @@ -7,6 +7,7 @@ import ( "github.com/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/manifests" "github.com/openshift/hypershift/hypershift-operator/controllers/sharedingress" "github.com/openshift/hypershift/support/config" + "github.com/openshift/hypershift/support/util" routev1 "github.com/openshift/api/route/v1" ) @@ -20,12 +21,12 @@ func GetHealthcheckEndpointForRoute(externalRoute *routev1.Route, hcp *hyperv1.H endpoint = externalRoute.Status.Ingress[0].RouterCanonicalHostname port = 443 - if sharedingress.UseSharedIngress() { + if util.UseSharedIngressHCP(hcp) { endpoint = externalRoute.Spec.Host port = sharedingress.ExternalDNSLBPort } - if sharedingress.UseSharedIngress() && + if util.UseSharedIngressHCP(hcp) && hcp.Spec.Networking.APIServer != nil && len(hcp.Spec.Networking.APIServer.AllowedCIDRBlocks) > 0 { // When there's AllowedCIDRBlocks input, we have no guarantees the healthcheck can roundtrip through the haproxy load balancer. // Hence we use KubeAPIServerService as a best effort. diff --git a/control-plane-operator/controllers/hostedcontrolplane/kas/healthcheck_test.go b/control-plane-operator/controllers/hostedcontrolplane/kas/healthcheck_test.go index df1ddedcad7e..04539407885c 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/kas/healthcheck_test.go +++ b/control-plane-operator/controllers/hostedcontrolplane/kas/healthcheck_test.go @@ -64,7 +64,24 @@ func TestGetHealthcheckEndpoint(t *testing.T) { }, }, }, - hcp: &hyperv1.HostedControlPlane{}, + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "test-pni", + }, + }, + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeManagedIdentities, + }, + }, + }, + }, + }, useSharedIngress: true, expectedEndpoint: "route.example.com", expectedPort: sharedingress.ExternalDNSLBPort, @@ -85,6 +102,20 @@ func TestGetHealthcheckEndpoint(t *testing.T) { }, hcp: &hyperv1.HostedControlPlane{ Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "test-pni", + }, + }, + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeManagedIdentities, + }, + }, + }, Networking: hyperv1.ClusterNetworking{ APIServer: &hyperv1.APIServerNetworking{ AllowedCIDRBlocks: []hyperv1.CIDRBlock{"10.0.0.0/16"}, diff --git a/control-plane-operator/controllers/hostedcontrolplane/kas/service.go b/control-plane-operator/controllers/hostedcontrolplane/kas/service.go index 3934c0506509..8a8778958e77 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/kas/service.go +++ b/control-plane-operator/controllers/hostedcontrolplane/kas/service.go @@ -71,7 +71,7 @@ func ReconcileService(svc *corev1.Service, strategy *hyperv1.ServicePublishingSt if strategy.LoadBalancer != nil && strategy.LoadBalancer.Hostname != "" { svc.Annotations[hyperv1.ExternalDNSHostnameAnnotation] = strategy.LoadBalancer.Hostname } - if !azureutil.IsAroHCP() { + if !azureutil.IsAroHCPByHCP(hcp) { svc.Spec.LoadBalancerSourceRanges = apiAllowedCIDRBlocks } diff --git a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/GCP/zz_fixture_TestControlPlaneComponents_azure_cloud_config_configmap.yaml b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/GCP/zz_fixture_TestControlPlaneComponents_azure_cloud_config_configmap.yaml index 7e185cd1eb5f..854f8ab89828 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/GCP/zz_fixture_TestControlPlaneComponents_azure_cloud_config_configmap.yaml +++ b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/GCP/zz_fixture_TestControlPlaneComponents_azure_cloud_config_configmap.yaml @@ -5,12 +5,12 @@ data: "cloud": "", "tenantId": "", "useManagedIdentityExtension": false, - "useFederatedWorkloadIdentityExtension": false, + "useFederatedWorkloadIdentityExtension": true, "subscriptionId": "", - "aadClientId": "", + "aadClientId": "myClientID", "aadClientSecret": "", "aadClientCertPath": "", - "aadFederatedTokenFile": "", + "aadFederatedTokenFile": "/var/run/secrets/openshift/serviceaccount/token", "aadMSIDataPlaneIdentityPath": "", "resourceGroup": "", "location": "", diff --git a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/GCP/zz_fixture_TestControlPlaneComponents_azure_cloud_config_secret.yaml b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/GCP/zz_fixture_TestControlPlaneComponents_azure_cloud_config_secret.yaml index 6c4df55d61f3..daa214bfed83 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/GCP/zz_fixture_TestControlPlaneComponents_azure_cloud_config_secret.yaml +++ b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/GCP/zz_fixture_TestControlPlaneComponents_azure_cloud_config_secret.yaml @@ -1,6 +1,6 @@ apiVersion: v1 data: - cloud.conf: ewogICJjbG91ZCI6ICIiLAogICJ0ZW5hbnRJZCI6ICIiLAogICJ1c2VNYW5hZ2VkSWRlbnRpdHlFeHRlbnNpb24iOiBmYWxzZSwKICAidXNlRmVkZXJhdGVkV29ya2xvYWRJZGVudGl0eUV4dGVuc2lvbiI6IGZhbHNlLAogICJzdWJzY3JpcHRpb25JZCI6ICIiLAogICJhYWRDbGllbnRJZCI6ICIiLAogICJhYWRDbGllbnRTZWNyZXQiOiAiIiwKICAiYWFkQ2xpZW50Q2VydFBhdGgiOiAiIiwKICAiYWFkRmVkZXJhdGVkVG9rZW5GaWxlIjogIiIsCiAgImFhZE1TSURhdGFQbGFuZUlkZW50aXR5UGF0aCI6ICIiLAogICJyZXNvdXJjZUdyb3VwIjogIiIsCiAgImxvY2F0aW9uIjogIiIsCiAgInZuZXROYW1lIjogIm15Vm5ldE5hbWUiLAogICJ2bmV0UmVzb3VyY2VHcm91cCI6ICJteVJlc291cmNlR3JvdXBOYW1lIiwKICAic3VibmV0TmFtZSI6ICJteVN1Ym5ldE5hbWUiLAogICJzZWN1cml0eUdyb3VwTmFtZSI6ICJteU5TR05hbWUiLAogICJzZWN1cml0eUdyb3VwUmVzb3VyY2VHcm91cCI6ICJteVJlc291cmNlR3JvdXBOYW1lIiwKICAicm91dGVUYWJsZU5hbWUiOiAiIiwKICAiY2xvdWRQcm92aWRlckJhY2tvZmYiOiB0cnVlLAogICJjbG91ZFByb3ZpZGVyQmFja29mZkR1cmF0aW9uIjogNiwKICAidXNlSW5zdGFuY2VNZXRhZGF0YSI6IHRydWUsCiAgImxvYWRCYWxhbmNlclNrdSI6ICJzdGFuZGFyZCIsCiAgImRpc2FibGVPdXRib3VuZFNOQVQiOiB0cnVlLAogICJsb2FkQmFsYW5jZXJOYW1lIjogIiIsCiAgImNsdXN0ZXJTZXJ2aWNlTG9hZEJhbGFuY2VySGVhbHRoUHJvYmVNb2RlIjogInNoYXJlZCIKfQ== + cloud.conf: ewogICJjbG91ZCI6ICIiLAogICJ0ZW5hbnRJZCI6ICIiLAogICJ1c2VNYW5hZ2VkSWRlbnRpdHlFeHRlbnNpb24iOiBmYWxzZSwKICAidXNlRmVkZXJhdGVkV29ya2xvYWRJZGVudGl0eUV4dGVuc2lvbiI6IHRydWUsCiAgInN1YnNjcmlwdGlvbklkIjogIiIsCiAgImFhZENsaWVudElkIjogIm15Q2xpZW50SUQiLAogICJhYWRDbGllbnRTZWNyZXQiOiAiIiwKICAiYWFkQ2xpZW50Q2VydFBhdGgiOiAiIiwKICAiYWFkRmVkZXJhdGVkVG9rZW5GaWxlIjogIi92YXIvcnVuL3NlY3JldHMvb3BlbnNoaWZ0L3NlcnZpY2VhY2NvdW50L3Rva2VuIiwKICAiYWFkTVNJRGF0YVBsYW5lSWRlbnRpdHlQYXRoIjogIiIsCiAgInJlc291cmNlR3JvdXAiOiAiIiwKICAibG9jYXRpb24iOiAiIiwKICAidm5ldE5hbWUiOiAibXlWbmV0TmFtZSIsCiAgInZuZXRSZXNvdXJjZUdyb3VwIjogIm15UmVzb3VyY2VHcm91cE5hbWUiLAogICJzdWJuZXROYW1lIjogIm15U3VibmV0TmFtZSIsCiAgInNlY3VyaXR5R3JvdXBOYW1lIjogIm15TlNHTmFtZSIsCiAgInNlY3VyaXR5R3JvdXBSZXNvdXJjZUdyb3VwIjogIm15UmVzb3VyY2VHcm91cE5hbWUiLAogICJyb3V0ZVRhYmxlTmFtZSI6ICIiLAogICJjbG91ZFByb3ZpZGVyQmFja29mZiI6IHRydWUsCiAgImNsb3VkUHJvdmlkZXJCYWNrb2ZmRHVyYXRpb24iOiA2LAogICJ1c2VJbnN0YW5jZU1ldGFkYXRhIjogdHJ1ZSwKICAibG9hZEJhbGFuY2VyU2t1IjogInN0YW5kYXJkIiwKICAiZGlzYWJsZU91dGJvdW5kU05BVCI6IHRydWUsCiAgImxvYWRCYWxhbmNlck5hbWUiOiAiIiwKICAiY2x1c3RlclNlcnZpY2VMb2FkQmFsYW5jZXJIZWFsdGhQcm9iZU1vZGUiOiAic2hhcmVkIgp9 kind: Secret metadata: name: azure-cloud-config diff --git a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/GCP/zz_fixture_TestControlPlaneComponents_azure_cloud_controller_manager_deployment.yaml b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/GCP/zz_fixture_TestControlPlaneComponents_azure_cloud_controller_manager_deployment.yaml index 82e9a468eded..f04b83971e73 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/GCP/zz_fixture_TestControlPlaneComponents_azure_cloud_controller_manager_deployment.yaml +++ b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/GCP/zz_fixture_TestControlPlaneComponents_azure_cloud_controller_manager_deployment.yaml @@ -25,7 +25,7 @@ spec: metadata: annotations: cluster-autoscaler.kubernetes.io/safe-to-evict-local-volumes: cloud-token,tmp-dir - component.hypershift.openshift.io/config-hash: 6390db5f + component.hypershift.openshift.io/config-hash: 5e25069a hypershift.openshift.io/release-image: quay.io/openshift-release-dev/ocp-release:4.16.10-x86_64 labels: app: cloud-controller-manager @@ -139,6 +139,7 @@ spec: - mountPath: /etc/kubernetes name: kubeconfig priorityClassName: hypershift-control-plane + serviceAccountName: azure-cloud-controller-manager tolerations: - effect: NoSchedule key: hypershift.openshift.io/control-plane diff --git a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/IBMCloud/zz_fixture_TestControlPlaneComponents_azure_cloud_config_configmap.yaml b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/IBMCloud/zz_fixture_TestControlPlaneComponents_azure_cloud_config_configmap.yaml index 7e185cd1eb5f..854f8ab89828 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/IBMCloud/zz_fixture_TestControlPlaneComponents_azure_cloud_config_configmap.yaml +++ b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/IBMCloud/zz_fixture_TestControlPlaneComponents_azure_cloud_config_configmap.yaml @@ -5,12 +5,12 @@ data: "cloud": "", "tenantId": "", "useManagedIdentityExtension": false, - "useFederatedWorkloadIdentityExtension": false, + "useFederatedWorkloadIdentityExtension": true, "subscriptionId": "", - "aadClientId": "", + "aadClientId": "myClientID", "aadClientSecret": "", "aadClientCertPath": "", - "aadFederatedTokenFile": "", + "aadFederatedTokenFile": "/var/run/secrets/openshift/serviceaccount/token", "aadMSIDataPlaneIdentityPath": "", "resourceGroup": "", "location": "", diff --git a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/IBMCloud/zz_fixture_TestControlPlaneComponents_azure_cloud_config_secret.yaml b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/IBMCloud/zz_fixture_TestControlPlaneComponents_azure_cloud_config_secret.yaml index 6c4df55d61f3..daa214bfed83 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/IBMCloud/zz_fixture_TestControlPlaneComponents_azure_cloud_config_secret.yaml +++ b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/IBMCloud/zz_fixture_TestControlPlaneComponents_azure_cloud_config_secret.yaml @@ -1,6 +1,6 @@ apiVersion: v1 data: - cloud.conf: ewogICJjbG91ZCI6ICIiLAogICJ0ZW5hbnRJZCI6ICIiLAogICJ1c2VNYW5hZ2VkSWRlbnRpdHlFeHRlbnNpb24iOiBmYWxzZSwKICAidXNlRmVkZXJhdGVkV29ya2xvYWRJZGVudGl0eUV4dGVuc2lvbiI6IGZhbHNlLAogICJzdWJzY3JpcHRpb25JZCI6ICIiLAogICJhYWRDbGllbnRJZCI6ICIiLAogICJhYWRDbGllbnRTZWNyZXQiOiAiIiwKICAiYWFkQ2xpZW50Q2VydFBhdGgiOiAiIiwKICAiYWFkRmVkZXJhdGVkVG9rZW5GaWxlIjogIiIsCiAgImFhZE1TSURhdGFQbGFuZUlkZW50aXR5UGF0aCI6ICIiLAogICJyZXNvdXJjZUdyb3VwIjogIiIsCiAgImxvY2F0aW9uIjogIiIsCiAgInZuZXROYW1lIjogIm15Vm5ldE5hbWUiLAogICJ2bmV0UmVzb3VyY2VHcm91cCI6ICJteVJlc291cmNlR3JvdXBOYW1lIiwKICAic3VibmV0TmFtZSI6ICJteVN1Ym5ldE5hbWUiLAogICJzZWN1cml0eUdyb3VwTmFtZSI6ICJteU5TR05hbWUiLAogICJzZWN1cml0eUdyb3VwUmVzb3VyY2VHcm91cCI6ICJteVJlc291cmNlR3JvdXBOYW1lIiwKICAicm91dGVUYWJsZU5hbWUiOiAiIiwKICAiY2xvdWRQcm92aWRlckJhY2tvZmYiOiB0cnVlLAogICJjbG91ZFByb3ZpZGVyQmFja29mZkR1cmF0aW9uIjogNiwKICAidXNlSW5zdGFuY2VNZXRhZGF0YSI6IHRydWUsCiAgImxvYWRCYWxhbmNlclNrdSI6ICJzdGFuZGFyZCIsCiAgImRpc2FibGVPdXRib3VuZFNOQVQiOiB0cnVlLAogICJsb2FkQmFsYW5jZXJOYW1lIjogIiIsCiAgImNsdXN0ZXJTZXJ2aWNlTG9hZEJhbGFuY2VySGVhbHRoUHJvYmVNb2RlIjogInNoYXJlZCIKfQ== + cloud.conf: ewogICJjbG91ZCI6ICIiLAogICJ0ZW5hbnRJZCI6ICIiLAogICJ1c2VNYW5hZ2VkSWRlbnRpdHlFeHRlbnNpb24iOiBmYWxzZSwKICAidXNlRmVkZXJhdGVkV29ya2xvYWRJZGVudGl0eUV4dGVuc2lvbiI6IHRydWUsCiAgInN1YnNjcmlwdGlvbklkIjogIiIsCiAgImFhZENsaWVudElkIjogIm15Q2xpZW50SUQiLAogICJhYWRDbGllbnRTZWNyZXQiOiAiIiwKICAiYWFkQ2xpZW50Q2VydFBhdGgiOiAiIiwKICAiYWFkRmVkZXJhdGVkVG9rZW5GaWxlIjogIi92YXIvcnVuL3NlY3JldHMvb3BlbnNoaWZ0L3NlcnZpY2VhY2NvdW50L3Rva2VuIiwKICAiYWFkTVNJRGF0YVBsYW5lSWRlbnRpdHlQYXRoIjogIiIsCiAgInJlc291cmNlR3JvdXAiOiAiIiwKICAibG9jYXRpb24iOiAiIiwKICAidm5ldE5hbWUiOiAibXlWbmV0TmFtZSIsCiAgInZuZXRSZXNvdXJjZUdyb3VwIjogIm15UmVzb3VyY2VHcm91cE5hbWUiLAogICJzdWJuZXROYW1lIjogIm15U3VibmV0TmFtZSIsCiAgInNlY3VyaXR5R3JvdXBOYW1lIjogIm15TlNHTmFtZSIsCiAgInNlY3VyaXR5R3JvdXBSZXNvdXJjZUdyb3VwIjogIm15UmVzb3VyY2VHcm91cE5hbWUiLAogICJyb3V0ZVRhYmxlTmFtZSI6ICIiLAogICJjbG91ZFByb3ZpZGVyQmFja29mZiI6IHRydWUsCiAgImNsb3VkUHJvdmlkZXJCYWNrb2ZmRHVyYXRpb24iOiA2LAogICJ1c2VJbnN0YW5jZU1ldGFkYXRhIjogdHJ1ZSwKICAibG9hZEJhbGFuY2VyU2t1IjogInN0YW5kYXJkIiwKICAiZGlzYWJsZU91dGJvdW5kU05BVCI6IHRydWUsCiAgImxvYWRCYWxhbmNlck5hbWUiOiAiIiwKICAiY2x1c3RlclNlcnZpY2VMb2FkQmFsYW5jZXJIZWFsdGhQcm9iZU1vZGUiOiAic2hhcmVkIgp9 kind: Secret metadata: name: azure-cloud-config diff --git a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/IBMCloud/zz_fixture_TestControlPlaneComponents_azure_cloud_controller_manager_deployment.yaml b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/IBMCloud/zz_fixture_TestControlPlaneComponents_azure_cloud_controller_manager_deployment.yaml index 46764bcf7cbf..c1fc8dcb56c2 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/IBMCloud/zz_fixture_TestControlPlaneComponents_azure_cloud_controller_manager_deployment.yaml +++ b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/IBMCloud/zz_fixture_TestControlPlaneComponents_azure_cloud_controller_manager_deployment.yaml @@ -25,7 +25,7 @@ spec: metadata: annotations: cluster-autoscaler.kubernetes.io/safe-to-evict-local-volumes: tmp-dir - component.hypershift.openshift.io/config-hash: 6390db5f + component.hypershift.openshift.io/config-hash: 5e25069a hypershift.openshift.io/release-image: quay.io/openshift-release-dev/ocp-release:4.16.10-x86_64 labels: app: cloud-controller-manager @@ -94,6 +94,7 @@ spec: - mountPath: /tmp name: tmp-dir priorityClassName: hypershift-control-plane + serviceAccountName: azure-cloud-controller-manager tolerations: - effect: NoSchedule key: hypershift.openshift.io/control-plane diff --git a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/TechPreviewNoUpgrade/zz_fixture_TestControlPlaneComponents_azure_cloud_config_configmap.yaml b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/TechPreviewNoUpgrade/zz_fixture_TestControlPlaneComponents_azure_cloud_config_configmap.yaml index 7e185cd1eb5f..854f8ab89828 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/TechPreviewNoUpgrade/zz_fixture_TestControlPlaneComponents_azure_cloud_config_configmap.yaml +++ b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/TechPreviewNoUpgrade/zz_fixture_TestControlPlaneComponents_azure_cloud_config_configmap.yaml @@ -5,12 +5,12 @@ data: "cloud": "", "tenantId": "", "useManagedIdentityExtension": false, - "useFederatedWorkloadIdentityExtension": false, + "useFederatedWorkloadIdentityExtension": true, "subscriptionId": "", - "aadClientId": "", + "aadClientId": "myClientID", "aadClientSecret": "", "aadClientCertPath": "", - "aadFederatedTokenFile": "", + "aadFederatedTokenFile": "/var/run/secrets/openshift/serviceaccount/token", "aadMSIDataPlaneIdentityPath": "", "resourceGroup": "", "location": "", diff --git a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/TechPreviewNoUpgrade/zz_fixture_TestControlPlaneComponents_azure_cloud_config_secret.yaml b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/TechPreviewNoUpgrade/zz_fixture_TestControlPlaneComponents_azure_cloud_config_secret.yaml index 6c4df55d61f3..daa214bfed83 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/TechPreviewNoUpgrade/zz_fixture_TestControlPlaneComponents_azure_cloud_config_secret.yaml +++ b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/TechPreviewNoUpgrade/zz_fixture_TestControlPlaneComponents_azure_cloud_config_secret.yaml @@ -1,6 +1,6 @@ apiVersion: v1 data: - cloud.conf: ewogICJjbG91ZCI6ICIiLAogICJ0ZW5hbnRJZCI6ICIiLAogICJ1c2VNYW5hZ2VkSWRlbnRpdHlFeHRlbnNpb24iOiBmYWxzZSwKICAidXNlRmVkZXJhdGVkV29ya2xvYWRJZGVudGl0eUV4dGVuc2lvbiI6IGZhbHNlLAogICJzdWJzY3JpcHRpb25JZCI6ICIiLAogICJhYWRDbGllbnRJZCI6ICIiLAogICJhYWRDbGllbnRTZWNyZXQiOiAiIiwKICAiYWFkQ2xpZW50Q2VydFBhdGgiOiAiIiwKICAiYWFkRmVkZXJhdGVkVG9rZW5GaWxlIjogIiIsCiAgImFhZE1TSURhdGFQbGFuZUlkZW50aXR5UGF0aCI6ICIiLAogICJyZXNvdXJjZUdyb3VwIjogIiIsCiAgImxvY2F0aW9uIjogIiIsCiAgInZuZXROYW1lIjogIm15Vm5ldE5hbWUiLAogICJ2bmV0UmVzb3VyY2VHcm91cCI6ICJteVJlc291cmNlR3JvdXBOYW1lIiwKICAic3VibmV0TmFtZSI6ICJteVN1Ym5ldE5hbWUiLAogICJzZWN1cml0eUdyb3VwTmFtZSI6ICJteU5TR05hbWUiLAogICJzZWN1cml0eUdyb3VwUmVzb3VyY2VHcm91cCI6ICJteVJlc291cmNlR3JvdXBOYW1lIiwKICAicm91dGVUYWJsZU5hbWUiOiAiIiwKICAiY2xvdWRQcm92aWRlckJhY2tvZmYiOiB0cnVlLAogICJjbG91ZFByb3ZpZGVyQmFja29mZkR1cmF0aW9uIjogNiwKICAidXNlSW5zdGFuY2VNZXRhZGF0YSI6IHRydWUsCiAgImxvYWRCYWxhbmNlclNrdSI6ICJzdGFuZGFyZCIsCiAgImRpc2FibGVPdXRib3VuZFNOQVQiOiB0cnVlLAogICJsb2FkQmFsYW5jZXJOYW1lIjogIiIsCiAgImNsdXN0ZXJTZXJ2aWNlTG9hZEJhbGFuY2VySGVhbHRoUHJvYmVNb2RlIjogInNoYXJlZCIKfQ== + cloud.conf: ewogICJjbG91ZCI6ICIiLAogICJ0ZW5hbnRJZCI6ICIiLAogICJ1c2VNYW5hZ2VkSWRlbnRpdHlFeHRlbnNpb24iOiBmYWxzZSwKICAidXNlRmVkZXJhdGVkV29ya2xvYWRJZGVudGl0eUV4dGVuc2lvbiI6IHRydWUsCiAgInN1YnNjcmlwdGlvbklkIjogIiIsCiAgImFhZENsaWVudElkIjogIm15Q2xpZW50SUQiLAogICJhYWRDbGllbnRTZWNyZXQiOiAiIiwKICAiYWFkQ2xpZW50Q2VydFBhdGgiOiAiIiwKICAiYWFkRmVkZXJhdGVkVG9rZW5GaWxlIjogIi92YXIvcnVuL3NlY3JldHMvb3BlbnNoaWZ0L3NlcnZpY2VhY2NvdW50L3Rva2VuIiwKICAiYWFkTVNJRGF0YVBsYW5lSWRlbnRpdHlQYXRoIjogIiIsCiAgInJlc291cmNlR3JvdXAiOiAiIiwKICAibG9jYXRpb24iOiAiIiwKICAidm5ldE5hbWUiOiAibXlWbmV0TmFtZSIsCiAgInZuZXRSZXNvdXJjZUdyb3VwIjogIm15UmVzb3VyY2VHcm91cE5hbWUiLAogICJzdWJuZXROYW1lIjogIm15U3VibmV0TmFtZSIsCiAgInNlY3VyaXR5R3JvdXBOYW1lIjogIm15TlNHTmFtZSIsCiAgInNlY3VyaXR5R3JvdXBSZXNvdXJjZUdyb3VwIjogIm15UmVzb3VyY2VHcm91cE5hbWUiLAogICJyb3V0ZVRhYmxlTmFtZSI6ICIiLAogICJjbG91ZFByb3ZpZGVyQmFja29mZiI6IHRydWUsCiAgImNsb3VkUHJvdmlkZXJCYWNrb2ZmRHVyYXRpb24iOiA2LAogICJ1c2VJbnN0YW5jZU1ldGFkYXRhIjogdHJ1ZSwKICAibG9hZEJhbGFuY2VyU2t1IjogInN0YW5kYXJkIiwKICAiZGlzYWJsZU91dGJvdW5kU05BVCI6IHRydWUsCiAgImxvYWRCYWxhbmNlck5hbWUiOiAiIiwKICAiY2x1c3RlclNlcnZpY2VMb2FkQmFsYW5jZXJIZWFsdGhQcm9iZU1vZGUiOiAic2hhcmVkIgp9 kind: Secret metadata: name: azure-cloud-config diff --git a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/TechPreviewNoUpgrade/zz_fixture_TestControlPlaneComponents_azure_cloud_controller_manager_deployment.yaml b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/TechPreviewNoUpgrade/zz_fixture_TestControlPlaneComponents_azure_cloud_controller_manager_deployment.yaml index db98131c4780..355ee94448ad 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/TechPreviewNoUpgrade/zz_fixture_TestControlPlaneComponents_azure_cloud_controller_manager_deployment.yaml +++ b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/TechPreviewNoUpgrade/zz_fixture_TestControlPlaneComponents_azure_cloud_controller_manager_deployment.yaml @@ -25,7 +25,7 @@ spec: metadata: annotations: cluster-autoscaler.kubernetes.io/safe-to-evict-local-volumes: cloud-token,tmp-dir - component.hypershift.openshift.io/config-hash: 6390db5f + component.hypershift.openshift.io/config-hash: 5e25069a hypershift.openshift.io/release-image: quay.io/openshift-release-dev/ocp-release:4.16.10-x86_64 labels: app: cloud-controller-manager @@ -128,6 +128,7 @@ spec: - mountPath: /etc/kubernetes name: kubeconfig priorityClassName: hypershift-control-plane + serviceAccountName: azure-cloud-controller-manager tolerations: - effect: NoSchedule key: hypershift.openshift.io/control-plane diff --git a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/zz_fixture_TestControlPlaneComponents_azure_cloud_config_configmap.yaml b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/zz_fixture_TestControlPlaneComponents_azure_cloud_config_configmap.yaml index 7e185cd1eb5f..854f8ab89828 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/zz_fixture_TestControlPlaneComponents_azure_cloud_config_configmap.yaml +++ b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/zz_fixture_TestControlPlaneComponents_azure_cloud_config_configmap.yaml @@ -5,12 +5,12 @@ data: "cloud": "", "tenantId": "", "useManagedIdentityExtension": false, - "useFederatedWorkloadIdentityExtension": false, + "useFederatedWorkloadIdentityExtension": true, "subscriptionId": "", - "aadClientId": "", + "aadClientId": "myClientID", "aadClientSecret": "", "aadClientCertPath": "", - "aadFederatedTokenFile": "", + "aadFederatedTokenFile": "/var/run/secrets/openshift/serviceaccount/token", "aadMSIDataPlaneIdentityPath": "", "resourceGroup": "", "location": "", diff --git a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/zz_fixture_TestControlPlaneComponents_azure_cloud_config_secret.yaml b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/zz_fixture_TestControlPlaneComponents_azure_cloud_config_secret.yaml index 6c4df55d61f3..daa214bfed83 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/zz_fixture_TestControlPlaneComponents_azure_cloud_config_secret.yaml +++ b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/zz_fixture_TestControlPlaneComponents_azure_cloud_config_secret.yaml @@ -1,6 +1,6 @@ apiVersion: v1 data: - cloud.conf: ewogICJjbG91ZCI6ICIiLAogICJ0ZW5hbnRJZCI6ICIiLAogICJ1c2VNYW5hZ2VkSWRlbnRpdHlFeHRlbnNpb24iOiBmYWxzZSwKICAidXNlRmVkZXJhdGVkV29ya2xvYWRJZGVudGl0eUV4dGVuc2lvbiI6IGZhbHNlLAogICJzdWJzY3JpcHRpb25JZCI6ICIiLAogICJhYWRDbGllbnRJZCI6ICIiLAogICJhYWRDbGllbnRTZWNyZXQiOiAiIiwKICAiYWFkQ2xpZW50Q2VydFBhdGgiOiAiIiwKICAiYWFkRmVkZXJhdGVkVG9rZW5GaWxlIjogIiIsCiAgImFhZE1TSURhdGFQbGFuZUlkZW50aXR5UGF0aCI6ICIiLAogICJyZXNvdXJjZUdyb3VwIjogIiIsCiAgImxvY2F0aW9uIjogIiIsCiAgInZuZXROYW1lIjogIm15Vm5ldE5hbWUiLAogICJ2bmV0UmVzb3VyY2VHcm91cCI6ICJteVJlc291cmNlR3JvdXBOYW1lIiwKICAic3VibmV0TmFtZSI6ICJteVN1Ym5ldE5hbWUiLAogICJzZWN1cml0eUdyb3VwTmFtZSI6ICJteU5TR05hbWUiLAogICJzZWN1cml0eUdyb3VwUmVzb3VyY2VHcm91cCI6ICJteVJlc291cmNlR3JvdXBOYW1lIiwKICAicm91dGVUYWJsZU5hbWUiOiAiIiwKICAiY2xvdWRQcm92aWRlckJhY2tvZmYiOiB0cnVlLAogICJjbG91ZFByb3ZpZGVyQmFja29mZkR1cmF0aW9uIjogNiwKICAidXNlSW5zdGFuY2VNZXRhZGF0YSI6IHRydWUsCiAgImxvYWRCYWxhbmNlclNrdSI6ICJzdGFuZGFyZCIsCiAgImRpc2FibGVPdXRib3VuZFNOQVQiOiB0cnVlLAogICJsb2FkQmFsYW5jZXJOYW1lIjogIiIsCiAgImNsdXN0ZXJTZXJ2aWNlTG9hZEJhbGFuY2VySGVhbHRoUHJvYmVNb2RlIjogInNoYXJlZCIKfQ== + cloud.conf: ewogICJjbG91ZCI6ICIiLAogICJ0ZW5hbnRJZCI6ICIiLAogICJ1c2VNYW5hZ2VkSWRlbnRpdHlFeHRlbnNpb24iOiBmYWxzZSwKICAidXNlRmVkZXJhdGVkV29ya2xvYWRJZGVudGl0eUV4dGVuc2lvbiI6IHRydWUsCiAgInN1YnNjcmlwdGlvbklkIjogIiIsCiAgImFhZENsaWVudElkIjogIm15Q2xpZW50SUQiLAogICJhYWRDbGllbnRTZWNyZXQiOiAiIiwKICAiYWFkQ2xpZW50Q2VydFBhdGgiOiAiIiwKICAiYWFkRmVkZXJhdGVkVG9rZW5GaWxlIjogIi92YXIvcnVuL3NlY3JldHMvb3BlbnNoaWZ0L3NlcnZpY2VhY2NvdW50L3Rva2VuIiwKICAiYWFkTVNJRGF0YVBsYW5lSWRlbnRpdHlQYXRoIjogIiIsCiAgInJlc291cmNlR3JvdXAiOiAiIiwKICAibG9jYXRpb24iOiAiIiwKICAidm5ldE5hbWUiOiAibXlWbmV0TmFtZSIsCiAgInZuZXRSZXNvdXJjZUdyb3VwIjogIm15UmVzb3VyY2VHcm91cE5hbWUiLAogICJzdWJuZXROYW1lIjogIm15U3VibmV0TmFtZSIsCiAgInNlY3VyaXR5R3JvdXBOYW1lIjogIm15TlNHTmFtZSIsCiAgInNlY3VyaXR5R3JvdXBSZXNvdXJjZUdyb3VwIjogIm15UmVzb3VyY2VHcm91cE5hbWUiLAogICJyb3V0ZVRhYmxlTmFtZSI6ICIiLAogICJjbG91ZFByb3ZpZGVyQmFja29mZiI6IHRydWUsCiAgImNsb3VkUHJvdmlkZXJCYWNrb2ZmRHVyYXRpb24iOiA2LAogICJ1c2VJbnN0YW5jZU1ldGFkYXRhIjogdHJ1ZSwKICAibG9hZEJhbGFuY2VyU2t1IjogInN0YW5kYXJkIiwKICAiZGlzYWJsZU91dGJvdW5kU05BVCI6IHRydWUsCiAgImxvYWRCYWxhbmNlck5hbWUiOiAiIiwKICAiY2x1c3RlclNlcnZpY2VMb2FkQmFsYW5jZXJIZWFsdGhQcm9iZU1vZGUiOiAic2hhcmVkIgp9 kind: Secret metadata: name: azure-cloud-config diff --git a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/zz_fixture_TestControlPlaneComponents_azure_cloud_controller_manager_deployment.yaml b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/zz_fixture_TestControlPlaneComponents_azure_cloud_controller_manager_deployment.yaml index db98131c4780..355ee94448ad 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/zz_fixture_TestControlPlaneComponents_azure_cloud_controller_manager_deployment.yaml +++ b/control-plane-operator/controllers/hostedcontrolplane/testdata/azure-cloud-controller-manager/zz_fixture_TestControlPlaneComponents_azure_cloud_controller_manager_deployment.yaml @@ -25,7 +25,7 @@ spec: metadata: annotations: cluster-autoscaler.kubernetes.io/safe-to-evict-local-volumes: cloud-token,tmp-dir - component.hypershift.openshift.io/config-hash: 6390db5f + component.hypershift.openshift.io/config-hash: 5e25069a hypershift.openshift.io/release-image: quay.io/openshift-release-dev/ocp-release:4.16.10-x86_64 labels: app: cloud-controller-manager @@ -128,6 +128,7 @@ spec: - mountPath: /etc/kubernetes name: kubeconfig priorityClassName: hypershift-control-plane + serviceAccountName: azure-cloud-controller-manager tolerations: - effect: NoSchedule key: hypershift.openshift.io/control-plane diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/component.go b/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/component.go index 9aa87ef2839c..1c1e7acc341a 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/component.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/component.go @@ -90,9 +90,9 @@ func adaptServiceAccount(cpContext component.WorkloadContext, sa *corev1.Service } func isAroHCP(cpContext component.WorkloadContext) bool { - return azureutil.IsAroHCP() + return azureutil.IsAroHCPByHCP(cpContext.HCP) } func isSelfManagedAzure(cpContext component.WorkloadContext) bool { - return !azureutil.IsAroHCP() + return !azureutil.IsAroHCPByHCP(cpContext.HCP) } diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/config.go b/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/config.go index 060fee3aeb29..623c0adac07e 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/config.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/config.go @@ -43,7 +43,7 @@ func adaptConfigSecret(cpContext component.WorkloadContext, secret *corev1.Secre return err } - if azureutil.IsAroHCP() { + if azureutil.IsAroHCPByHCP(cpContext.HCP) { cfg.UseManagedIdentityExtension = false cfg.UseInstanceMetadata = false } @@ -58,7 +58,7 @@ func adaptConfigSecret(cpContext component.WorkloadContext, secret *corev1.Secre } func adaptSecretProvider(cpContext component.WorkloadContext, secretProvider *secretsstorev1.SecretProviderClass) error { - if azureutil.IsAroHCP() { + if azureutil.IsAroHCPByHCP(cpContext.HCP) { secretproviderclass.ReconcileManagedAzureSecretProviderClass(secretProvider, cpContext.HCP, cpContext.HCP.Spec.Platform.Azure.AzureAuthenticationConfig.ManagedIdentities.ControlPlane.CloudProvider) } return nil @@ -146,10 +146,10 @@ func azureConfig(cpContext component.WorkloadContext, withCredentials bool) (Azu } // Configure authentication method based on platform type - if azureutil.IsAroHCP() { + if azureutil.IsAroHCPByHCP(hcp) { // ARO HCP uses managed identity azureConfig.UseManagedIdentityExtension = true - } else if azureutil.IsSelfManagedAzure(hcp.Spec.Platform.Type) { + } else { // Self-managed Azure uses workload identity azureConfig.UseFederatedWorkloadIdentityExtension = true azureConfig.AADClientID = string(azureplatform.AzureAuthenticationConfig.WorkloadIdentities.CloudProvider.ClientID) @@ -157,7 +157,7 @@ func azureConfig(cpContext component.WorkloadContext, withCredentials bool) (Azu } if withCredentials { - if azureutil.IsAroHCP() { + if azureutil.IsAroHCPByHCP(hcp) { azureConfig.AADMSIDataPlaneIdentityPath = config.ManagedAzureCertificatePath + hcp.Spec.Platform.Azure.AzureAuthenticationConfig.ManagedIdentities.ControlPlane.CloudProvider.CredentialsSecretName } } diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/deployment.go b/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/deployment.go index 6e7b7da898e6..ecfd7c507294 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/deployment.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/azure/deployment.go @@ -21,18 +21,18 @@ func adaptDeployment(cpContext component.WorkloadContext, deployment *appsv1.Dep c.Args = append(c.Args, fmt.Sprintf("--cluster-name=%s", cpContext.HCP.Spec.InfraID), ) - if azureutil.IsAroHCP() { + if azureutil.IsAroHCPByHCP(cpContext.HCP) { c.VolumeMounts = append(c.VolumeMounts, azureutil.CreateVolumeMountForAzureSecretStoreProviderClass(config.ManagedAzureCloudProviderSecretStoreVolumeName), ) } }) - if azureutil.IsAroHCP() { + if azureutil.IsAroHCPByHCP(cpContext.HCP) { deployment.Spec.Template.Spec.Volumes = append(deployment.Spec.Template.Spec.Volumes, azureutil.CreateVolumeForAzureSecretStoreProviderClass(config.ManagedAzureCloudProviderSecretStoreVolumeName, config.ManagedAzureCloudProviderSecretProviderClassName), ) - } else if azureutil.IsSelfManagedAzure(cpContext.HCP.Spec.Platform.Type) { + } else { deployment.Spec.Template.Spec.ServiceAccountName = "azure-cloud-controller-manager" } diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/cno/component.go b/control-plane-operator/controllers/hostedcontrolplane/v2/cno/component.go index 5e8339902060..4cc4fdca2d53 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/cno/component.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/cno/component.go @@ -78,7 +78,7 @@ func NewComponent() component.ControlPlaneComponent { } func isAroHCP(cpContext component.WorkloadContext) bool { - return azureutil.IsAroHCP() + return azureutil.IsAroHCPByHCP(cpContext.HCP) } func SetRestartAnnotationAndPatch(ctx context.Context, crclient client.Client, dep *appsv1.Deployment, restartAnnotation string) error { diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/cno/deployment.go b/control-plane-operator/controllers/hostedcontrolplane/v2/cno/deployment.go index 52280d5b61e1..06bdeea9aec1 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/cno/deployment.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/cno/deployment.go @@ -149,7 +149,7 @@ func buildCNOEnvVars(cpContext component.WorkloadContext) ([]corev1.EnvVar, erro // For managed Azure deployments, we pass the env variables for: // - the SecretProviderClass for the Secrets Store CSI driver to use on the CNCC deployment // - the filepath of the credentials - if azureutil.IsAroHCP() { + if azureutil.IsAroHCPByHCP(hcp) { cnoEnv = append(cnoEnv, corev1.EnvVar{ Name: config.ManagedAzureSecretProviderClassEnvVarKey, diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/controlplaneoperator/deployment.go b/control-plane-operator/controllers/hostedcontrolplane/v2/controlplaneoperator/deployment.go index 784b3a2201c1..bc5d45096642 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/controlplaneoperator/deployment.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/controlplaneoperator/deployment.go @@ -212,7 +212,7 @@ func (cpo *ControlPlaneOperatorOptions) applyPlatformSpecificConfig(hcp *hyperv1 MountPath: "/etc/provider", }) case hyperv1.AzurePlatform: - if azureutil.IsAroHCP() { + if azureutil.IsAroHCPByHCP(hcp) { // Add the client ID of the managed Azure key vault as an environment variable on the CPO. This is used in // configuring the SecretProviderClass CRs for OpenShift components on the HCP needing to authenticate with // Azure cloud API. @@ -243,7 +243,7 @@ func (cpo *ControlPlaneOperatorOptions) applyPlatformSpecificConfig(hcp *hyperv1 azureutil.CreateVolumeForAzureSecretStoreProviderClass(config.ManagedAzureKMSSecretStoreVolumeName, config.ManagedAzureKMSSecretProviderClassName), ) } - } else if azureutil.IsSelfManagedAzure(hcp.Spec.Platform.Type) { + } else { if hcp.Spec.Platform.Azure.AzureAuthenticationConfig.WorkloadIdentities != nil && hcp.Spec.Platform.Azure.AzureAuthenticationConfig.WorkloadIdentities.ControlPlaneOperator.ClientID != "" { deployment.Spec.Template.Spec.Containers[0].Env = append( diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/controlplaneoperator/role.go b/control-plane-operator/controllers/hostedcontrolplane/v2/controlplaneoperator/role.go index 80be837a34dc..7181d4c1ab2d 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/controlplaneoperator/role.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/controlplaneoperator/role.go @@ -39,7 +39,7 @@ func adaptRole(cpContext component.WorkloadContext, role *rbacv1.Role) error { }) } - if azureutil.IsAroHCP() { + if azureutil.IsAroHCPByHCP(cpContext.HCP) { role.Rules = append(role.Rules, rbacv1.PolicyRule{ APIGroups: []string{"secrets-store.csi.x-k8s.io"}, Resources: []string{"secretproviderclasses"}, diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/component.go b/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/component.go index ec8817b57d09..937c0b4f0c03 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/component.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/component.go @@ -87,5 +87,5 @@ func isIngressCapabilityEnabled(cpContext component.WorkloadContext) (bool, erro } func isAroHCP(cpContext component.WorkloadContext) bool { - return azureutil.IsAroHCP() + return azureutil.IsAroHCPByHCP(cpContext.HCP) } diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/deployment.go b/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/deployment.go index 22a47e4fc74f..0dc88d90813b 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/deployment.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/ingressoperator/deployment.go @@ -32,7 +32,7 @@ func adaptDeployment(cpContext component.WorkloadContext, deployment *appsv1.Dep // we authenticate with Azure API through UserAssignedCredential authentication. We also mount the // SecretProviderClass for the Secrets Store CSI driver to use; it will grab the JSON object stored in the // MANAGED_AZURE_HCP_CREDENTIALS_FILE_PATH and mount it as a volume in the ingress pod in the path. - if azureutil.IsAroHCP() { + if azureutil.IsAroHCPByHCP(cpContext.HCP) { c.Env = append(c.Env, azureutil.CreateEnvVarsForAzureManagedIdentity(cpContext.HCP.Spec.Platform.Azure.AzureAuthenticationConfig.ManagedIdentities.ControlPlane.Ingress.CredentialsSecretName)...) diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/kas/component.go b/control-plane-operator/controllers/hostedcontrolplane/v2/kas/component.go index d28a7c380f30..404cd9ff81f7 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/kas/component.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/kas/component.go @@ -130,7 +130,7 @@ func NewComponent() component.ControlPlaneComponent { func enableAzureKMSSecretProvider(cpContext component.WorkloadContext) bool { if cpContext.HCP.Spec.SecretEncryption != nil && cpContext.HCP.Spec.SecretEncryption.KMS != nil && cpContext.HCP.Spec.SecretEncryption.Type == hyperv1.KMS { - return azureutil.IsAroHCP() + return azureutil.IsAroHCPByHCP(cpContext.HCP) } return false } diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/kas/deployment.go b/control-plane-operator/controllers/hostedcontrolplane/v2/kas/deployment.go index ffa76be98433..5737367793c5 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/kas/deployment.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/kas/deployment.go @@ -139,7 +139,7 @@ func adaptDeployment(cpContext component.WorkloadContext, deployment *appsv1.Dep // sidecar resolves the Key Vault FQDN to the private-router Service ClusterIP. // The private router has access to the customer VNet (via Swift) and can reach the // Key Vault's private endpoint, acting as a TCP passthrough relay. - if azureutil.IsAroHCP() && azureutil.IsPrivateKeyVault(hcp) { + if azureutil.IsAroHCPByHCP(hcp) && azureutil.IsPrivateKeyVault(hcp) { kvFQDN, err := azureutil.GetKeyVaultFQDN(hcp) if err != nil { return fmt.Errorf("failed to get Key Vault FQDN for hostAlias: %w", err) diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/registryoperator/component.go b/control-plane-operator/controllers/hostedcontrolplane/v2/registryoperator/component.go index 5d56595c0caf..144a54c8c3d4 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/registryoperator/component.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/registryoperator/component.go @@ -64,5 +64,5 @@ func isImageRegistryCapabilityEnabled(cpContext component.WorkloadContext) (bool } func isAroHCP(cpContext component.WorkloadContext) bool { - return azureutil.IsAroHCP() + return azureutil.IsAroHCPByHCP(cpContext.HCP) } diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/registryoperator/deployment.go b/control-plane-operator/controllers/hostedcontrolplane/v2/registryoperator/deployment.go index eb251f7e6716..aae5460c91c1 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/registryoperator/deployment.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/registryoperator/deployment.go @@ -28,7 +28,7 @@ func adaptDeployment(cpContext component.WorkloadContext, deployment *appsv1.Dep // we authenticate with Azure API through UserAssignedCredential authentication. We also mount the // SecretProviderClass for the Secrets Store CSI driver to use; it will grab the JSON object stored in the // MANAGED_AZURE_HCP_CREDENTIALS_FILE_PATH and mount it as a volume in the image registry pod in the path. - if azureutil.IsAroHCP() { + if azureutil.IsAroHCPByHCP(cpContext.HCP) { c.Env = append(c.Env, azureutil.CreateEnvVarsForAzureManagedIdentity(cpContext.HCP.Spec.Platform.Azure.AzureAuthenticationConfig.ManagedIdentities.ControlPlane.ImageRegistry.CredentialsSecretName)...) diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/router/config.go b/control-plane-operator/controllers/hostedcontrolplane/v2/router/config.go index dea8a7520532..d8a5d4120b88 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/router/config.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/router/config.go @@ -62,7 +62,7 @@ func adaptConfig(cpContext component.WorkloadContext, cm *corev1.ConfigMap) erro } var keyVaultFQDN string - if azureutil.IsAroHCP() && azureutil.IsPrivateKeyVault(cpContext.HCP) { + if azureutil.IsAroHCPByHCP(cpContext.HCP) && azureutil.IsPrivateKeyVault(cpContext.HCP) { kvFQDN, err := azureutil.GetKeyVaultFQDN(cpContext.HCP) if err != nil { return fmt.Errorf("failed to get Key Vault FQDN: %w", err) diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/router/deployment.go b/control-plane-operator/controllers/hostedcontrolplane/v2/router/deployment.go index 205e96ec02ba..2d360a734061 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/router/deployment.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/router/deployment.go @@ -1,18 +1,18 @@ package router import ( - hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1" component "github.com/openshift/hypershift/support/controlplane-component" + "github.com/openshift/hypershift/support/util" appsv1 "k8s.io/api/apps/v1" ) func adaptDeployment(cpContext component.WorkloadContext, deployment *appsv1.Deployment) error { - if swiftPodNetworkInstance := cpContext.HCP.Annotations[hyperv1.SwiftPodNetworkInstanceAnnotation]; swiftPodNetworkInstance != "" { + if pni := util.SwiftPodNetworkInstanceHCP(cpContext.HCP); pni != "" { if deployment.Spec.Template.Labels == nil { deployment.Spec.Template.Labels = map[string]string{} } - deployment.Spec.Template.Labels["kubernetes.azure.com/pod-network-instance"] = swiftPodNetworkInstance + deployment.Spec.Template.Labels["kubernetes.azure.com/pod-network-instance"] = pni } return nil diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/router/util/util.go b/control-plane-operator/controllers/hostedcontrolplane/v2/router/util/util.go index d5d97e1e88b7..0fcbaa7341b2 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/router/util/util.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/router/util/util.go @@ -2,7 +2,6 @@ package util import ( hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1" - "github.com/openshift/hypershift/support/azureutil" "github.com/openshift/hypershift/support/util" ) @@ -17,11 +16,10 @@ func UseHCPRouter(hcp *hyperv1.HostedControlPlane) bool { if hcp.Spec.Platform.Type == hyperv1.IBMCloudPlatform { return false } - // For ARO HCP, the dedicated HCP router is only needed when the cluster is private - // (Swift enabled). LabelHCPRoutes returns true for all ARO to support the - // SharedIngressReconciler, but that doesn't mean a dedicated router deployment is needed. - if azureutil.IsAroHCP() { - return util.IsPrivateHCP(hcp) + // SharedIngress handles public routing for ARO-HCP; a dedicated HCP + // router is only needed when the cluster also has private access. + if util.UseSharedIngressHCP(hcp) && !util.IsPrivateHCP(hcp) { + return false } // Router infrastructure is needed when: // 1. Cluster has private access (Private or PublicAndPrivate) - for internal routes, OR diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/storage/azure.go b/control-plane-operator/controllers/hostedcontrolplane/v2/storage/azure.go index 5b6ba52bd1b1..4bf3381dadd4 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/storage/azure.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/storage/azure.go @@ -28,9 +28,9 @@ func adaptAzureCSISecret(cpContext component.WorkloadContext, managedIdentity hy Location: azureSpec.Location, } - if azureutil.IsAroHCP() { + if azureutil.IsAroHCPByHCP(cpContext.HCP) { azureConfig.AADMSIDataPlaneIdentityPath = path.Join(hyperconfig.ManagedAzureCertificatePath, managedIdentity.CredentialsSecretName) - } else if azureutil.IsSelfManagedAzure(cpContext.HCP.Spec.Platform.Type) { + } else { azureConfig.UseFederatedWorkloadIdentityExtension = true azureConfig.AADClientID = string(workloadIdentity.ClientID) azureConfig.AADFederatedTokenFile = "/var/run/secrets/openshift/serviceaccount/token" @@ -55,9 +55,9 @@ func adaptAzureCSISecret(cpContext component.WorkloadContext, managedIdentity hy func adaptAzureCSIDiskSecret(cpContext component.WorkloadContext, secret *corev1.Secret) error { var managedIdentity hyperv1.ManagedIdentity var workloadIdentity hyperv1.WorkloadIdentity - if azureutil.IsAroHCP() { + if azureutil.IsAroHCPByHCP(cpContext.HCP) { managedIdentity = cpContext.HCP.Spec.Platform.Azure.AzureAuthenticationConfig.ManagedIdentities.ControlPlane.Disk - } else if azureutil.IsSelfManagedAzure(cpContext.HCP.Spec.Platform.Type) { + } else { workloadIdentity = cpContext.HCP.Spec.Platform.Azure.AzureAuthenticationConfig.WorkloadIdentities.Disk } return adaptAzureCSISecret(cpContext, managedIdentity, workloadIdentity, secret) @@ -72,9 +72,9 @@ func adaptAzureCSIDiskSecretProvider(cpContext component.WorkloadContext, secret func adaptAzureCSIFileSecret(cpContext component.WorkloadContext, secret *corev1.Secret) error { var managedIdentity hyperv1.ManagedIdentity var workloadIdentity hyperv1.WorkloadIdentity - if azureutil.IsAroHCP() { + if azureutil.IsAroHCPByHCP(cpContext.HCP) { managedIdentity = cpContext.HCP.Spec.Platform.Azure.AzureAuthenticationConfig.ManagedIdentities.ControlPlane.File - } else if azureutil.IsSelfManagedAzure(cpContext.HCP.Spec.Platform.Type) { + } else { workloadIdentity = cpContext.HCP.Spec.Platform.Azure.AzureAuthenticationConfig.WorkloadIdentities.File } return adaptAzureCSISecret(cpContext, managedIdentity, workloadIdentity, secret) diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/storage/component.go b/control-plane-operator/controllers/hostedcontrolplane/v2/storage/component.go index 30a6f907c308..26076ad8e33a 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/storage/component.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/storage/component.go @@ -83,7 +83,7 @@ func isStorageAndCSIManaged(cpContext component.WorkloadContext) (bool, error) { } func isAroHCP(cpContext component.WorkloadContext) bool { - return azureutil.IsAroHCP() + return azureutil.IsAroHCPByHCP(cpContext.HCP) } type operand struct { diff --git a/control-plane-operator/controllers/hostedcontrolplane/v2/storage/deployment.go b/control-plane-operator/controllers/hostedcontrolplane/v2/storage/deployment.go index 48b7032acd72..7ead8b8be064 100644 --- a/control-plane-operator/controllers/hostedcontrolplane/v2/storage/deployment.go +++ b/control-plane-operator/controllers/hostedcontrolplane/v2/storage/deployment.go @@ -20,7 +20,7 @@ func adaptDeployment(cpContext component.WorkloadContext, deployment *appsv1.Dep // For managed Azure, we need to supply a couple of environment variables for CSO to pass on to the CSI controllers for disk and file. // CSO passes those on to the CSI deployment here - https://github.com/openshift/cluster-storage-operator/pull/517/files. // CSI then mounts the Secrets Provider Class here - https://github.com/openshift/csi-operator/pull/309/files. - if azureutil.IsAroHCP() { + if azureutil.IsAroHCPByHCP(cpContext.HCP) { c.Env = append(c.Env, corev1.EnvVar{ Name: "ARO_HCP_SECRET_PROVIDER_CLASS_FOR_DISK", diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go b/control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go index cf15304789c6..969ac71eac12 100644 --- a/control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go +++ b/control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.go @@ -1303,7 +1303,7 @@ func (r *reconciler) reconcileRBAC(ctx context.Context, hcp *hyperv1.HostedContr manifestAndReconcile[*rbacv1.RoleBinding]{manifest: manifests.KASConnectionCheckerRoleBinding, reconcile: rbac.ReconcileKASConnectionCheckerRoleBinding}, } - if azureutil.IsAroHCP() { + if azureutil.IsAroHCPByHCP(hcp) { rbacReconciler = append(rbacReconciler, manifestAndReconcile[*rbacv1.ClusterRole]{manifest: manifests.AzureDiskCSIDriverNodeServiceAccountRole, reconcile: rbac.ReconcileAzureDiskCSIDriverNodeServiceAccountClusterRole}, manifestAndReconcile[*rbacv1.ClusterRoleBinding]{manifest: manifests.AzureDiskCSIDriverNodeServiceAccountRoleBinding, reconcile: rbac.ReconcileAzureDiskCSIDriverNodeServiceAccountClusterRoleBinding}, @@ -1456,7 +1456,7 @@ func (r *reconciler) reconcileAuthOIDC(ctx context.Context, hcp *hyperv1.HostedC errs = append(errs, fmt.Errorf("failed to get OIDCClient secret %s: %w", oidcClient.ClientSecret.Name, err)) continue } - if azureutil.IsAroHCP() && util.HasAnnotationWithValue(&src, hyperv1.HostedClusterSourcedAnnotation, "true") { + if azureutil.IsAroHCPByHCP(hcp) && util.HasAnnotationWithValue(&src, hyperv1.HostedClusterSourcedAnnotation, "true") { // This is a day-2 secret. We shouldn't copy it, instead it'll be provided by the end-user on the hosted cluster. continue } @@ -2126,7 +2126,7 @@ func (r *reconciler) reconcileCloudCredentialSecrets(ctx context.Context, hcp *h } // Set up the operand credentials for either managed or self-managed Azure environments - errs = azureresources.SetupOperandCredentials(ctx, r.client, r.CreateOrUpdateProvider, hcp, secretData, azureutil.IsAroHCP()) + errs = azureresources.SetupOperandCredentials(ctx, r.client, r.CreateOrUpdateProvider, hcp, secretData, azureutil.IsAroHCPByHCP(hcp)) if len(errs) > 0 { return errs } @@ -3400,7 +3400,7 @@ func (r *reconciler) reconcileStorage(ctx context.Context, hcp *hyperv1.HostedCo operatorv1.ManilaCSIDriver, } case hyperv1.AzurePlatform: - if azureutil.IsSelfManagedAzure(hcp.Spec.Platform.Type) { + if !azureutil.IsAroHCPByHCP(hcp) { driverNames = []operatorv1.CSIDriverName{ operatorv1.AzureDiskCSIDriver, operatorv1.AzureFileCSIDriver, diff --git a/control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources_test.go b/control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources_test.go index ab476e6f6afc..1bf13ff11914 100644 --- a/control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources_test.go +++ b/control-plane-operator/hostedclusterconfigoperator/controllers/resources/resources_test.go @@ -1930,6 +1930,20 @@ func TestReconcileAuthOIDC(t *testing.T) { Namespace: testNamespace, }, Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "test-pni", + }, + }, + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeManagedIdentities, + }, + }, + }, Configuration: &hyperv1.ClusterConfiguration{ Authentication: &configv1.AuthenticationSpec{ Type: configv1.AuthenticationTypeOIDC, @@ -2029,6 +2043,20 @@ func TestReconcileAuthOIDC(t *testing.T) { Namespace: testNamespace, }, Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "test-pni", + }, + }, + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeManagedIdentities, + }, + }, + }, Configuration: &hyperv1.ClusterConfiguration{ Authentication: &configv1.AuthenticationSpec{ Type: configv1.AuthenticationTypeOIDC, diff --git a/docs/content/reference/aggregated-docs.md b/docs/content/reference/aggregated-docs.md index 84276ddfcdc8..65aa3f381f04 100644 --- a/docs/content/reference/aggregated-docs.md +++ b/docs/content/reference/aggregated-docs.md @@ -34796,8 +34796,7 @@ in the format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

AzurePrivateSpec configures private connectivity to an Azure hosted cluster’s API server. It is a discriminated union keyed on the type field, which selects the private connectivity -mechanism. Currently only PrivateLink is supported; additional mechanisms (e.g., Swift) may -be added in the future.

+mechanism.

@@ -34819,6 +34818,7 @@ AzurePrivateType @@ -34837,6 +34837,23 @@ AzurePrivateLinkSpec This field is required when type is “PrivateLink” and must not be set otherwise.

+ + + +

type specifies the private connectivity mechanism used for the hosted cluster’s API server. “PrivateLink” selects Azure Private Link Service for private API server access. +“Swift” selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set.

+swift,omitzero
+ + +AzureSwiftSpec + + +
+(Optional) +

swift configures Azure Swift pod networking for private API server access. +Swift networking requires the management cluster to be pre-configured with +Azure Swift support; this is not provisioned by HyperShift automatically. +This field is required when type is “Swift” and must not be set otherwise.

+
###AzurePrivateType { #hypershift.openshift.io/v1beta1.AzurePrivateType } @@ -34860,6 +34877,12 @@ hosted cluster’s API server. This acts as the discriminator for the AzureP In this mode, the operator creates a Private Link Service backed by the management cluster’s internal load balancer, and a Private Endpoint in the guest VNet for private API server access.

+

"Swift"

+

AzurePrivateTypeSwift specifies private connectivity using Azure Swift pod networking. +In this mode, Azure Swift assigns a private IP from the customer VNet directly +to the hosted cluster’s router pods, providing private API server access without a +separate Private Link Service. This is used by ARO HCP managed clusters.

+ ###AzureResourceManagedIdentities { #hypershift.openshift.io/v1beta1.AzureResourceManagedIdentities } @@ -34932,6 +34955,42 @@ The expected format is:

Must be exactly 36 characters consisting of hexadecimal digits [0-9a-fA-F] and hyphens in the format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (e.g., “550e8400-e29b-41d4-a716-446655440000”).

+###AzureSwiftSpec { #hypershift.openshift.io/v1beta1.AzureSwiftSpec } +

+(Appears on: +AzurePrivateSpec) +

+

+

AzureSwiftSpec configures Azure Swift pod networking for private API server access. +Swift assigns a private IP from the customer VNet directly to the hosted cluster’s +router pods, providing private connectivity without a separate Private Link Service.

+

+ + + + + + + + + + + + + +
FieldDescription
+podNetworkInstance
+ +string + +
+

podNetworkInstance is the name of a PodNetworkInstance custom resource in the +hosted control plane namespace. This resource configures Azure Swift pod networking +for private connectivity to the hosted cluster’s router pods. +The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase +alphanumeric characters or hyphens, must start and end with an alphanumeric character. +This field is immutable once set.

+
###AzureTopologyType { #hypershift.openshift.io/v1beta1.AzureTopologyType }

(Appears on: diff --git a/docs/content/reference/api.md b/docs/content/reference/api.md index 023503430cfb..1529b011fe36 100644 --- a/docs/content/reference/api.md +++ b/docs/content/reference/api.md @@ -4345,8 +4345,7 @@ in the format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

AzurePrivateSpec configures private connectivity to an Azure hosted cluster’s API server. It is a discriminated union keyed on the type field, which selects the private connectivity -mechanism. Currently only PrivateLink is supported; additional mechanisms (e.g., Swift) may -be added in the future.

+mechanism.

@@ -4368,6 +4367,7 @@ AzurePrivateType @@ -4386,6 +4386,23 @@ AzurePrivateLinkSpec This field is required when type is “PrivateLink” and must not be set otherwise.

+ + + +

type specifies the private connectivity mechanism used for the hosted cluster’s API server. “PrivateLink” selects Azure Private Link Service for private API server access. +“Swift” selects Azure Swift pod networking for private API server access, used by ARO HCP. This field is immutable once set.

+swift,omitzero
+ + +AzureSwiftSpec + + +
+(Optional) +

swift configures Azure Swift pod networking for private API server access. +Swift networking requires the management cluster to be pre-configured with +Azure Swift support; this is not provisioned by HyperShift automatically. +This field is required when type is “Swift” and must not be set otherwise.

+
###AzurePrivateType { #hypershift.openshift.io/v1beta1.AzurePrivateType } @@ -4409,6 +4426,12 @@ hosted cluster’s API server. This acts as the discriminator for the AzureP In this mode, the operator creates a Private Link Service backed by the management cluster’s internal load balancer, and a Private Endpoint in the guest VNet for private API server access.

+

"Swift"

+

AzurePrivateTypeSwift specifies private connectivity using Azure Swift pod networking. +In this mode, Azure Swift assigns a private IP from the customer VNet directly +to the hosted cluster’s router pods, providing private API server access without a +separate Private Link Service. This is used by ARO HCP managed clusters.

+ ###AzureResourceManagedIdentities { #hypershift.openshift.io/v1beta1.AzureResourceManagedIdentities } @@ -4481,6 +4504,42 @@ The expected format is:

Must be exactly 36 characters consisting of hexadecimal digits [0-9a-fA-F] and hyphens in the format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (e.g., “550e8400-e29b-41d4-a716-446655440000”).

+###AzureSwiftSpec { #hypershift.openshift.io/v1beta1.AzureSwiftSpec } +

+(Appears on: +AzurePrivateSpec) +

+

+

AzureSwiftSpec configures Azure Swift pod networking for private API server access. +Swift assigns a private IP from the customer VNet directly to the hosted cluster’s +router pods, providing private connectivity without a separate Private Link Service.

+

+ + + + + + + + + + + + + +
FieldDescription
+podNetworkInstance
+ +string + +
+

podNetworkInstance is the name of a PodNetworkInstance custom resource in the +hosted control plane namespace. This resource configures Azure Swift pod networking +for private connectivity to the hosted cluster’s router pods. +The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase +alphanumeric characters or hyphens, must start and end with an alphanumeric character. +This field is immutable once set.

+
###AzureTopologyType { #hypershift.openshift.io/v1beta1.AzureTopologyType }

(Appears on: diff --git a/support/azureutil/azureutil.go b/support/azureutil/azureutil.go index e11580efe81c..686f487e33d4 100644 --- a/support/azureutil/azureutil.go +++ b/support/azureutil/azureutil.go @@ -12,6 +12,7 @@ import ( hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1" "github.com/openshift/hypershift/support/config" "github.com/openshift/hypershift/support/upsert" + "github.com/openshift/hypershift/support/util" "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" @@ -260,11 +261,23 @@ func IsPrivateKeyVault(hcp *hyperv1.HostedControlPlane) bool { return hcp.Spec.SecretEncryption.KMS.Azure.KeyVaultAccess == hyperv1.AzureKeyVaultPrivate } -// IsAroHCP returns true if the managed service environment variable is set to ARO-HCP +// IsAroHCP returns true if the managed service environment variable is set to ARO-HCP. +// Use this only for management-cluster-level decisions where no HC/HCP context is available. +// For per-cluster decisions, use IsAroHCPByHCP or IsAroHCPByHC instead. func IsAroHCP() bool { return os.Getenv("MANAGED_SERVICE") == hyperv1.AroHCP } +// IsAroHCPByHCP returns true when this HCP belongs to an ARO-managed cluster. +func IsAroHCPByHCP(hcp *hyperv1.HostedControlPlane) bool { + return util.IsAroHCPByHCP(hcp) +} + +// IsAroHCPByHC returns true when this HostedCluster belongs to an ARO-managed cluster. +func IsAroHCPByHC(hc *hyperv1.HostedCluster) bool { + return util.IsAroHCPByHC(hc) +} + // IsSelfManagedAzure returns true when the platform is Azure and the managed service is not ARO-HCP func IsSelfManagedAzure(platform hyperv1.PlatformType) bool { return platform == hyperv1.AzurePlatform && !IsAroHCP() diff --git a/support/azureutil/azureutil_test.go b/support/azureutil/azureutil_test.go index e81deea5b4a2..6987c36bb1b2 100644 --- a/support/azureutil/azureutil_test.go +++ b/support/azureutil/azureutil_test.go @@ -188,6 +188,193 @@ func TestIsAroHCP(t *testing.T) { } } +func TestIsAroHCPByHCP(t *testing.T) { + tests := []struct { + name string + hcp *hyperv1.HostedControlPlane + envVar string + expected bool + }{ + { + name: "When AzureAuthenticationConfigType is ManagedIdentities it should return true", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeManagedIdentities, + }, + }, + }, + }, + }, + expected: true, + }, + { + name: "When AzureAuthenticationConfigType is WorkloadIdentities it should return false", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeWorkloadIdentities, + }, + }, + }, + }, + }, + expected: false, + }, + { + name: "When platform is not Azure it should return false", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AWSPlatform, + }, + }, + }, + expected: false, + }, + { + name: "When Azure spec is nil it should fall back to env var", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + }, + }, + }, + envVar: hyperv1.AroHCP, + expected: true, + }, + { + name: "When Azure spec is nil and env var is not set it should return false", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + }, + }, + }, + expected: false, + }, + { + name: "When WorkloadIdentities with ARO HCP env var it should return false because API takes precedence", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeWorkloadIdentities, + }, + }, + }, + }, + }, + envVar: hyperv1.AroHCP, + expected: false, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + g := NewGomegaWithT(t) + if tc.envVar != "" { + t.Setenv("MANAGED_SERVICE", tc.envVar) + } + g.Expect(IsAroHCPByHCP(tc.hcp)).To(Equal(tc.expected)) + }) + } +} + +func TestIsAroHCPByHC(t *testing.T) { + tests := []struct { + name string + hc *hyperv1.HostedCluster + envVar string + expected bool + }{ + { + name: "When AzureAuthenticationConfigType is ManagedIdentities it should return true", + hc: &hyperv1.HostedCluster{ + Spec: hyperv1.HostedClusterSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeManagedIdentities, + }, + }, + }, + }, + }, + expected: true, + }, + { + name: "When AzureAuthenticationConfigType is WorkloadIdentities it should return false", + hc: &hyperv1.HostedCluster{ + Spec: hyperv1.HostedClusterSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeWorkloadIdentities, + }, + }, + }, + }, + }, + expected: false, + }, + { + name: "When platform is not Azure it should return false", + hc: &hyperv1.HostedCluster{ + Spec: hyperv1.HostedClusterSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AWSPlatform, + }, + }, + }, + expected: false, + }, + { + name: "When Azure spec is nil it should fall back to env var", + hc: &hyperv1.HostedCluster{ + Spec: hyperv1.HostedClusterSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + }, + }, + }, + envVar: hyperv1.AroHCP, + expected: true, + }, + { + name: "When Azure spec is nil and env var is not set it should return false", + hc: &hyperv1.HostedCluster{ + Spec: hyperv1.HostedClusterSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + }, + }, + }, + expected: false, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + g := NewGomegaWithT(t) + if tc.envVar != "" { + t.Setenv("MANAGED_SERVICE", tc.envVar) + } + g.Expect(IsAroHCPByHC(tc.hc)).To(Equal(tc.expected)) + }) + } +} + func TestIsPrivateKeyVault(t *testing.T) { tests := []struct { name string diff --git a/support/util/visibility.go b/support/util/visibility.go index c19b3e20cec7..bd0fcaaa362d 100644 --- a/support/util/visibility.go +++ b/support/util/visibility.go @@ -5,6 +5,7 @@ import ( hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1" + "k8s.io/klog/v2" "k8s.io/utils/ptr" ) @@ -14,25 +15,109 @@ func isAroHCP() bool { return os.Getenv(managedServiceEnvVar) == hyperv1.AroHCP } -func IsPrivateHCP(hcp *hyperv1.HostedControlPlane) bool { - // ARO always have swift enabled. - // We still check the annotation to keep CI working. - // TODO(alberto): Remove this once CI has swift enabled. +// UseSwiftNetworkingHCP returns true when the HCP uses Azure Swift pod networking. +// Checks the Private.Type API field first; falls back to env var + annotation +// for unmigrated clusters during the Phase 1 migration window. +func UseSwiftNetworkingHCP(hcp *hyperv1.HostedControlPlane) bool { + if hcp.Spec.Platform.Type != hyperv1.AzurePlatform { + return false + } + azure := ptr.Deref(hcp.Spec.Platform.Azure, hyperv1.AzurePlatformSpec{}) + if azure.Private.Type == hyperv1.AzurePrivateTypeSwift { + return true + } if isAroHCP() && hcp.Annotations[hyperv1.SwiftPodNetworkInstanceAnnotation] != "" { + klog.V(2).Info("Using legacy annotation fallback for Swift networking detection on HostedControlPlane", "namespace", hcp.Namespace, "name", hcp.Name) return true } + return false +} + +// UseSwiftNetworkingHC returns true when the HostedCluster uses Azure Swift pod networking. +func UseSwiftNetworkingHC(hc *hyperv1.HostedCluster) bool { + if hc.Spec.Platform.Type != hyperv1.AzurePlatform { + return false + } + azure := ptr.Deref(hc.Spec.Platform.Azure, hyperv1.AzurePlatformSpec{}) + if azure.Private.Type == hyperv1.AzurePrivateTypeSwift { + return true + } + if isAroHCP() && hc.Annotations[hyperv1.SwiftPodNetworkInstanceAnnotation] != "" { + klog.V(2).Info("Using legacy annotation fallback for Swift networking detection on HostedCluster", "namespace", hc.Namespace, "name", hc.Name) + return true + } + return false +} + +// IsAroHCPByHCP returns true when this HCP belongs to an ARO-managed cluster. +// Checks AzureAuthenticationConfigType == ManagedIdentities as the per-cluster +// API indicator. Falls back to the MANAGED_SERVICE env var when the Azure spec +// is nil (unmigrated clusters during Phase 1). +func IsAroHCPByHCP(hcp *hyperv1.HostedControlPlane) bool { + if hcp.Spec.Platform.Type != hyperv1.AzurePlatform { + return false + } + azure := hcp.Spec.Platform.Azure + if azure != nil { + return azure.AzureAuthenticationConfig.AzureAuthenticationConfigType == hyperv1.AzureAuthenticationTypeManagedIdentities + } + return isAroHCP() +} + +// IsAroHCPByHC returns true when this HostedCluster belongs to an ARO-managed cluster. +func IsAroHCPByHC(hc *hyperv1.HostedCluster) bool { + if hc.Spec.Platform.Type != hyperv1.AzurePlatform { + return false + } + azure := hc.Spec.Platform.Azure + if azure != nil { + return azure.AzureAuthenticationConfig.AzureAuthenticationConfigType == hyperv1.AzureAuthenticationTypeManagedIdentities + } + return isAroHCP() +} + +// UseSharedIngressHCP returns true when this specific HCP should use the +// management cluster's shared ingress (HAProxy) for public endpoints. +// IsAroHCPByHCP includes an env var fallback for unmigrated clusters. +func UseSharedIngressHCP(hcp *hyperv1.HostedControlPlane) bool { + return IsAroHCPByHCP(hcp) && IsPublicHCP(hcp) +} + +// UseSharedIngressHC returns true when this specific HostedCluster should use +// the management cluster's shared ingress for public endpoints. +func UseSharedIngressHC(hc *hyperv1.HostedCluster) bool { + return IsAroHCPByHC(hc) && IsPublicHC(hc) +} + +// SwiftPodNetworkInstanceHCP returns the Swift pod network instance name for +// the HCP. Checks the API field first; falls back to the annotation for +// unmigrated clusters. +func SwiftPodNetworkInstanceHCP(hcp *hyperv1.HostedControlPlane) string { + if hcp.Spec.Platform.Type != hyperv1.AzurePlatform { + return "" + } + azure := ptr.Deref(hcp.Spec.Platform.Azure, hyperv1.AzurePlatformSpec{}) + if azure.Private.Type == hyperv1.AzurePrivateTypeSwift { + return azure.Private.Swift.PodNetworkInstance + } + return hcp.Annotations[hyperv1.SwiftPodNetworkInstanceAnnotation] +} + +func IsPrivateHCP(hcp *hyperv1.HostedControlPlane) bool { if hcp.Spec.Platform.Type == hyperv1.AWSPlatform { access := ptr.Deref(hcp.Spec.Platform.AWS, hyperv1.AWSPlatformSpec{}).EndpointAccess return access == hyperv1.PublicAndPrivate || access == hyperv1.Private } - if hcp.Spec.Platform.Type == hyperv1.GCPPlatform { access := ptr.Deref(hcp.Spec.Platform.GCP, hyperv1.GCPPlatformSpec{}).EndpointAccess return access == hyperv1.GCPEndpointAccessPublicAndPrivate || access == hyperv1.GCPEndpointAccessPrivate } if hcp.Spec.Platform.Type == hyperv1.AzurePlatform { topology := ptr.Deref(hcp.Spec.Platform.Azure, hyperv1.AzurePlatformSpec{}).Topology - return topology == hyperv1.AzureTopologyPublicAndPrivate || topology == hyperv1.AzureTopologyPrivate + if topology != "" { + return topology == hyperv1.AzureTopologyPublicAndPrivate || topology == hyperv1.AzureTopologyPrivate + } + return UseSwiftNetworkingHCP(hcp) } return false } @@ -54,12 +139,6 @@ func IsPublicHCP(hcp *hyperv1.HostedControlPlane) bool { } func IsPrivateHC(hc *hyperv1.HostedCluster) bool { - // ARO always have swift enabled. - // We still check the annotation to keep CI working. - // TODO(alberto): Remove this once CI has swift enabled. - if isAroHCP() && hc.Annotations[hyperv1.SwiftPodNetworkInstanceAnnotation] != "" { - return true - } if hc.Spec.Platform.Type == hyperv1.AWSPlatform { access := ptr.Deref(hc.Spec.Platform.AWS, hyperv1.AWSPlatformSpec{}).EndpointAccess return access == hyperv1.PublicAndPrivate || access == hyperv1.Private @@ -70,7 +149,10 @@ func IsPrivateHC(hc *hyperv1.HostedCluster) bool { } if hc.Spec.Platform.Type == hyperv1.AzurePlatform { topology := ptr.Deref(hc.Spec.Platform.Azure, hyperv1.AzurePlatformSpec{}).Topology - return topology == hyperv1.AzureTopologyPublicAndPrivate || topology == hyperv1.AzureTopologyPrivate + if topology != "" { + return topology == hyperv1.AzureTopologyPublicAndPrivate || topology == hyperv1.AzureTopologyPrivate + } + return UseSwiftNetworkingHC(hc) } return false } @@ -92,106 +174,28 @@ func IsPublicHC(hc *hyperv1.HostedCluster) bool { } // LabelHCPRoutes determines if routes should be labeled for admission by the HCP router. -// Routes with the label "hypershift.openshift.io/hosted-control-plane" are served by a -// dedicated HCP router (HAProxy deployment in the HCP namespace). Routes without this label -// are served by the management cluster's default OpenShift ingress controller. -// -// This function is the single source of truth for route labeling decisions and is called by: -// - OAuth route reconciliation (external public/private routes) -// - Konnectivity route reconciliation (external routes) -// - Ignition server route reconciliation (external routes) -// - Router component predicate (determines if router Deployment/ConfigMap/PDB are created) -// - Router service creation (determines if public router LoadBalancer service is created) -// -// The HCP router infrastructure (Deployment, Services) is created when routes need to be labeled. -// This ensures routes and router services stay synchronized. -// -// # Platform-Specific Behavior -// -// AWS Platform: -// - Private: Always labels routes (no public access) -// - PublicAndPrivate + KAS LoadBalancer: Does NOT label external routes (uses mgmt cluster router) -// - PublicAndPrivate + KAS Route: Labels routes (uses HCP router for all routes) -// - Public + KAS LoadBalancer: Does NOT label routes (uses mgmt cluster router) -// - Public + KAS Route: Labels routes (uses HCP router) -// -// GCP Platform: -// - Same behavior as AWS platform -// -// Azure Platform: -// - Same behavior as AWS platform (supports endpoint access modes) -// -// Agent Platform (bare metal): -// - No EndpointAccess field (no Private/PublicAndPrivate concept) -// - Labels routes ONLY when KAS uses Route with explicit hostname -// - KAS LoadBalancer/NodePort: Does NOT label routes (uses mgmt cluster router) -// -// KubeVirt, OpenStack, None Platforms: -// - Same behavior as Agent platform -// - Labels routes ONLY when KAS uses Route with explicit hostname -// -// IBM Cloud Platform: -// - Never labels routes (uses different routing mechanism) -// -// # Internal Routes -// -// Note that internal routes (*.apps..hypershift.local) are ALWAYS labeled for -// HCP router regardless of this function's return value. This function only controls -// EXTERNAL route labeling. Internal routes are handled separately in ReconcileInternalRoute(). -// -// # Architecture Reference -// -// For complete details on the HCP ingress architecture, see HCP_INGRESS_ARCHITECTURE.md -// in the repository root, which documents the full decision flow, code references, and -// interaction between route labeling and router service creation. -// -// Returns true when routes should be labeled for HCP router; false when routes should -// use the management cluster router. func LabelHCPRoutes(hcp *hyperv1.HostedControlPlane) bool { - // When shared ingress is active (e.g., ARO HCP), all routes must be labeled - // so the SharedIngressReconciler can discover and admit them. - if isAroHCP() { + // When shared ingress or Swift networking is active, all routes must be + // labeled so the SharedIngressReconciler can discover them and the HCP + // router can serve them. + if UseSharedIngressHCP(hcp) || UseSwiftNetworkingHCP(hcp) { return true } switch hcp.Spec.Platform.Type { case hyperv1.AWSPlatform, hyperv1.GCPPlatform, hyperv1.AzurePlatform: - // AWS, GCP, and Azure support endpoint access modes (Private/PublicAndPrivate/Public). - // Label routes for HCP router when: - // 1. Cluster has no public access (Private-only), OR - // 2. Public cluster with dedicated DNS for KAS (KAS uses Route with hostname) - // - // For PublicAndPrivate clusters using LoadBalancer for KAS: - // - Internal routes (Konnectivity, Ignition) are served by internal HCP router - // - External routes (OAuth) use the management cluster router (no public HCP router needed) - // This avoids creating an unnecessary public LoadBalancer service. return !IsPublicHCP(hcp) || UseDedicatedDNSForKAS(hcp) case hyperv1.AgentPlatform, hyperv1.KubevirtPlatform, hyperv1.OpenStackPlatform, hyperv1.NonePlatform: - // These platforms do not have endpoint access mode concepts (no Private/PublicAndPrivate). - // Label routes for HCP router ONLY when KAS explicitly uses Route with a hostname. - // - // This prevents creating HCP router infrastructure when: - // - KAS uses LoadBalancer (routes should use management cluster router) - // - KAS uses NodePort (routes should use management cluster router) - // - // When KAS uses Route with hostname, all routes are labeled for HCP router to ensure - // consistent routing through dedicated infrastructure. return UseDedicatedDNSForKAS(hcp) case hyperv1.IBMCloudPlatform: - // IBM Cloud uses a different routing mechanism (shared ingress with HAProxy and - // kube-apiserver-proxy on worker nodes). Never use HCP router. return false case hyperv1.PowerVSPlatform: - // PowerVS (IBM Cloud Power Virtual Servers) follows the same pattern as other - // platforms without endpoint access modes. return UseDedicatedDNSForKAS(hcp) default: - // Conservative default for unknown platforms: do not create HCP router infrastructure. - // Routes will use the management cluster router. return false } } diff --git a/support/util/visibility_test.go b/support/util/visibility_test.go index 52fab5967c20..3901984a03e2 100644 --- a/support/util/visibility_test.go +++ b/support/util/visibility_test.go @@ -3,6 +3,8 @@ package util import ( "testing" + . "github.com/onsi/gomega" + hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -103,8 +105,22 @@ func baseVisibilityCases() []visibilityCase { wantPublic: true, }, { - name: "When is ARO with Swift it should be public and private", - platformType: hyperv1.NonePlatform, + name: "When Azure topology is PublicAndPrivate it should be public and private", + platformType: hyperv1.AzurePlatform, + azureTopology: hyperv1.AzureTopologyPublicAndPrivate, + wantPrivate: true, + wantPublic: true, + }, + { + name: "When Azure topology is Private it should be private and not public", + platformType: hyperv1.AzurePlatform, + azureTopology: hyperv1.AzureTopologyPrivate, + wantPrivate: true, + wantPublic: false, + }, + { + name: "When Azure topology is empty with Swift annotation fallback it should be private and public", + platformType: hyperv1.AzurePlatform, setupEnv: func(t *testing.T) { t.Setenv("MANAGED_SERVICE", hyperv1.AroHCP) }, @@ -222,8 +238,41 @@ func TestLabelHCPRoutes(t *testing.T) { }{ // Shared Ingress Tests { - name: "When shared ingress is active (ARO HCP), it should always label routes regardless of platform", + name: "When Swift networking is active via API field, it should always label routes", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + Topology: hyperv1.AzureTopologyPublicAndPrivate, + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "test-swift-instance", + }, + }, + }, + }, + Services: []hyperv1.ServicePublishingStrategyMapping{ + { + Service: hyperv1.APIServer, + ServicePublishingStrategy: hyperv1.ServicePublishingStrategy{ + Type: hyperv1.LoadBalancer, + }, + }, + }, + }, + }, + want: true, + }, + { + name: "When Swift networking is active via annotation fallback, it should always label routes", hcp: &hyperv1.HostedControlPlane{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + hyperv1.SwiftPodNetworkInstanceAnnotation: "test-swift-instance", + }, + }, Spec: hyperv1.HostedControlPlaneSpec{ Platform: hyperv1.PlatformSpec{ Type: hyperv1.AzurePlatform, @@ -996,3 +1045,704 @@ func TestLabelHCPRoutes(t *testing.T) { }) } } + +func TestUseSwiftNetworkingHCP(t *testing.T) { + tests := []struct { + name string + hcp *hyperv1.HostedControlPlane + setupEnv func(t *testing.T) + want bool + }{ + { + name: "When Azure platform with Private.Type=Swift it should return true", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "test-pni", + }, + }, + }, + }, + }, + }, + want: true, + }, + { + name: "When Azure platform with annotation fallback it should return true", + hcp: &hyperv1.HostedControlPlane{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + hyperv1.SwiftPodNetworkInstanceAnnotation: "test-pni", + }, + }, + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + }, + }, + }, + setupEnv: func(t *testing.T) { + t.Setenv("MANAGED_SERVICE", hyperv1.AroHCP) + }, + want: true, + }, + { + name: "When Azure platform with neither API field nor annotation it should return false", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{}, + }, + }, + }, + want: false, + }, + { + name: "When AWS platform it should return false", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AWSPlatform, + AWS: &hyperv1.AWSPlatformSpec{}, + }, + }, + }, + want: false, + }, + { + name: "When Azure platform with Private.Type=PrivateLink it should return false", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypePrivateLink, + }, + }, + }, + }, + }, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + if tt.setupEnv != nil { + tt.setupEnv(t) + } + g.Expect(UseSwiftNetworkingHCP(tt.hcp)).To(Equal(tt.want)) + }) + } +} + +func TestUseSwiftNetworkingHC(t *testing.T) { + tests := []struct { + name string + hc *hyperv1.HostedCluster + setupEnv func(t *testing.T) + want bool + }{ + { + name: "When Azure platform with Private.Type=Swift it should return true", + hc: &hyperv1.HostedCluster{ + Spec: hyperv1.HostedClusterSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "test-pni", + }, + }, + }, + }, + }, + }, + want: true, + }, + { + name: "When Azure platform with annotation fallback it should return true", + hc: &hyperv1.HostedCluster{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + hyperv1.SwiftPodNetworkInstanceAnnotation: "test-pni", + }, + }, + Spec: hyperv1.HostedClusterSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + }, + }, + }, + setupEnv: func(t *testing.T) { + t.Setenv("MANAGED_SERVICE", hyperv1.AroHCP) + }, + want: true, + }, + { + name: "When Azure platform with neither API field nor annotation it should return false", + hc: &hyperv1.HostedCluster{ + Spec: hyperv1.HostedClusterSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{}, + }, + }, + }, + want: false, + }, + { + name: "When AWS platform it should return false", + hc: &hyperv1.HostedCluster{ + Spec: hyperv1.HostedClusterSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AWSPlatform, + AWS: &hyperv1.AWSPlatformSpec{}, + }, + }, + }, + want: false, + }, + { + name: "When Azure platform with Private.Type=PrivateLink it should return false", + hc: &hyperv1.HostedCluster{ + Spec: hyperv1.HostedClusterSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypePrivateLink, + }, + }, + }, + }, + }, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + if tt.setupEnv != nil { + tt.setupEnv(t) + } + g.Expect(UseSwiftNetworkingHC(tt.hc)).To(Equal(tt.want)) + }) + } +} + +func TestUseSharedIngressHCP(t *testing.T) { + tests := []struct { + name string + hcp *hyperv1.HostedControlPlane + want bool + }{ + { + name: "When Swift with PublicAndPrivate topology it should return true", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + Topology: hyperv1.AzureTopologyPublicAndPrivate, + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "test-pni", + }, + }, + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeManagedIdentities, + }, + }, + }, + }, + }, + want: true, + }, + { + name: "When Swift with Private topology it should return false", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + Topology: hyperv1.AzureTopologyPrivate, + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "test-pni", + }, + }, + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeManagedIdentities, + }, + }, + }, + }, + }, + want: false, + }, + { + name: "When Swift with empty topology it should return true", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "test-pni", + }, + }, + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeManagedIdentities, + }, + }, + }, + }, + }, + want: true, + }, + { + name: "When ManagedIdentities without Swift and empty topology it should return true", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeManagedIdentities, + }, + }, + }, + }, + }, + want: true, + }, + { + name: "When non-Swift it should return false", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + Topology: hyperv1.AzureTopologyPublicAndPrivate, + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypePrivateLink, + }, + }, + }, + }, + }, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + g.Expect(UseSharedIngressHCP(tt.hcp)).To(Equal(tt.want)) + }) + } +} + +func TestUseSharedIngressHC(t *testing.T) { + tests := []struct { + name string + hc *hyperv1.HostedCluster + want bool + }{ + { + name: "When Swift with PublicAndPrivate topology it should return true", + hc: &hyperv1.HostedCluster{ + Spec: hyperv1.HostedClusterSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + Topology: hyperv1.AzureTopologyPublicAndPrivate, + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "test-pni", + }, + }, + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeManagedIdentities, + }, + }, + }, + }, + }, + want: true, + }, + { + name: "When Swift with Private topology it should return false", + hc: &hyperv1.HostedCluster{ + Spec: hyperv1.HostedClusterSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + Topology: hyperv1.AzureTopologyPrivate, + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "test-pni", + }, + }, + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeManagedIdentities, + }, + }, + }, + }, + }, + want: false, + }, + { + name: "When Swift with empty topology it should return true", + hc: &hyperv1.HostedCluster{ + Spec: hyperv1.HostedClusterSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "test-pni", + }, + }, + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeManagedIdentities, + }, + }, + }, + }, + }, + want: true, + }, + { + name: "When ManagedIdentities without Swift and empty topology it should return true", + hc: &hyperv1.HostedCluster{ + Spec: hyperv1.HostedClusterSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeManagedIdentities, + }, + }, + }, + }, + }, + want: true, + }, + { + name: "When non-Swift it should return false", + hc: &hyperv1.HostedCluster{ + Spec: hyperv1.HostedClusterSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + Topology: hyperv1.AzureTopologyPublicAndPrivate, + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypePrivateLink, + }, + }, + }, + }, + }, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + g.Expect(UseSharedIngressHC(tt.hc)).To(Equal(tt.want)) + }) + } +} + +func TestSwiftPodNetworkInstanceHCP(t *testing.T) { + tests := []struct { + name string + hcp *hyperv1.HostedControlPlane + want string + }{ + { + name: "When Azure with Private.Type=Swift it should return PodNetworkInstance from API field", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + Private: hyperv1.AzurePrivateSpec{ + Type: hyperv1.AzurePrivateTypeSwift, + Swift: hyperv1.AzureSwiftSpec{ + PodNetworkInstance: "test-pni", + }, + }, + }, + }, + }, + }, + want: "test-pni", + }, + { + name: "When Azure with annotation fallback it should return value from annotation", + hcp: &hyperv1.HostedControlPlane{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + hyperv1.SwiftPodNetworkInstanceAnnotation: "annotation-pni", + }, + }, + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{}, + }, + }, + }, + want: "annotation-pni", + }, + { + name: "When Azure with neither API field nor annotation it should return empty string", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{}, + }, + }, + }, + want: "", + }, + { + name: "When non-Azure platform it should return empty string", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AWSPlatform, + AWS: &hyperv1.AWSPlatformSpec{}, + }, + }, + }, + want: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + g.Expect(SwiftPodNetworkInstanceHCP(tt.hcp)).To(Equal(tt.want)) + }) + } +} + +func TestIsAroHCPByHCP(t *testing.T) { + tests := []struct { + name string + hcp *hyperv1.HostedControlPlane + setupEnv func(t *testing.T) + want bool + }{ + { + name: "When AzureAuthenticationConfigType is ManagedIdentities it should return true", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeManagedIdentities, + }, + }, + }, + }, + }, + want: true, + }, + { + name: "When AzureAuthenticationConfigType is WorkloadIdentities it should return false", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeWorkloadIdentities, + }, + }, + }, + }, + }, + want: false, + }, + { + name: "When platform is not Azure it should return false", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AWSPlatform, + }, + }, + }, + want: false, + }, + { + name: "When Azure spec is nil it should fall back to env var", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + }, + }, + }, + setupEnv: func(t *testing.T) { + t.Setenv("MANAGED_SERVICE", hyperv1.AroHCP) + }, + want: true, + }, + { + name: "When Azure spec is nil and env var is not set it should return false", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + }, + }, + }, + want: false, + }, + { + name: "When WorkloadIdentities with ARO HCP env var it should return false because API takes precedence", + hcp: &hyperv1.HostedControlPlane{ + Spec: hyperv1.HostedControlPlaneSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeWorkloadIdentities, + }, + }, + }, + }, + }, + setupEnv: func(t *testing.T) { + t.Setenv("MANAGED_SERVICE", hyperv1.AroHCP) + }, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + if tt.setupEnv != nil { + tt.setupEnv(t) + } + g.Expect(IsAroHCPByHCP(tt.hcp)).To(Equal(tt.want)) + }) + } +} + +func TestIsAroHCPByHC(t *testing.T) { + tests := []struct { + name string + hc *hyperv1.HostedCluster + setupEnv func(t *testing.T) + want bool + }{ + { + name: "When AzureAuthenticationConfigType is ManagedIdentities it should return true", + hc: &hyperv1.HostedCluster{ + Spec: hyperv1.HostedClusterSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeManagedIdentities, + }, + }, + }, + }, + }, + want: true, + }, + { + name: "When AzureAuthenticationConfigType is WorkloadIdentities it should return false", + hc: &hyperv1.HostedCluster{ + Spec: hyperv1.HostedClusterSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + Azure: &hyperv1.AzurePlatformSpec{ + AzureAuthenticationConfig: hyperv1.AzureAuthenticationConfiguration{ + AzureAuthenticationConfigType: hyperv1.AzureAuthenticationTypeWorkloadIdentities, + }, + }, + }, + }, + }, + want: false, + }, + { + name: "When platform is not Azure it should return false", + hc: &hyperv1.HostedCluster{ + Spec: hyperv1.HostedClusterSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AWSPlatform, + }, + }, + }, + want: false, + }, + { + name: "When Azure spec is nil it should fall back to env var", + hc: &hyperv1.HostedCluster{ + Spec: hyperv1.HostedClusterSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + }, + }, + }, + setupEnv: func(t *testing.T) { + t.Setenv("MANAGED_SERVICE", hyperv1.AroHCP) + }, + want: true, + }, + { + name: "When Azure spec is nil and env var is not set it should return false", + hc: &hyperv1.HostedCluster{ + Spec: hyperv1.HostedClusterSpec{ + Platform: hyperv1.PlatformSpec{ + Type: hyperv1.AzurePlatform, + }, + }, + }, + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + if tt.setupEnv != nil { + tt.setupEnv(t) + } + g.Expect(IsAroHCPByHC(tt.hc)).To(Equal(tt.want)) + }) + } +} diff --git a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/azure.go b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/azure.go index c99523ceedfc..0c130111e1b8 100644 --- a/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/azure.go +++ b/vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/azure.go @@ -653,7 +653,7 @@ const ( // AzurePrivateType specifies the type of private connectivity mechanism used for the Azure // hosted cluster's API server. This acts as the discriminator for the AzurePrivateSpec union. // -// +kubebuilder:validation:Enum=PrivateLink +// +kubebuilder:validation:Enum=PrivateLink;Swift type AzurePrivateType string const ( @@ -661,23 +661,30 @@ const ( // In this mode, the operator creates a Private Link Service backed by the management cluster's // internal load balancer, and a Private Endpoint in the guest VNet for private API server access. AzurePrivateTypePrivateLink AzurePrivateType = "PrivateLink" + + // AzurePrivateTypeSwift specifies private connectivity using Azure Swift pod networking. + // In this mode, Azure Swift assigns a private IP from the customer VNet directly + // to the hosted cluster's router pods, providing private API server access without a + // separate Private Link Service. This is used by ARO HCP managed clusters. + AzurePrivateTypeSwift AzurePrivateType = "Swift" ) // AzurePrivateSpec configures private connectivity to an Azure hosted cluster's API server. // It is a discriminated union keyed on the type field, which selects the private connectivity -// mechanism. Currently only PrivateLink is supported; additional mechanisms (e.g., Swift) may -// be added in the future. +// mechanism. // -// +kubebuilder:validation:XValidation:rule="self.type != 'PrivateLink' ? !has(self.privateLink) : true",message="privateLink is forbidden when type is not PrivateLink" +// +kubebuilder:validation:XValidation:rule="!has(oldSelf.type) || self.type == oldSelf.type",message="type is immutable" +// +kubebuilder:validation:XValidation:rule="self.type == 'PrivateLink' ? has(self.privateLink) : !has(self.privateLink)",message="privateLink is required when type is PrivateLink, and forbidden otherwise" +// +kubebuilder:validation:XValidation:rule="self.type == 'Swift' ? has(self.swift) : !has(self.swift)",message="swift is required when type is Swift, and forbidden otherwise" // +union type AzurePrivateSpec struct { // type specifies the private connectivity mechanism used for the hosted cluster's API server. // "PrivateLink" selects Azure Private Link Service for private API server access. + // "Swift" selects Azure Swift pod networking for private API server access, used by ARO HCP. // This field is immutable once set. // // +unionDiscriminator // +required - // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="type is immutable" Type AzurePrivateType `json:"type,omitempty"` // privateLink configures Azure Private Link Service for private API server access. @@ -686,6 +693,15 @@ type AzurePrivateSpec struct { // +optional // +unionMember PrivateLink AzurePrivateLinkSpec `json:"privateLink,omitzero"` + + // swift configures Azure Swift pod networking for private API server access. + // Swift networking requires the management cluster to be pre-configured with + // Azure Swift support; this is not provisioned by HyperShift automatically. + // This field is required when type is "Swift" and must not be set otherwise. + // + // +optional + // +unionMember + Swift AzureSwiftSpec `json:"swift,omitzero"` } // AzurePrivateLinkSpec configures Azure Private Link Service connectivity. @@ -716,6 +732,26 @@ type AzurePrivateLinkSpec struct { AdditionalAllowedSubscriptions []AzureSubscriptionID `json:"additionalAllowedSubscriptions,omitempty"` } +// AzureSwiftSpec configures Azure Swift pod networking for private API server access. +// Swift assigns a private IP from the customer VNet directly to the hosted cluster's +// router pods, providing private connectivity without a separate Private Link Service. +// +// +kubebuilder:validation:XValidation:rule="self.podNetworkInstance == oldSelf.podNetworkInstance",message="podNetworkInstance is immutable" +type AzureSwiftSpec struct { + // podNetworkInstance is the name of a PodNetworkInstance custom resource in the + // hosted control plane namespace. This resource configures Azure Swift pod networking + // for private connectivity to the hosted cluster's router pods. + // The value must be a valid Kubernetes object name (RFC 1123 DNS label): lowercase + // alphanumeric characters or hyphens, must start and end with an alphanumeric character. + // This field is immutable once set. + // + // +required + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=63 + // +kubebuilder:validation:XValidation:rule="self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$')",message="podNetworkInstance must be a valid DNS label: lowercase alphanumeric characters or hyphens, must start and end with an alphanumeric character" + PodNetworkInstance string `json:"podNetworkInstance,omitempty"` +} + // ControlPlaneManagedIdentities contains the managed identities on the HCP control plane needing to authenticate with // Azure's API. type ControlPlaneManagedIdentities struct { 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 558be0746f8f..80f9062b9ee0 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 @@ -857,6 +857,7 @@ func (in *AzurePrivateLinkSpec) DeepCopy() *AzurePrivateLinkSpec { func (in *AzurePrivateSpec) DeepCopyInto(out *AzurePrivateSpec) { *out = *in in.PrivateLink.DeepCopyInto(&out.PrivateLink) + out.Swift = in.Swift } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzurePrivateSpec. @@ -886,6 +887,21 @@ func (in *AzureResourceManagedIdentities) DeepCopy() *AzureResourceManagedIdenti return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureSwiftSpec) DeepCopyInto(out *AzureSwiftSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureSwiftSpec. +func (in *AzureSwiftSpec) DeepCopy() *AzureSwiftSpec { + if in == nil { + return nil + } + out := new(AzureSwiftSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AzureVMImage) DeepCopyInto(out *AzureVMImage) { *out = *in