Skip to content
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
8 changes: 8 additions & 0 deletions api/v1alpha2/linodemachine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ type LinodeMachineSpec struct {
// VPCID is the ID of an existing VPC in Linode. This allows using a VPC that is not managed by CAPL.
// +optional
VPCID *int `json:"vpcID,omitempty"`

// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
// +optional
// NetworkHelper is an option usually enabled on account level. It helps configure networking automatically for instances.
// You can use this to enable/disable the network helper for a specific instance.
// For more information, see https://techdocs.akamai.com/cloud-computing/docs/automatically-configure-networking
// Defaults to true.
NetworkHelper *bool `json:"networkHelper,omitempty"`
}

// InstanceDisk defines a list of disks to use for an instance
Expand Down
5 changes: 5 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 @@ -264,6 +264,16 @@ spec:
x-kubernetes-validations:
- message: Value is immutable
rule: self == oldSelf
networkHelper:
description: |-
NetworkHelper is an option usually enabled on account level. It helps configure networking automatically for instances.
You can use this to enable/disable the network helper for a specific instance.
For more information, see https://techdocs.akamai.com/cloud-computing/docs/automatically-configure-networking
Defaults to true.
type: boolean
x-kubernetes-validations:
- message: Value is immutable
rule: self == oldSelf
osDisk:
description: |-
OSDisk is configuration for the root disk that includes the OS,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,16 @@ spec:
x-kubernetes-validations:
- message: Value is immutable
rule: self == oldSelf
networkHelper:
description: |-
NetworkHelper is an option usually enabled on account level. It helps configure networking automatically for instances.
You can use this to enable/disable the network helper for a specific instance.
For more information, see https://techdocs.akamai.com/cloud-computing/docs/automatically-configure-networking
Defaults to true.
type: boolean
x-kubernetes-validations:
- message: Value is immutable
rule: self == oldSelf
osDisk:
description: |-
OSDisk is configuration for the root disk that includes the OS,
Expand Down
1 change: 1 addition & 0 deletions docs/src/reference/out.md
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,7 @@ _Appears in:_
| `firewallRef` _[ObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#objectreference-v1-core)_ | FirewallRef is a reference to a firewall object. This makes the linode use the specified firewall. | | |
| `vpcRef` _[ObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#objectreference-v1-core)_ | VPCRef is a reference to a LinodeVPC resource. If specified, this takes precedence over<br />the cluster-level VPC configuration for multi-region support. | | |
| `vpcID` _integer_ | VPCID is the ID of an existing VPC in Linode. This allows using a VPC that is not managed by CAPL. | | |
| `networkHelper` _boolean_ | NetworkHelper is an option usually enabled on account level. It helps configure networking automatically for instances.<br />You can use this to enable/disable the network helper for a specific instance.<br />For more information, see https://techdocs.akamai.com/cloud-computing/docs/automatically-configure-networking<br />Defaults to true. | | |


#### LinodeMachineStatus
Expand Down
33 changes: 25 additions & 8 deletions internal/controller/linodemachine_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -618,18 +618,35 @@ func (r *LinodeMachineReconciler) reconcilePreflightConfigure(ctx context.Contex
})
return ctrl.Result{RequeueAfter: reconciler.DefaultMachineControllerWaitForRunningDelay}, nil
}

configData := linodego.InstanceConfigUpdateOptions{
Helpers: &linodego.InstanceConfigHelpers{
Network: true,
},
}

if machineScope.LinodeMachine.Spec.Configuration != nil && machineScope.LinodeMachine.Spec.Configuration.Kernel != "" {
instanceConfig, err := getDefaultInstanceConfig(ctx, machineScope, instanceID)
if err != nil {
logger.Error(err, "Failed to get default instance configuration")
return retryIfTransient(err, logger)
}
configData.Kernel = machineScope.LinodeMachine.Spec.Configuration.Kernel
}

