@@ -17,31 +17,171 @@ limitations under the License.
1717package v1beta2
1818
1919import (
20+ corev1 "k8s.io/api/core/v1"
2021 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
22+ clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2"
23+ "sigs.k8s.io/cluster-api/util/conditions"
2124)
2225
23- // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
24- // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
26+ const (
27+ // ClusterFinalizer allows cleanup of resources before removal from the API.
28+ ClusterFinalizer = "cloudscalecluster.infrastructure.cluster.x-k8s.io"
29+ )
2530
2631// CloudscaleClusterSpec defines the desired state of CloudscaleCluster
2732type CloudscaleClusterSpec struct {
28- // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
29- // Important: Run "make" to regenerate code after modifying this file
30- // The following markers will use OpenAPI v3 schema to validate the value
31- // More info: https://book.kubebuilder.io/reference/markers/crd-validation.html
33+ // Region is the cloudscale.ch region (e.g., "rma", "lpg").
34+ // +kubebuilder:validation:Required
35+ // +kubebuilder:validation:Enum=rma;lpg
36+ Region string `json:"region"`
37+
38+ // CredentialsRef references the Secret containing the cloudscale.ch API token.
39+ // +kubebuilder:validation:Required
40+ CredentialsRef CloudscaleCredentialsReference `json:"credentialsRef"`
41+
42+ // ControlPlaneEndpoint represents the endpoint to communicate with the control plane.
43+ // This is set automatically from the load balancer's VIP address.
44+ // +optional
45+ ControlPlaneEndpoint clusterv1.APIEndpoint `json:"controlPlaneEndpoint,omitzero"`
46+
47+ // Network contains network configuration for the cluster.
48+ // +optional
49+ Network NetworkSpec `json:"network,omitzero"`
50+
51+ // ControlPlaneLoadBalancer configures the load balancer for the control plane.
52+ // +optional
53+ ControlPlaneLoadBalancer LoadBalancerSpec `json:"controlPlaneLoadBalancer,omitzero"`
54+ }
55+
56+ // CloudscaleCredentialsReference references a Secret containing the API token.
57+ type CloudscaleCredentialsReference struct {
58+ // Name is the name of the Secret.
59+ // +kubebuilder:validation:Required
60+ Name string `json:"name"`
61+
62+ // Namespace is the namespace of the Secret. Defaults to the cluster namespace.
63+ // +optional
64+ Namespace string `json:"namespace,omitempty"`
65+ }
66+
67+ // NetworkSpec defines the network configuration.
68+ type NetworkSpec struct {
69+ // Zone is the cloudscale.ch zone for the network (e.g., "rma1", "lpg1").
70+ // Defaults to region + "1" if not specified.
71+ // +optional
72+ Zone string `json:"zone,omitempty"`
73+
74+ // CIDR is the CIDR block for the private network subnet.
75+ // +kubebuilder:default="10.0.0.0/24"
76+ // +optional
77+ CIDR string `json:"cidr,omitempty"`
78+
79+ // GatewayAddress is the gateway IP address for the subnet.
80+ // By default, no gateway is configured on the private network subnet. This ensures
81+ // that outbound internet traffic uses the public network interface, which is required
82+ // for the Cloud Controller Manager to reach the cloudscale.ch API.
83+ // Set this to a specific IP address (e.g., "10.0.0.1") only if you have configured
84+ // a NAT gateway or similar infrastructure on the private network.
85+ // +optional
86+ GatewayAddress * string `json:"gatewayAddress,omitempty"`
87+ }
88+
89+ // LoadBalancerSpec defines the load balancer configuration for the control plane.
90+ type LoadBalancerSpec struct {
91+ // Enabled controls whether a load balancer is created for the control plane.
92+ // Set to false for external control planes (e.g., hosted control plane) where the endpoint
93+ // is provided externally.
94+ // +kubebuilder:default=true
95+ // +optional
96+ Enabled * bool `json:"enabled,omitempty"`
97+
98+ // Algorithm is the load balancing algorithm.
99+ // +kubebuilder:validation:Enum=round_robin;least_connections;source_ip
100+ // +kubebuilder:default="round_robin"
101+ // +optional
102+ Algorithm string `json:"algorithm,omitempty"`
32103
33- // foo is an example field of CloudscaleCluster. Edit cloudscalecluster_types.go to remove/update
104+ // Flavor is the load balancer flavor (size).
105+ // +kubebuilder:default="lb-standard"
34106 // +optional
35- Foo * string `json:"foo,omitempty"`
107+ Flavor string `json:"flavor,omitempty"`
108+
109+ // APIServerPort is the port for the Kubernetes API server.
110+ // +kubebuilder:default=6443
111+ // +kubebuilder:validation:Minimum=1
112+ // +kubebuilder:validation:Maximum=65535
113+ // +optional
114+ APIServerPort int32 `json:"apiServerPort,omitempty"`
115+
116+ // HealthMonitor configures the load balancer health monitor.
117+ // +optional
118+ HealthMonitor HealthMonitorSpec `json:"healthMonitor,omitempty"`
119+ }
120+
121+ // HealthMonitorSpec configures the load balancer health monitor.
122+ type HealthMonitorSpec struct {
123+ // DelayS is the interval between health checks in seconds.
124+ // +kubebuilder:default=5
125+ // +kubebuilder:validation:Minimum=1
126+ // +kubebuilder:validation:Maximum=300
127+ // +optional
128+ DelayS int `json:"delayS,omitempty"`
129+
130+ // TimeoutS is the health check timeout in seconds.
131+ // +kubebuilder:default=3
132+ // +kubebuilder:validation:Minimum=1
133+ // +kubebuilder:validation:Maximum=300
134+ // +optional
135+ TimeoutS int `json:"timeoutS,omitempty"`
136+
137+ // UpThreshold is the number of successful checks to mark healthy.
138+ // +kubebuilder:default=2
139+ // +kubebuilder:validation:Minimum=1
140+ // +kubebuilder:validation:Maximum=10
141+ // +optional
142+ UpThreshold int `json:"upThreshold,omitempty"`
143+
144+ // DownThreshold is the number of failed checks to mark unhealthy.
145+ // +kubebuilder:default=3
146+ // +kubebuilder:validation:Minimum=1
147+ // +kubebuilder:validation:Maximum=10
148+ // +optional
149+ DownThreshold int `json:"downThreshold,omitempty"`
36150}
37151
38152// CloudscaleClusterStatus defines the observed state of CloudscaleCluster.
39153type CloudscaleClusterStatus struct {
40- // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
41- // Important: Run "make" to regenerate code after modifying this file
154+ // Initialization contains v1beta2 initialization tracking.
155+ // +optional
156+ Initialization * ClusterInitializationStatus `json:"initialization,omitempty"`
157+
158+ // NetworkID is the cloudscale.ch network UUID.
159+ // +optional
160+ NetworkID string `json:"networkID,omitempty"`
42161
43- // For Kubernetes API conventions, see:
44- // https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties
162+ // SubnetID is the cloudscale.ch subnet UUID.
163+ // +optional
164+ SubnetID string `json:"subnetID,omitempty"`
165+
166+ // LoadBalancerID is the cloudscale.ch load balancer UUID.
167+ // +optional
168+ LoadBalancerID string `json:"loadBalancerID,omitempty"`
169+
170+ // LoadBalancerPoolID is the cloudscale.ch load balancer pool UUID for the API server.
171+ // +optional
172+ LoadBalancerPoolID string `json:"loadBalancerPoolID,omitempty"`
173+
174+ // LoadBalancerListenerID is the cloudscale.ch load balancer listener UUID for the API server.
175+ // +optional
176+ LoadBalancerListenerID string `json:"loadBalancerListenerID,omitempty"`
177+
178+ // LoadBalancerHealthMonitorID is the cloudscale.ch load balancer health monitor UUID.
179+ // +optional
180+ LoadBalancerHealthMonitorID string `json:"loadBalancerHealthMonitorID,omitempty"`
181+
182+ // LoadBalancerMemberIDs are the list of nodes attached to the loadBalancer.
183+ // +optional
184+ LoadBalancerMemberIDs []string `json:"LoadBalancerMemberIDs,omitempty"`
45185
46186 // conditions represent the current state of the CloudscaleCluster resource.
47187 // Each condition has a unique type and reflects the status of a specific aspect of the resource.
@@ -58,8 +198,21 @@ type CloudscaleClusterStatus struct {
58198 Conditions []metav1.Condition `json:"conditions,omitempty"`
59199}
60200
201+ // ClusterInitializationStatus contains v1beta2 initialization tracking for CloudscaleCluster.
202+ type ClusterInitializationStatus struct {
203+ // Provisioned indicates that all cluster infrastructure has been provisioned.
204+ // True when Network, Subnet, Load Balancer, and Control Plane Endpoint are ready.
205+ // +optional
206+ Provisioned * bool `json:"provisioned,omitempty"`
207+ }
208+
61209// +kubebuilder:object:root=true
62210// +kubebuilder:subresource:status
211+ // +kubebuilder:resource:path=cloudscaleclusters,scope=Namespaced,categories=cluster-api
212+ // +kubebuilder:printcolumn:name="Cluster",type="string",JSONPath=".metadata.labels.cluster\\.x-k8s\\.io/cluster-name",description="Cluster"
213+ // +kubebuilder:printcolumn:name="Provisioned",type="string",JSONPath=".status.initialization.provisioned",description="Infrastructure provisioned"
214+ // +kubebuilder:printcolumn:name="Region",type="string",JSONPath=".spec.region",description="cloudscale.ch region"
215+ // +kubebuilder:printcolumn:name="Endpoint",type="string",JSONPath=".spec.controlPlaneEndpoint.host",description="Control plane endpoint"
63216
64217// CloudscaleCluster is the Schema for the cloudscaleclusters API
65218type CloudscaleCluster struct {
@@ -78,6 +231,40 @@ type CloudscaleCluster struct {
78231 Status CloudscaleClusterStatus `json:"status,omitzero"`
79232}
80233
234+ // ensures CloudscaleCluster implements conditions.Setter
235+ var _ conditions.Setter = & CloudscaleCluster {}
236+
237+ // GetConditions returns the conditions for the CloudscaleCluster.
238+ // This implements the conditions.Getter interface from CAPI util/conditions.
239+ func (c * CloudscaleCluster ) GetConditions () []metav1.Condition {
240+ return c .Status .Conditions
241+ }
242+
243+ // SetConditions sets the conditions for the CloudscaleCluster.
244+ // This implements the conditions.Setter interface from CAPI util/conditions.
245+ func (c * CloudscaleCluster ) SetConditions (conds []metav1.Condition ) {
246+ c .Status .Conditions = conds
247+ }
248+
249+ // CredentialsSecretRef returns an ObjectReference to the credentials Secret.
250+ func (c * CloudscaleCluster ) CredentialsSecretRef () corev1.ObjectReference {
251+ ns := c .Spec .CredentialsRef .Namespace
252+ if ns == "" {
253+ ns = c .Namespace
254+ }
255+ return corev1.ObjectReference {
256+ APIVersion : "v1" ,
257+ Kind : "Secret" ,
258+ Name : c .Spec .CredentialsRef .Name ,
259+ Namespace : ns ,
260+ }
261+ }
262+
263+ // ClusterTagKey generates the key for resources associated with a cluster.
264+ func (c * CloudscaleCluster ) ClusterTagKey () string {
265+ return NameCloudscaleProviderOwned + c .Name
266+ }
267+
81268// +kubebuilder:object:root=true
82269
83270// CloudscaleClusterList contains a list of CloudscaleCluster
@@ -88,5 +275,8 @@ type CloudscaleClusterList struct {
88275}
89276
90277func init () {
91- SchemeBuilder .Register (& CloudscaleCluster {}, & CloudscaleClusterList {})
278+ objectTypes = append (objectTypes ,
279+ & CloudscaleCluster {},
280+ & CloudscaleClusterList {},
281+ )
92282}
0 commit comments