Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ feat: add support for cluster class #261

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ Set the following environment variables:
- CABPR_WK_REPLICAS
- KUBERNETES_VERSION

for example :
for example:

```bash
export CABPR_NAMESPACE=example
Expand Down Expand Up @@ -197,6 +197,62 @@ To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

:tada: CONGRATULATIONS ! :tada: You created your first RKE2 cluster with CAPD as an infrastructure provider.

### Using ClusterClass for cluster creation
Danil-Grigorev marked this conversation as resolved.
Show resolved Hide resolved

This provider supports using [ClusterClass](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/proposals/20210526-cluster-class-and-managed-topologies.md), a Cluster API feature that implements an extra level of abstraction on top of the existing Cluster API functionality. The `ClusterClass` object is used to define a collection of template resources (control plane and machine deployment) which are used to generate one or more clusters of the same flavor.

If you are interested in leveraging this functionality, you can refer to the examples [here](./samples/docker/clusterclass/):
- [clusterclass-quick-start.yaml](./samples/docker/clusterclass/clusterclass-quick-start.yaml): creates a sample `ClusterClass` and necessary resources.
- [rke2-sample.yaml](./samples/docker/clusterclass/rke2-sample.yaml): creates a workload cluster using the `ClusterClass`.

As with other sample templates, you will need to set a number environment variables:
- CLUSTER_NAME
- CABPR_CP_REPLICAS
- CABPR_WK_REPLICAS
- KUBERNETES_VERSION
- KIND_IP

for example:

```bash
export CLUSTER_NAME=capd-rke2-clusterclass
export CABPR_CP_REPLICAS=3
export CABPR_WK_REPLICAS=2
export KUBERNETES_VERSION=v1.25.11
export KIND_IP=192.168.20.20
```

**Remember that, since we are using Kind, the value of `KIND_IP` must be an IP address in the range of the `kind` network.**
You can check the range Docker assigns to this network by inspecting it:

```bash
docker network inspect kind
```

The next step is to substitue the values in the YAML using the following commands:

```bash
cat clusterclass-quick-start.yaml | clusterctl generate yaml > clusterclass-example.yaml
```

At this moment, you can take some time to study the resulting YAML, then you can apply it to the management cluster:

```bash
kubectl apply -f clusterclass-example.yaml
```

This will create a new `ClusterClass` template that can be used to provision one or multiple workload clusters of the same flavor.
To do so, you can follow the same procedure and substitute the values in the YAML for the cluster definition:

```bash
cat rke2-sample.yaml | clusterctl generate yaml > rke2-clusterclass-example.yaml
```

And then apply the resulting YAML file to create a cluster from the existing `ClusterClass`.
```bash
kubectl apply -f rke2-clusterclass-example.yaml
```

## Testing the DEV main branch
These instructions are for development purposes initially and will be changed in the future for user facing instructions.

Expand Down
1 change: 1 addition & 0 deletions bootstrap/api/v1beta1/rke2config_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ type RKE2AgentConfig struct {
LoadBalancerPort int `json:"loadBalancerPort,omitempty"`

// Version specifies the rke2 version.
// This field will be deprecated in newer versions of the API and RKE2ControlPlaneSpec.Version will be used instead.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use the +kubebuilder:deprecatedversion:warning="" annotation?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Until we resolve the way we manage the new Version field (here), we're still using this and the other is just a placeholder required by the ClusterClass implementation. The deprecation warning may push people to use the new field while it is technically not supported yet.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could modify the code to use one or the other, and then have the deprecation warning. Initially didn't want to include this in the same PR, but we can do it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say lets do it or create an issue to do it straight afterwards so that its in the API bump release.

//+optional
Version string `json:"version,omitempty"`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -850,7 +850,9 @@ spec:
for all system images.
type: string
version:
description: Version specifies the rke2 version.
description: Version specifies the rke2 version. This field will
be deprecated in newer versions of the API and RKE2ControlPlaneSpec.Version
will be used instead.
type: string
type: object
files:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -869,7 +869,9 @@ spec:
be used for all system images.
type: string
version:
description: Version specifies the rke2 version.
description: Version specifies the rke2 version. This
field will be deprecated in newer versions of the API
and RKE2ControlPlaneSpec.Version will be used instead.
type: string
type: object
files:
Expand Down
2 changes: 1 addition & 1 deletion bootstrap/config/crd/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
commonLabels:
cluster.x-k8s.io/v1beta1: v1alpha1
cluster.x-k8s.io/v1beta1: v1alpha1_v1beta1

# This kustomization.yaml is not intended to be run by itself,
# since it depends on service name and namespace that are out of this kustomize package.
Expand Down
1 change: 1 addition & 0 deletions bootstrap/config/crd/patches/webhook_in_rke2configs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ spec:
path: /convert
conversionReviewVersions:
- v1
- v1beta1
63 changes: 62 additions & 1 deletion controlplane/api/v1alpha1/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ package v1alpha1
import (
"fmt"

apiconversion "k8s.io/apimachinery/pkg/conversion"
utilconversion "sigs.k8s.io/cluster-api/util/conversion"

controlplanev1 "github.com/rancher-sandbox/cluster-api-provider-rke2/controlplane/api/v1beta1"
"sigs.k8s.io/controller-runtime/pkg/conversion"
)
Expand All @@ -28,11 +31,20 @@ func (src *RKE2ControlPlane) ConvertTo(dstRaw conversion.Hub) error {
if !ok {
return fmt.Errorf("not a RKE2ControlPlane: %v", dst)
}

if err := Convert_v1alpha1_RKE2ControlPlane_To_v1beta1_RKE2ControlPlane(src, dst, nil); err != nil {
return err
}

// Manually restore data.
restored := &controlplanev1.RKE2ControlPlane{}
if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok {
return err
}

dst.Spec.MachineTemplate = restored.Spec.MachineTemplate
dst.Spec.Version = restored.Spec.Version
dst.Status = restored.Status

return nil
}

Expand All @@ -46,6 +58,11 @@ func (dst *RKE2ControlPlane) ConvertFrom(srcRaw conversion.Hub) error {
return err
}

// Preserve Hub data on down-conversion
if err := utilconversion.MarshalData(src, dst); err != nil {
return err
}

return nil
}

Expand Down Expand Up @@ -85,6 +102,15 @@ func (src *RKE2ControlPlaneTemplate) ConvertTo(dstRaw conversion.Hub) error {
return err
}

// Manually restore data.
restored := &controlplanev1.RKE2ControlPlaneTemplate{}
if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok {
return err
}

dst.Spec.Template = restored.Spec.Template
dst.Status = restored.Status

return nil
}

Expand All @@ -98,6 +124,11 @@ func (dst *RKE2ControlPlaneTemplate) ConvertFrom(srcRaw conversion.Hub) error {
return err
}

// Preserve Hub data on down-conversion
if err := utilconversion.MarshalData(src, dst); err != nil {
return err
}

return nil
}

Expand Down Expand Up @@ -126,3 +157,33 @@ func (dst *RKE2ControlPlaneTemplateList) ConvertFrom(srcRaw conversion.Hub) erro

return nil
}

func Convert_v1beta1_RKE2ControlPlaneSpec_To_v1alpha1_RKE2ControlPlaneSpec(in *controlplanev1.RKE2ControlPlaneSpec, out *RKE2ControlPlaneSpec, s apiconversion.Scope) error {
// Version was added in v1beta1.
// MachineTemplate was added in v1beta1.
return autoConvert_v1beta1_RKE2ControlPlaneSpec_To_v1alpha1_RKE2ControlPlaneSpec(in, out, s)
}

func Convert_v1beta1_RKE2ControlPlaneStatus_To_v1alpha1_RKE2ControlPlaneStatus(in *controlplanev1.RKE2ControlPlaneStatus, out *RKE2ControlPlaneStatus, s apiconversion.Scope) error {
return autoConvert_v1beta1_RKE2ControlPlaneStatus_To_v1alpha1_RKE2ControlPlaneStatus(in, out, s)
}

func Convert_v1alpha1_RKE2ControlPlaneStatus_To_v1beta1_RKE2ControlPlaneStatus(in *RKE2ControlPlaneStatus, out *controlplanev1.RKE2ControlPlaneStatus, s apiconversion.Scope) error {
return autoConvert_v1alpha1_RKE2ControlPlaneStatus_To_v1beta1_RKE2ControlPlaneStatus(in, out, s)
}

func Convert_v1beta1_RKE2ControlPlaneTemplateSpec_To_v1alpha1_RKE2ControlPlaneTemplateSpec(in *controlplanev1.RKE2ControlPlaneTemplateSpec, out *RKE2ControlPlaneTemplateSpec, s apiconversion.Scope) error {
return autoConvert_v1beta1_RKE2ControlPlaneTemplateSpec_To_v1alpha1_RKE2ControlPlaneTemplateSpec(in, out, s)
}

func Convert_v1alpha1_RKE2ControlPlaneTemplateSpec_To_v1beta1_RKE2ControlPlaneTemplateSpec(in *RKE2ControlPlaneTemplateSpec, out *controlplanev1.RKE2ControlPlaneTemplateSpec, s apiconversion.Scope) error {
return autoConvert_v1alpha1_RKE2ControlPlaneTemplateSpec_To_v1beta1_RKE2ControlPlaneTemplateSpec(in, out, s)
}

func Convert_v1alpha1_RKE2ControlPlaneTemplateStatus_To_v1beta1_RKE2ControlPlaneStatus(in *RKE2ControlPlaneTemplateStatus, out *controlplanev1.RKE2ControlPlaneStatus, s apiconversion.Scope) error {
Comment on lines +160 to +183
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously there were no RKE2ControlPlaneTemplates in use. I think if there are issues with this conversion code, we can remove it.

return nil
}

func Convert_v1beta1_RKE2ControlPlaneStatus_To_v1alpha1_RKE2ControlPlaneTemplateStatus(in *controlplanev1.RKE2ControlPlaneStatus, out *RKE2ControlPlaneTemplateStatus, s apiconversion.Scope) error {
return nil
}
3 changes: 0 additions & 3 deletions controlplane/api/v1alpha1/rke2controlplanetemplate_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@ import (
type RKE2ControlPlaneTemplateSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file

// Foo is an example field of RKE2ControlPlaneTemplate. Edit rke2controlplanetemplate_types.go to remove/update
Foo string `json:"foo,omitempty"`
}

// RKE2ControlPlaneTemplateStatus defines the observed state of RKE2ControlPlaneTemplate.
Expand Down
Loading
Loading