if _, err := machineScope.LinodeClient.UpdateInstanceConfig(ctx, instanceID, instanceConfig.ID, linodego.InstanceConfigUpdateOptions{Kernel: machineScope.LinodeMachine.Spec.Configuration.Kernel}); err != nil {
logger.Error(err, "Failed to update default instance configuration")
return retryIfTransient(err, logger)
// For cases where the network helper is not enabled on account level, we can enable it per instance level
// Default is true, so we only need to update if it's explicitly set to false
if machineScope.LinodeMachine.Spec.NetworkHelper != nil {
configData.Helpers = &linodego.InstanceConfigHelpers{
Network: *machineScope.LinodeMachine.Spec.NetworkHelper,
}
}

instanceConfig, err := getDefaultInstanceConfig(ctx, machineScope, instanceID)
if err != nil {
logger.Error(err, "Failed to get default instance configuration")
return retryIfTransient(err, logger)
}
if _, err := machineScope.LinodeClient.UpdateInstanceConfig(ctx, instanceID, instanceConfig.ID, configData); err != nil {
logger.Error(err, "Failed to update default instance configuration")
return retryIfTransient(err, logger)
}

conditions.Set(machineScope.LinodeMachine, metav1.Condition{
Type: ConditionPreflightConfigured,
Status: metav1.ConditionTrue,
Expand Down
109 changes: 100 additions & 9 deletions internal/controller/linodemachine_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,17 @@ var _ = Describe("create", Label("machine", "create"), func() {
createInst := mockLinodeClient.EXPECT().
OnAfterResponse(gomock.Any()).
Return()
listInstConfs := mockLinodeClient.EXPECT().
ListInstanceConfigs(ctx, 123, gomock.Any()).
After(createInst).
Return([]linodego.InstanceConfig{{
ID: 1,
}}, nil)
mockLinodeClient.EXPECT().UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
Helpers: &linodego.InstanceConfigHelpers{Network: true},
}).
After(listInstConfs).
Return(nil, nil)
bootInst := mockLinodeClient.EXPECT().
BootInstance(ctx, 123, 0).
After(createInst).
Expand Down Expand Up @@ -374,6 +385,17 @@ var _ = Describe("create", Label("machine", "create"), func() {
createInst := mockLinodeClient.EXPECT().
OnAfterResponse(gomock.Any()).
Return()
listInstConfs := mockLinodeClient.EXPECT().
ListInstanceConfigs(ctx, 123, gomock.Any()).
After(createInst).
Return([]linodego.InstanceConfig{{
ID: 1,
}}, nil)
mockLinodeClient.EXPECT().UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
Helpers: &linodego.InstanceConfigHelpers{Network: true},
}).
After(listInstConfs).
Return(nil, nil)
bootInst := mockLinodeClient.EXPECT().
BootInstance(ctx, 123, 0).
After(createInst).
Expand Down Expand Up @@ -441,6 +463,17 @@ var _ = Describe("create", Label("machine", "create"), func() {
mockLinodeClient.EXPECT().
OnAfterResponse(gomock.Any()).
Return()
listInstConfs := mockLinodeClient.EXPECT().
ListInstanceConfigs(ctx, 123, gomock.Any()).
After(createInst).
Return([]linodego.InstanceConfig{{
ID: 1,
}}, nil)
mockLinodeClient.EXPECT().UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
Helpers: &linodego.InstanceConfigHelpers{Network: true},
}).
After(listInstConfs).
Return(nil, nil)
bootInst := mockLinodeClient.EXPECT().
BootInstance(ctx, 123, 0).
After(createInst).
Expand Down Expand Up @@ -527,6 +560,17 @@ var _ = Describe("create", Label("machine", "create"), func() {
mockLinodeClient.EXPECT().
OnAfterResponse(gomock.Any()).
Return()
listInstConfs := mockLinodeClient.EXPECT().
ListInstanceConfigs(ctx, 123, gomock.Any()).
After(createInst).
Return([]linodego.InstanceConfig{{
ID: 1,
}}, nil)
mockLinodeClient.EXPECT().UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
Helpers: &linodego.InstanceConfigHelpers{Network: true},
}).
After(listInstConfs).
Return(nil, nil)
bootInst := mockLinodeClient.EXPECT().
BootInstance(ctx, 123, 0).
After(listInst).
Expand Down Expand Up @@ -727,7 +771,7 @@ var _ = Describe("create", Label("machine", "create"), func() {
GetImage(ctx, gomock.Any()).
After(getRegion).
Return(&linodego.Image{Capabilities: []string{"cloud-init"}}, nil)
createInst := mockLinodeClient.EXPECT().
mockLinodeClient.EXPECT().
CreateInstance(ctx, gomock.Any()).
After(getImage).
Return(&linodego.Instance{
Expand All @@ -739,17 +783,19 @@ var _ = Describe("create", Label("machine", "create"), func() {
mockLinodeClient.EXPECT().
OnAfterResponse(gomock.Any()).
Return()
listInstConfs := mockLinodeClient.EXPECT().
mockLinodeClient.EXPECT().
ListInstanceConfigs(ctx, 123, gomock.Any()).
After(createInst).
Return([]linodego.InstanceConfig{{
ID: 1,
Devices: &linodego.InstanceConfigDeviceMap{
SDA: &linodego.InstanceConfigDevice{DiskID: 100},
},
}}, nil).MaxTimes(2)
}}, nil).MaxTimes(3)
mockLinodeClient.EXPECT().UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
Helpers: &linodego.InstanceConfigHelpers{Network: true},
}).Return(nil, nil)
getInstDisk := mockLinodeClient.EXPECT().
GetInstanceDisk(ctx, 123, 100).
After(listInstConfs).
Return(&linodego.InstanceDisk{ID: 100, Size: 15000}, nil)
resizeInstDisk := mockLinodeClient.EXPECT().
ResizeInstanceDisk(ctx, 123, 100, 4262).
Expand All @@ -767,12 +813,13 @@ var _ = Describe("create", Label("machine", "create"), func() {
ListInstanceConfigs(ctx, 123, gomock.Any()).
After(createEtcdDisk).
Return([]linodego.InstanceConfig{{
ID: 1,
Devices: &linodego.InstanceConfigDeviceMap{
SDA: &linodego.InstanceConfigDevice{DiskID: 100},
},
}}, nil).MaxTimes(2)
}}, nil).MaxTimes(3)
createInstanceProfile := mockLinodeClient.EXPECT().
UpdateInstanceConfig(ctx, 123, 0, linodego.InstanceConfigUpdateOptions{
UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
Devices: &linodego.InstanceConfigDeviceMap{
SDA: &linodego.InstanceConfigDevice{DiskID: 100},
SDB: &linodego.InstanceConfigDevice{DiskID: 101},
Expand Down Expand Up @@ -890,10 +937,16 @@ var _ = Describe("create", Label("machine", "create"), func() {
ListInstanceConfigs(ctx, 123, gomock.Any()).
After(createInst).
Return([]linodego.InstanceConfig{{
ID: 1,
Devices: &linodego.InstanceConfigDeviceMap{
SDA: &linodego.InstanceConfigDevice{DiskID: 100},
},
}}, nil)
mockLinodeClient.EXPECT().UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
Helpers: &linodego.InstanceConfigHelpers{Network: true},
}).
After(listInstConfs).
Return(nil, nil)
getInstDisk := mockLinodeClient.EXPECT().
GetInstanceDisk(ctx, 123, 100).
After(listInstConfs).
Expand Down Expand Up @@ -933,6 +986,17 @@ var _ = Describe("create", Label("machine", "create"), func() {
Expect(rutil.ConditionTrue(&linodeMachine, ConditionPreflightConfigured)).To(BeFalse())
Expect(rutil.ConditionTrue(&linodeMachine, ConditionPreflightAdditionalDisksCreated)).To(BeFalse())

mockLinodeClient.EXPECT().
ListInstanceConfigs(ctx, 123, gomock.Any()).
Return([]linodego.InstanceConfig{{
ID: 1,
Devices: &linodego.InstanceConfigDeviceMap{
SDA: &linodego.InstanceConfigDevice{DiskID: 100},
},
}}, nil).AnyTimes()
mockLinodeClient.EXPECT().UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
Helpers: &linodego.InstanceConfigHelpers{Network: true},
}).Return(nil, nil).AnyTimes()
getInst := mockLinodeClient.EXPECT().
GetInstance(ctx, 123).
After(createFailedEtcdDisk).
Expand All @@ -954,12 +1018,13 @@ var _ = Describe("create", Label("machine", "create"), func() {
ListInstanceConfigs(ctx, 123, gomock.Any()).
After(createEtcdDisk).
Return([]linodego.InstanceConfig{{
ID: 1,
Devices: &linodego.InstanceConfigDeviceMap{
SDA: &linodego.InstanceConfigDevice{DiskID: 100},
},
}}, nil)
}}, nil).AnyTimes()
createInstanceProfile := mockLinodeClient.EXPECT().
UpdateInstanceConfig(ctx, 123, 0, linodego.InstanceConfigUpdateOptions{
UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
Devices: &linodego.InstanceConfigDeviceMap{
SDA: &linodego.InstanceConfigDevice{DiskID: 100},
SDB: &linodego.InstanceConfigDevice{DiskID: 101},
Expand Down Expand Up @@ -1135,6 +1200,17 @@ var _ = Describe("createDNS", Label("machine", "createDNS"), func() {
mockLinodeClient.EXPECT().
OnAfterResponse(gomock.Any()).
Return()
listInstConfs := mockLinodeClient.EXPECT().
ListInstanceConfigs(ctx, 123, gomock.Any()).
After(createInst).
Return([]linodego.InstanceConfig{{
ID: 1,
}}, nil)
mockLinodeClient.EXPECT().UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
Helpers: &linodego.InstanceConfigHelpers{Network: true},
}).
After(listInstConfs).
Return(nil, nil)
bootInst := mockLinodeClient.EXPECT().
BootInstance(ctx, 123, 0).
After(createInst).
Expand Down Expand Up @@ -2435,6 +2511,17 @@ var _ = Describe("machine in vlan", Label("machine", "vlan"), Ordered, func() {
mockLinodeClient.EXPECT().
OnAfterResponse(gomock.Any()).
Return()
listInstConfs := mockLinodeClient.EXPECT().
ListInstanceConfigs(ctx, 123, gomock.Any()).
After(createInst).
Return([]linodego.InstanceConfig{{
ID: 1,
}}, nil)
mockLinodeClient.EXPECT().UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
Helpers: &linodego.InstanceConfigHelpers{Network: true},
}).
After(listInstConfs).
Return(nil, nil)
bootInst := mockLinodeClient.EXPECT().
BootInstance(ctx, 123, 0).
After(createInst).
Expand Down Expand Up @@ -2601,6 +2688,10 @@ var _ = Describe("create machine with direct VPCID", Label("machine", "VPCID"),
},
}, nil).
AnyTimes()
mockLinodeClient.EXPECT().
UpdateInstanceConfig(gomock.Any(), 12345, 1, gomock.Any()).
Return(nil, nil).
AnyTimes()
mockLinodeClient.EXPECT().
GetInstanceIPAddresses(gomock.Any(), gomock.Any()).
Return(&linodego.InstanceIPAddressResponse{
Expand Down
2 changes: 2 additions & 0 deletions templates/flavors/kubeadm/flatcar/patch-flatcar.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ spec:
configuration:
kernel: linode/direct-disk
diskEncryption: disabled
networkHelper: false
---
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha2
kind: LinodeMachineTemplate
Expand All @@ -129,3 +130,4 @@ spec:
configuration:
kernel: linode/direct-disk
diskEncryption: disabled
networkHelper: false
Loading