Skip to content

Commit

Permalink
Merge branch 'main' into linodeOBJBucket_v1alpha2
Browse files Browse the repository at this point in the history
  • Loading branch information
unnatiagg authored Jul 30, 2024
2 parents b843026 + 3119045 commit 3b2f24e
Show file tree
Hide file tree
Showing 21 changed files with 705 additions and 22 deletions.
2 changes: 2 additions & 0 deletions api/v1alpha1/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions api/v1alpha2/linodemachine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ type LinodeMachineSpec struct {
// DataDisks is a map of any additional disks to add to an instance,
// The sum of these disks + the OSDisk must not be more than allowed on a linodes plan
DataDisks map[string]*InstanceDisk `json:"dataDisks,omitempty"`
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
// +kubebuilder:validation:Enum=enabled;disabled
// DiskEncryption determines if the disks of the instance should be encrypted.
DiskEncryption string `json:"diskEncryption,omitempty"`

// CredentialsRef is a reference to a Secret that contains the credentials
// to use for provisioning this machine. If not supplied then these
Expand All @@ -84,6 +88,10 @@ type LinodeMachineSpec struct {
// +optional
CredentialsRef *corev1.SecretReference `json:"credentialsRef,omitempty"`

// Configuration is the Akamai instance configuration OS,
// if not specified this defaults to the default configuration associated to the instance.
Configuration *InstanceConfiguration `json:"configuration,omitempty"`

// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
// +optional
// PlacementGroupRef is a reference to a placement group object. This makes the linode to be launched in that specific group.
Expand All @@ -110,6 +118,12 @@ type InstanceMetadataOptions struct {
UserData string `json:"userData,omitempty"`
}

// InstanceConfiguration defines the instance configuration
type InstanceConfiguration struct {
// Kernel is a Kernel ID to boot a Linode with. (e.g linode/latest-64bit)
Kernel string `json:"kernel,omitempty"`
}

// InstanceConfigInterfaceCreateOptions defines network interface config
type InstanceConfigInterfaceCreateOptions struct {
IPAMAddress string `json:"ipamAddress,omitempty"`
Expand Down
20 changes: 20 additions & 0 deletions api/v1alpha2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,16 @@ spec:
x-kubernetes-validations:
- message: Value is immutable
rule: self == oldSelf
configuration:
description: |-
Configuration is the Akamai instance configuration OS,
if not specified this defaults to the default configuration associated to the instance.
properties:
kernel:
description: Kernel is a Kernel ID to boot a Linode with. (e.g
linode/latest-64bit)
type: string
type: object
credentialsRef:
description: |-
CredentialsRef is a reference to a Secret that contains the credentials
Expand Down Expand Up @@ -511,6 +521,16 @@ spec:
DataDisks is a map of any additional disks to add to an instance,
The sum of these disks + the OSDisk must not be more than allowed on a linodes plan
type: object
diskEncryption:
description: DiskEncryption determines if the disks of the instance
should be encrypted.
enum:
- enabled
- disabled
type: string
x-kubernetes-validations:
- message: Value is immutable
rule: self == oldSelf
firewallID:
type: integer
x-kubernetes-validations:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,16 @@ spec:
x-kubernetes-validations:
- message: Value is immutable
rule: self == oldSelf
configuration:
description: |-
Configuration is the Akamai instance configuration OS,
if not specified this defaults to the default configuration associated to the instance.
properties:
kernel:
description: Kernel is a Kernel ID to boot a Linode with.
(e.g linode/latest-64bit)
type: string
type: object
credentialsRef:
description: |-
CredentialsRef is a reference to a Secret that contains the credentials
Expand Down Expand Up @@ -376,6 +386,16 @@ spec:
DataDisks is a map of any additional disks to add to an instance,
The sum of these disks + the OSDisk must not be more than allowed on a linodes plan
type: object
diskEncryption:
description: DiskEncryption determines if the disks of the
instance should be encrypted.
enum:
- enabled
- disabled
type: string
x-kubernetes-validations:
- message: Value is immutable
rule: self == oldSelf
firewallID:
type: integer
x-kubernetes-validations:
Expand Down
36 changes: 30 additions & 6 deletions controller/linodemachine_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ func (r *LinodeMachineReconciler) reconcileCreate(
return r.reconcileInstanceCreate(ctx, logger, machineScope, linodeInstance)
}

//nolint:cyclop,gocognit // It is ok for the moment but need larger refactor.
func (r *LinodeMachineReconciler) reconcileInstanceCreate(
ctx context.Context,
logger logr.Logger,
Expand All @@ -357,6 +358,18 @@ func (r *LinodeMachineReconciler) reconcileInstanceCreate(
conditions.MarkTrue(machineScope.LinodeMachine, ConditionPreflightConfigured)
}

if machineScope.LinodeMachine.Spec.Configuration != nil && machineScope.LinodeMachine.Spec.Configuration.Kernel != "" {
instanceConfig, err := r.getDefaultInstanceConfig(ctx, machineScope, linodeInstance.ID)
if err != nil {
logger.Error(err, "Failed to get default instance configuration")
return ctrl.Result{}, err
}

if _, err := machineScope.LinodeClient.UpdateInstanceConfig(ctx, linodeInstance.ID, instanceConfig.ID, linodego.InstanceConfigUpdateOptions{Kernel: machineScope.LinodeMachine.Spec.Configuration.Kernel}); err != nil {
return ctrl.Result{}, err
}
}

if !reconciler.ConditionTrue(machineScope.LinodeMachine, ConditionPreflightBootTriggered) {
if err := machineScope.LinodeClient.BootInstance(ctx, linodeInstance.ID, 0); err != nil && !strings.HasSuffix(err.Error(), "already booted.") {
logger.Error(err, "Failed to boot instance")
Expand Down Expand Up @@ -529,16 +542,14 @@ func (r *LinodeMachineReconciler) resizeRootDisk(
if reconciler.ConditionTrue(machineScope.LinodeMachine, ConditionPreflightRootDiskResized) {
return nil
}
// get the default instance config
configs, err := machineScope.LinodeClient.ListInstanceConfigs(ctx, linodeInstanceID, &linodego.ListOptions{})
if err != nil || len(configs) == 0 {
logger.Error(err, "Failed to list instance configs")

conditions.MarkFalse(machineScope.LinodeMachine, ConditionPreflightRootDiskResized, string(cerrs.CreateMachineError), clusterv1.ConditionSeverityWarning, err.Error())
instanceConfig, err := r.getDefaultInstanceConfig(ctx, machineScope, linodeInstanceID)
if err != nil {
logger.Error(err, "Failed to get default instance configuration")

conditions.MarkFalse(machineScope.LinodeMachine, ConditionPreflightRootDiskResized, string(cerrs.CreateMachineError), clusterv1.ConditionSeverityWarning, err.Error())
return err
}
instanceConfig := configs[0]

if instanceConfig.Devices.SDA == nil {
conditions.MarkFalse(machineScope.LinodeMachine, ConditionPreflightRootDiskResized, string(cerrs.CreateMachineError), clusterv1.ConditionSeverityWarning, "root disk not yet ready")
Expand Down Expand Up @@ -779,3 +790,16 @@ func (r *LinodeMachineReconciler) SetupWithManager(mgr ctrl.Manager, options crc
func (r *LinodeMachineReconciler) TracedClient() client.Client {
return wrappedruntimeclient.NewRuntimeClientWithTracing(r.Client, wrappedruntimeclient.DefaultDecorator())
}

func (r *LinodeMachineReconciler) getDefaultInstanceConfig(
ctx context.Context,
machineScope *scope.MachineScope,
linodeInstanceID int,
) (linodego.InstanceConfig, error) {
configs, err := machineScope.LinodeClient.ListInstanceConfigs(ctx, linodeInstanceID, &linodego.ListOptions{})
if err != nil || len(configs) == 0 {
return linodego.InstanceConfig{}, fmt.Errorf("failing to list instance configurations: %w", err)
}

return configs[0], nil
}
15 changes: 8 additions & 7 deletions controller/linodemachine_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,10 @@ var _ = Describe("create", Label("machine", "create"), func() {
UID: "12345",
},
Spec: infrav1alpha2.LinodeMachineSpec{
InstanceID: ptr.To(0),
Type: "g6-nanode-1",
Image: rutil.DefaultMachineControllerLinodeImage,
InstanceID: ptr.To(0),
Type: "g6-nanode-1",
Image: rutil.DefaultMachineControllerLinodeImage,
DiskEncryption: string(linodego.InstanceDiskEncryptionEnabled),
},
}
reconciler = &LinodeMachineReconciler{
Expand Down Expand Up @@ -141,7 +142,7 @@ var _ = Describe("create", Label("machine", "create"), func() {
getRegion := mockLinodeClient.EXPECT().
GetRegion(ctx, gomock.Any()).
After(listInst).
Return(&linodego.Region{Capabilities: []string{"Metadata"}}, nil)
Return(&linodego.Region{Capabilities: []string{linodego.CapabilityMetadata, linodego.CapabilityDiskEncryption}}, nil)
getImage := mockLinodeClient.EXPECT().
GetImage(ctx, gomock.Any()).
After(getRegion).
Expand Down Expand Up @@ -227,7 +228,7 @@ var _ = Describe("create", Label("machine", "create"), func() {
getRegion := mockLinodeClient.EXPECT().
GetRegion(ctx, gomock.Any()).
After(listInst).
Return(&linodego.Region{Capabilities: []string{"Metadata"}}, nil)
Return(&linodego.Region{Capabilities: []string{linodego.CapabilityMetadata, linodego.CapabilityDiskEncryption}}, nil)
getImage := mockLinodeClient.EXPECT().
GetImage(ctx, gomock.Any()).
After(getRegion).
Expand Down Expand Up @@ -309,7 +310,7 @@ var _ = Describe("create", Label("machine", "create"), func() {
getRegion := mockLinodeClient.EXPECT().
GetRegion(ctx, gomock.Any()).
After(listInst).
Return(&linodego.Region{Capabilities: []string{"Metadata"}}, nil)
Return(&linodego.Region{Capabilities: []string{linodego.CapabilityMetadata, linodego.CapabilityDiskEncryption}}, nil)
getImage := mockLinodeClient.EXPECT().
GetImage(ctx, gomock.Any()).
After(getRegion).
Expand Down Expand Up @@ -460,7 +461,7 @@ var _ = Describe("create", Label("machine", "create"), func() {
getRegion := mockLinodeClient.EXPECT().
GetRegion(ctx, gomock.Any()).
After(listInst).
Return(&linodego.Region{Capabilities: []string{"Metadata"}}, nil)
Return(&linodego.Region{Capabilities: []string{linodego.CapabilityMetadata, linodego.CapabilityDiskEncryption}}, nil)
getImage := mockLinodeClient.EXPECT().
GetImage(ctx, gomock.Any()).
After(getRegion).
Expand Down
56 changes: 56 additions & 0 deletions docs/src/topics/flavors/flatcar.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Flatcar

This flavor supports provisioning k8s clusters outside of VPC using [Flatcar][flatcar] as a base OS. It uses kubeadm for
setting up control plane and uses cilium with VXLAN for pod networking.

## Specification
| Supported Control Plane | CNI | Default OS | Installs ClusterClass | IPv4 | IPv6 |
|-------------------------|--------|--------------|-----------------------|------|------|
| kubeadm | Cilium | Flatcar | No | Yes | No |

## Notes
This flavor is identical to the default flavor with the exception that it provisions
k8s clusters without VPC using [Flatcar][flatcar] as a base OS. Since it runs outside of VPC, native routing is not
supported in this flavor and it uses VXLAN for pod to pod communication.

## Usage

### Initialization

Before generating the cluster configuration, it is required to initialize the management cluster with [Ignition][ignition] support to provision Flatcar nodes:

```bash
export EXP_KUBEADM_BOOTSTRAP_FORMAT_IGNITION=true
clusterctl init --infrastructure linode-linode --addon helm
```

### Import the Flatcar image

Flatcar is not officially provided by Akamai/Linode so it is required to import a Flatcar image. Akamai support is available on Flatcar since the release [4012.0.0][release-4012]: all releases equal or greater than this major release will fit.

To import the image, it is recommended to follow this documentation: https://www.flatcar.org/docs/latest/installing/community-platforms/akamai/#importing-an-image

By following this import step, you will get the Flatcar image ID stored into `IMAGE_ID`.

### Configure and deploy the workload cluster

1. Set the Flatcar image name from the previous step:
```bash
export FLATCAR_IMAGE_NAME="${IMAGE_ID}"
```

2. Generate cluster yaml
```bash
clusterctl generate cluster test-cluster \
--kubernetes-version v1.29.1 \
--infrastructure linode-linode \
--flavor kubeadm-flatcar > test-cluster.yaml
```
2. Apply cluster yaml
```bash
kubectl apply -f test-cluster.yaml
```

[flatcar]: https://www.flatcar.org/
[ignition]: https://coreos.github.io/ignition/
[release-4012]: https://www.flatcar.org/releases#release-4012.0.0
6 changes: 3 additions & 3 deletions docs/src/topics/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ export LINODE_MACHINE_TYPE=g6-standard-2
For Regions and Images that do not yet support Akamai's cloud-init datasource CAPL will automatically use a stackscript shim
to provision the node. If you are using a custom image ensure the [cloud_init](https://www.linode.com/docs/api/images/#image-create) flag is set correctly on it
```
```admonish warning
By default, clusters are provisioned within VPC. For Regions which do not have [VPC support](https://www.linode.com/docs/products/networking/vpc/#availability) yet, use the [VPCLess](./flavors/vpcless.md) flavor to have clusters provisioned.
```
~~~admonish warning
By default, clusters are provisioned within VPC with disk encryption enabled. For Regions which do not have [VPC support](https://www.linode.com/docs/products/networking/vpc/#availability) yet, use the [VPCLess](./flavors/vpcless.md) flavor to have clusters provisioned. For disabling disk encryption, set `spec.template.spec.diskEncryption=disabled` in your generated LinodeMachineTemplate resources when creating a CAPL cluster.
~~~

## Install CAPL on your management cluster
```admonish warning
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: capi-controller-manager
namespace: capi-system
status:
availableReplicas: 1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: capl-controller-manager
namespace: capl-system
status:
availableReplicas: 1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: capi-kubeadm-bootstrap-controller-manager
namespace: kubeadm-bootstrap-system
status:
availableReplicas: 1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: capi-kubeadm-control-plane-controller-manager
namespace: kubeadm-control-plane-system
status:
availableReplicas: 1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: caaph-controller-manager
namespace: caaph-system
status:
availableReplicas: 1
Loading

0 comments on commit 3b2f24e

Please sign in to comment.