Skip to content

Commit

Permalink
Add MachinePool Machine implementation in core CAPI components
Browse files Browse the repository at this point in the history
  • Loading branch information
Jont828 committed Jul 7, 2023
1 parent 71e6776 commit 6f3892a
Show file tree
Hide file tree
Showing 8 changed files with 648 additions and 12 deletions.
4 changes: 4 additions & 0 deletions api/v1beta1/machine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ const (
// MachineDeploymentNameLabel is the label set on machines if they're controlled by MachineDeployment.
MachineDeploymentNameLabel = "cluster.x-k8s.io/deployment-name"

// MachinePoolNameLabel is the label indicating the name of the MachinePool a Machine is controlled by.
// Note: The value of this label may be a hash if the MachinePool name is longer than 63 characters.
MachinePoolNameLabel = "cluster.x-k8s.io/pool-name"

// MachineControlPlaneNameLabel is the label set on machines if they're controlled by a ControlPlane.
// Note: The value of this label may be a hash if the control plane name is longer than 63 characters.
MachineControlPlaneNameLabel = "cluster.x-k8s.io/control-plane-name"
Expand Down
27 changes: 20 additions & 7 deletions api/v1beta1/machine_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,16 @@ func (m *Machine) validate(old *Machine) error {
var allErrs field.ErrorList
specPath := field.NewPath("spec")
if m.Spec.Bootstrap.ConfigRef == nil && m.Spec.Bootstrap.DataSecretName == nil {
allErrs = append(
allErrs,
field.Required(
specPath.Child("bootstrap", "data"),
"expected either spec.bootstrap.dataSecretName or spec.bootstrap.configRef to be populated",
),
)
// MachinePool Machines don't have a bootstrap configRef, so don't require it. The bootstrap config is instead owned by the MachinePool.
if !isMachinePoolMachine(m) {
allErrs = append(
allErrs,
field.Required(
specPath.Child("bootstrap", "data"),
"expected either spec.bootstrap.dataSecretName or spec.bootstrap.configRef to be populated",
),
)
}
}

if m.Spec.Bootstrap.ConfigRef != nil && m.Spec.Bootstrap.ConfigRef.Namespace != m.Namespace {
Expand Down Expand Up @@ -143,3 +146,13 @@ func (m *Machine) validate(old *Machine) error {
}
return apierrors.NewInvalid(GroupVersion.WithKind("Machine").GroupKind(), m.Name, allErrs)
}

func isMachinePoolMachine(m *Machine) bool {
for _, owner := range m.OwnerReferences {
if owner.Kind == "MachinePool" {
return true
}
}

return false
}
53 changes: 53 additions & 0 deletions api/v1beta1/machine_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,59 @@ func TestMachineClusterNameImmutable(t *testing.T) {
}
}

func TestIsMachinePoolMachine(t *testing.T) {
tests := []struct {
name string
machine Machine
isMPM bool
}{
{
name: "machine is a MachinePoolMachine",
machine: Machine{
ObjectMeta: metav1.ObjectMeta{
OwnerReferences: []metav1.OwnerReference{
{
Kind: "MachinePool",
},
},
},
},
isMPM: true,
},
{
name: "machine is not a MachinePoolMachine",
machine: Machine{
ObjectMeta: metav1.ObjectMeta{
OwnerReferences: []metav1.OwnerReference{
{
Kind: "NotMachinePool",
},
},
},
},
isMPM: false,
},
{
name: "machine is not a MachinePoolMachine, no owner references",
machine: Machine{
ObjectMeta: metav1.ObjectMeta{
OwnerReferences: nil,
},
},
isMPM: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)

result := isMachinePoolMachine(&tt.machine)
g.Expect(result).To(Equal(tt.isMPM))
})
}
}

