---
# System prepended metadata

title: Wayfinder nodepool split

---

# Wayfinder nodepool split

## Goal

Split Wayfinder `NodePool` object from `Cluster` objecct so it can be tracked, reported and reconciled individually.

## Options

1. Split `NodePools` to separate object
2. Add more status to `Cluster` with `NodePool` details and extend with more status details. 
3. Make nodepools independent from `Cluster` all together and do "scheduling" approach where we 
match node pools to clusters and create. This way you in theory should be able to move capacity from 1 cluster to other.

## Challenges

1. How to migrate existing clusters and their spec into this model without downtime
2. Currently NodePool are integated into cluster spec
```
// NodePools is a collection of node pools associated to the cluster
	// +kubebuilder:validation:Optional
	// +kubebuilder:validation:MinItems=1
	NodePools []*NodePool `json:"nodePools,omitempty"`
```
If this change removed this dependency, this means `ClusterPlan` would not be 1:1 mapping to cluster object anymore, but `ClusterPlan` would derive `Cluster` and `NodePool`'s objects. Currently `Cluster` is single soure of truth

## Option 1

1. Add new NodePool object:
```
type NodePool struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   NodePoolSpec   `json:"spec,omitempty"`
	Status NodePoolStatus `json:"status,omitempty"`
}
```

2. Alias old type into Spec:
type `type LegacyNodePool = NodePoolSpec` and rename all in the code
`NodePool` -> `LegacyNodePool`. At this point cluster creation flow should not change and input is still from "clusterplan/template".

3. Add `NodePool` controller which would create shallow object to report status, objects should be owned by cluster and name should imply clear relationship. 
Controller should reconcile only status of the object, but not spec. Spec should be ignored for now. But objects should be recycled together with cluster object in child parent relationship.

4. Add new ClusterSpec field: `NodePoolRef` and point to references of `NodePool objects`. Add mutating webhook to create references to shallow-objects. Cluster controller should be created `NodePool` objects and populating references. 

5. Add `featureFlag` for `NodePoolController` which would move from reconcoling from `ClusterSpec` to `NodePool` objects (objects should be created in step 3 already)

## Option 2

We extend just cluster status with:

```
// ClusterStatus defines the observed state of a cluster
// +k8s:openapi-gen=true
type ClusterStatus struct {
     ...
	// NodePoolStatuses is a list of statuses for the node pools in this cluster
	// +kubebuilder:validation:Optional
	NodePoolStatuses []NodePoolStatus `json:"nodePoolStatuses,omitempty"`
}

type NodePoolStatus struct {
	// Name is the name of the node pool
	Name string `json:"name,omitempty"`
	// ProvisioningState is provisioning state of the nodePool
	// +kubebuilder:validation:Optional
	ProvisioningState ProvisioningState `json:"providerStatus,omitempty"`
	// NodeCount is the number of nodes in the node pool
	// +kubebuilder:validation:Optional
	NodeCount int `json:"nodeCount,omitempty"`
	// NodeCountReady is the number of nodes in the node pool which are ready
	// +kubebuilder:validation:Optional
	
```

And populate data inside there. Fast and relativelly easy fix. But does not add any compartmentalization. Everything still in the cluster controller.

## Option 3

This is very similart to option 1, but we threat NodePools as individual entities and schedule them to clusters.
So Compute is decoupled from Clusters all together. 