diff --git a/api/v1alpha1/kubevirtcluster_types.go b/api/v1alpha1/kubevirtcluster_types.go index 098ae063..3f8caae2 100644 --- a/api/v1alpha1/kubevirtcluster_types.go +++ b/api/v1alpha1/kubevirtcluster_types.go @@ -42,10 +42,20 @@ type KubevirtClusterSpec struct { // +optional ControlPlaneEndpoint APIEndpoint `json:"controlPlaneEndpoint,omitempty"` + // ControlPlaneServiceTemplate can be used to modify service that fronts the control plane nodes to handle the + // api-server traffic (port 6443). This field is optional, by default control plane nodes will use a service + // of type ClusterIP, which will make workload cluster only accessible within the same cluster. Note, this does + // not aim to expose the entire Service spec to users, but only provides capability to modify the service metadata + // and the service type. + // +optional + ControlPlaneServiceTemplate ControlPlaneServiceTemplate `json:"controlPlaneServiceTemplate,omitempty"` + // SSHKeys is a reference to a local struct for SSH keys persistence. + // +optional SshKeys SSHKeys `json:"sshKeys,omitempty"` // InfraClusterSecretRef is a reference to a secret with a kubeconfig for external cluster used for infra. + // +optional InfraClusterSecretRef *corev1.ObjectReference `json:"infraClusterSecretRef,omitempty"` } @@ -85,6 +95,28 @@ type SSHKeys struct { DataSecretName *string `json:"dataSecretName,omitempty"` } +// ControlPlaneServiceTemplate describes the template for the control plane service. +type ControlPlaneServiceTemplate struct { + // Service metadata allows to set labels and annotations for the service. + // This field is optional. + // +kubebuilder:pruning:PreserveUnknownFields + // +nullable + ObjectMeta metav1.ObjectMeta `json:"metadata,omitempty"` + // Service specification allows to override some fields in the service spec. + // Note, it does not aim cover all fields of the service spec. + // +optional + Spec ServiceSpecTemplate `json:"spec,omitempty"` +} + +// ServiceSpecTemplate describes the service spec template. +type ServiceSpecTemplate struct { + // Type determines how the Service is exposed. Defaults to ClusterIP. Valid + // options are ExternalName, ClusterIP, NodePort, and LoadBalancer. + // More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types + // +optional + Type corev1.ServiceType `json:"type,omitempty"` +} + // +kubebuilder:resource:path=kubevirtclusters,scope=Namespaced,categories=cluster-api // +kubebuilder:subresource:status // +kubebuilder:storageversion diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index f393a635..05832c7a 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* @@ -41,6 +42,23 @@ func (in *APIEndpoint) DeepCopy() *APIEndpoint { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControlPlaneServiceTemplate) DeepCopyInto(out *ControlPlaneServiceTemplate) { + *out = *in + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControlPlaneServiceTemplate. +func (in *ControlPlaneServiceTemplate) DeepCopy() *ControlPlaneServiceTemplate { + if in == nil { + return nil + } + out := new(ControlPlaneServiceTemplate) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KubevirtCluster) DeepCopyInto(out *KubevirtCluster) { *out = *in @@ -104,6 +122,7 @@ func (in *KubevirtClusterList) DeepCopyObject() runtime.Object { func (in *KubevirtClusterSpec) DeepCopyInto(out *KubevirtClusterSpec) { *out = *in out.ControlPlaneEndpoint = in.ControlPlaneEndpoint + in.ControlPlaneServiceTemplate.DeepCopyInto(&out.ControlPlaneServiceTemplate) in.SshKeys.DeepCopyInto(&out.SshKeys) if in.InfraClusterSecretRef != nil { in, out := &in.InfraClusterSecretRef, &out.InfraClusterSecretRef @@ -373,6 +392,21 @@ func (in *SSHKeys) DeepCopy() *SSHKeys { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceSpecTemplate) DeepCopyInto(out *ServiceSpecTemplate) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceSpecTemplate. +func (in *ServiceSpecTemplate) DeepCopy() *ServiceSpecTemplate { + if in == nil { + return nil + } + out := new(ServiceSpecTemplate) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VirtualMachineTemplateSpec) DeepCopyInto(out *VirtualMachineTemplateSpec) { *out = *in diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_kubevirtclusters.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_kubevirtclusters.yaml index 9d0ea75e..acde4cfd 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_kubevirtclusters.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_kubevirtclusters.yaml @@ -52,6 +52,33 @@ spec: - host - port type: object + controlPlaneServiceTemplate: + description: ControlPlaneServiceTemplate can be used to modify service + that fronts the control plane nodes to handle the api-server traffic + (port 6443). This field is optional, by default control plane nodes + will use a service of type ClusterIP, which will make workload cluster + only accessible within the same cluster. Note, this does not aim + to expose the entire Service spec to users, but only provides capability + to modify the service metadata and the service type. + properties: + metadata: + description: Service metadata allows to set labels and annotations + for the service. This field is optional. + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + spec: + description: Service specification allows to override some fields + in the service spec. Note, it does not aim cover all fields + of the service spec. + properties: + type: + description: 'Type determines how the Service is exposed. + Defaults to ClusterIP. Valid options are ExternalName, ClusterIP, + NodePort, and LoadBalancer. More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types' + type: string + type: object + type: object infraClusterSecretRef: description: InfraClusterSecretRef is a reference to a secret with a kubeconfig for external cluster used for infra. diff --git a/pkg/loadbalancer/loadbalancer.go b/pkg/loadbalancer/loadbalancer.go index dff57e40..442f4d54 100644 --- a/pkg/loadbalancer/loadbalancer.go +++ b/pkg/loadbalancer/loadbalancer.go @@ -95,11 +95,16 @@ func (l *LoadBalancer) Create(ctx *context.ClusterContext) error { }, }, Selector: map[string]string{ - "cluster.x-k8s.io/role": constants.ControlPlaneNodeRoleValue, + "cluster.x-k8s.io/role": constants.ControlPlaneNodeRoleValue, "cluster.x-k8s.io/cluster-name": ctx.Cluster.Name, }, }, } + + lbService.Labels = ctx.KubevirtCluster.Spec.ControlPlaneServiceTemplate.ObjectMeta.Labels + lbService.Annotations = ctx.KubevirtCluster.Spec.ControlPlaneServiceTemplate.ObjectMeta.Annotations + lbService.Spec.Type = ctx.KubevirtCluster.Spec.ControlPlaneServiceTemplate.Spec.Type + mutateFn := func() (err error) { if lbService.Labels == nil { lbService.Labels = map[string]string{} diff --git a/templates/cluster-template.yaml b/templates/cluster-template.yaml index ca8d907f..ad730666 100644 --- a/templates/cluster-template.yaml +++ b/templates/cluster-template.yaml @@ -25,6 +25,10 @@ kind: KubevirtCluster metadata: name: "${CLUSTER_NAME}" namespace: "${NAMESPACE}" +spec: + controlPlaneServiceTemplate: + spec: + type: ClusterIP --- apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 kind: KubevirtMachineTemplate