func TestMachineVersionValidation(t *testing.T) {
tests := []struct {
name string
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# MachinePool Controller
# MachinePool Controller

![](../../../images/cluster-admission-machinepool-controller.png)

Expand Down Expand Up @@ -95,8 +95,11 @@ The `status` object **may** define several fields that do not affect functionali

* `failureReason` - is a string that explains why a fatal error has occurred, if possible.
* `failureMessage` - is a string that holds the message contained by the error.
* `infrastructureMachineKind` - the kind of the InfraMachines. This should be set if the InfrastructureMachinePool plans to support MachinePool Machines.

Example:
**Note:** Infrastructure providers can support MachinePool Machines by having the InfraMachinePool set the `infrastructureMachineKind` to the kind of their InfrastructureMachines. The InfrastructureMachinePool will be responsible for creating InfrastructureMachines as the MachinePool is scaled up, and the MachinePool controller will create Machines for each InfrastructureMachine and set the ownerRef. The InfrastructureMachinePool will be responsible for deleting the Machines as the MachinePool is scaled down in order for the Machine deletion workflow to function properly. In addition, the InfrastructureMachines must also have the following label set by the InfrastructureMachinePool: `cluster.x-k8s.io/cluster-name` and `cluster.x-k8s.io/pool-name`.

Example
```yaml
kind: MyMachinePool
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
Expand All @@ -106,6 +109,7 @@ spec:
- cloud:////my-cloud-provider-id-1
status:
ready: true
infrastructureMachineKind: InfrastructureMachine
```

#### Externally Managed Autoscaler
Expand Down Expand Up @@ -133,6 +137,7 @@ spec:
status:
ready: true
phase: Scaling
infrastructureMachineKind: InfrastructureMachine
```

It is the provider's responsibility to update Cluster API's `Spec.Replicas` property to the value observed in the underlying infra environment as it changes in response to external autoscaling behaviors. Once that is done, and the number of providerID items is equal to the `Spec.Replicas` property, the MachinePools's `Status.Phase` property will be set to `Running` by Cluster API.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ maintainers of providers and consumers of our Go API.

### API Changes

-
- InfrastructureMachinePools now include an optional status field for `infrastructureMachineKind`. This allows infrastructure providers to support MachinePool Machines by having the InfraMachinePool set the `infrastructureMachineKind` to the kind of their InfrastructureMachines. The InfrastructureMachinePool will be responsible for creating InfrastructureMachines as the MachinePool is scaled up, and the MachinePool controller will create Machines for each InfrastructureMachine and set the ownerRef. The InfrastructureMachinePool will be responsible for deleting the Machines as the MachinePool is scaled down in order for the Machine deletion workflow to function properly. In addition, the InfrastructureMachines must also have the following labels set by the InfrastructureMachinePool: `cluster.x-k8s.io/cluster-name` and `cluster.x-k8s.io/pool-name`. See the [MachinePool Machines proposal](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/proposals/20220209-machinepool-machines.md) for more details and the [CAPD implementation](https://github.com/kubernetes-sigs/cluster-api/pull/8842) for a reference.

### Other

Expand Down
5 changes: 3 additions & 2 deletions docs/book/src/reference/labels_and_annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@


| Label | Note |
|:------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| :---------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| cluster.x-k8s.io/cluster-name | It is set on machines linked to a cluster and external objects(bootstrap and infrastructure providers). |
| topology.cluster.x-k8s.io/owned | It is set on all the object which are managed as part of a ClusterTopology. |
| topology.cluster.x-k8s.io/deployment-name | It is set on the generated MachineDeployment objects to track the name of the MachineDeployment topology it represents. |
Expand All @@ -13,14 +13,15 @@
| cluster.x-k8s.io/set-name | It is set on machines if they're controlled by MachineSet. The value of this label may be a hash if the MachineSet name is longer than 63 characters. |
| cluster.x-k8s.io/control-plane-name | It is set on machines if they're controlled by a control plane. The value of this label may be a hash if the control plane name is longer than 63 characters. |
| cluster.x-k8s.io/deployment-name | It is set on machines if they're controlled by a MachineDeployment. |
| cluster.x-k8s.io/pool-name | It is set on machines if they're controlled by a MachinePool. |
| machine-template-hash | It is applied to Machines in a MachineDeployment containing the hash of the template. |
<br>


**Supported Annotations:**

| Annotation | Note |
|:-----------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| :--------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| clusterctl.cluster.x-k8s.io/skip-crd-name-preflight-check | Can be placed on provider CRDs, so that clusterctl doesn't emit an error if the CRD doesn't comply with Cluster APIs naming scheme. Only CRDs that are referenced by core Cluster API CRDs have to comply with the naming scheme. |
| clusterctl.cluster.x-k8s.io/delete-for-move | DeleteForMoveAnnotation will be set to objects that are going to be deleted from the source cluster after being moved to the target cluster during the clusterctl move operation. It will help any validation webhook to take decision based on it. |
| unsafe.topology.cluster.x-k8s.io/disable-update-class-name-check | It can be used to disable the webhook check on update that disallows a pre-existing Cluster to be populated with Topology information and Class. |
Expand Down
Loading

0 comments on commit 6f3892a

Please sign in to comment.