Skip to content

Commit ae140f5

Browse files
authored
[improvement] Add NetworkHelper field to LinodeMachineSpec and update instance configuration logic (#806)
* Add NetworkHelper field to LinodeMachineSpec and update instance configuration logic - Introduced a new optional boolean field `NetworkHelper` in `LinodeMachineSpec` to indicate if the network helper should be used, defaulting to true. - Updated the instance configuration logic in `linodemachine_controller.go` to conditionally enable the network helper based on the new field. * Enhance NetworkHelper documentation in LinodeMachineSpec - Updated the comment for the `NetworkHelper` field in `LinodeMachineSpec` to provide clearer guidance on its purpose and usage. - Added a link to the relevant documentation for automatic networking configuration. * disable network helper for flatcar based cluster * update unit tests cases to account for an extra api call during the reconcile loop for linodemachine
1 parent eb218ad commit ae140f5

File tree

8 files changed

+161
-17
lines changed

8 files changed

+161
-17
lines changed

api/v1alpha2/linodemachine_types.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,14 @@ type LinodeMachineSpec struct {
111111
// VPCID is the ID of an existing VPC in Linode. This allows using a VPC that is not managed by CAPL.
112112
// +optional
113113
VPCID *int `json:"vpcID,omitempty"`
114+
115+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
116+
// +optional
117+
// NetworkHelper is an option usually enabled on account level. It helps configure networking automatically for instances.
118+
// You can use this to enable/disable the network helper for a specific instance.
119+
// For more information, see https://techdocs.akamai.com/cloud-computing/docs/automatically-configure-networking
120+
// Defaults to true.
121+
NetworkHelper *bool `json:"networkHelper,omitempty"`
114122
}
115123

116124
// InstanceDisk defines a list of disks to use for an instance

api/v1alpha2/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/infrastructure.cluster.x-k8s.io_linodemachines.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,16 @@ spec:
264264
x-kubernetes-validations:
265265
- message: Value is immutable
266266
rule: self == oldSelf
267+
networkHelper:
268+
description: |-
269+
NetworkHelper is an option usually enabled on account level. It helps configure networking automatically for instances.
270+
You can use this to enable/disable the network helper for a specific instance.
271+
For more information, see https://techdocs.akamai.com/cloud-computing/docs/automatically-configure-networking
272+
Defaults to true.
273+
type: boolean
274+
x-kubernetes-validations:
275+
- message: Value is immutable
276+
rule: self == oldSelf
267277
osDisk:
268278
description: |-
269279
OSDisk is configuration for the root disk that includes the OS,

config/crd/bases/infrastructure.cluster.x-k8s.io_linodemachinetemplates.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,16 @@ spec:
256256
x-kubernetes-validations:
257257
- message: Value is immutable
258258
rule: self == oldSelf
259+
networkHelper:
260+
description: |-
261+
NetworkHelper is an option usually enabled on account level. It helps configure networking automatically for instances.
262+
You can use this to enable/disable the network helper for a specific instance.
263+
For more information, see https://techdocs.akamai.com/cloud-computing/docs/automatically-configure-networking
264+
Defaults to true.
265+
type: boolean
266+
x-kubernetes-validations:
267+
- message: Value is immutable
268+
rule: self == oldSelf
259269
osDisk:
260270
description: |-
261271
OSDisk is configuration for the root disk that includes the OS,

docs/src/reference/out.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,7 @@ _Appears in:_
621621
| `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. | | |
622622
| `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. | | |
623623
| `vpcID` _integer_ | VPCID is the ID of an existing VPC in Linode. This allows using a VPC that is not managed by CAPL. | | |
624+
| `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. | | |
624625

625626

626627
#### LinodeMachineStatus

internal/controller/linodemachine_controller.go

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -618,18 +618,35 @@ func (r *LinodeMachineReconciler) reconcilePreflightConfigure(ctx context.Contex
618618
})
619619
return ctrl.Result{RequeueAfter: reconciler.DefaultMachineControllerWaitForRunningDelay}, nil
620620
}
621+
622+
configData := linodego.InstanceConfigUpdateOptions{
623+
Helpers: &linodego.InstanceConfigHelpers{
624+
Network: true,
625+
},
626+
}
627+
621628
if machineScope.LinodeMachine.Spec.Configuration != nil && machineScope.LinodeMachine.Spec.Configuration.Kernel != "" {
622-
instanceConfig, err := getDefaultInstanceConfig(ctx, machineScope, instanceID)
623-
if err != nil {
624-
logger.Error(err, "Failed to get default instance configuration")
625-
return retryIfTransient(err, logger)
626-
}
629+
configData.Kernel = machineScope.LinodeMachine.Spec.Configuration.Kernel
630+
}
627631

628-
if _, err := machineScope.LinodeClient.UpdateInstanceConfig(ctx, instanceID, instanceConfig.ID, linodego.InstanceConfigUpdateOptions{Kernel: machineScope.LinodeMachine.Spec.Configuration.Kernel}); err != nil {
629-
logger.Error(err, "Failed to update default instance configuration")
630-
return retryIfTransient(err, logger)
632+
// For cases where the network helper is not enabled on account level, we can enable it per instance level
633+
// Default is true, so we only need to update if it's explicitly set to false
634+
if machineScope.LinodeMachine.Spec.NetworkHelper != nil {
635+
configData.Helpers = &linodego.InstanceConfigHelpers{
636+
Network: *machineScope.LinodeMachine.Spec.NetworkHelper,
631637
}
632638
}
639+
640+
instanceConfig, err := getDefaultInstanceConfig(ctx, machineScope, instanceID)
641+
if err != nil {
642+
logger.Error(err, "Failed to get default instance configuration")
643+
return retryIfTransient(err, logger)
644+
}
645+
if _, err := machineScope.LinodeClient.UpdateInstanceConfig(ctx, instanceID, instanceConfig.ID, configData); err != nil {
646+
logger.Error(err, "Failed to update default instance configuration")
647+
return retryIfTransient(err, logger)
648+
}
649+
633650
conditions.Set(machineScope.LinodeMachine, metav1.Condition{
634651
Type: ConditionPreflightConfigured,
635652
Status: metav1.ConditionTrue,

internal/controller/linodemachine_controller_test.go

Lines changed: 100 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,17 @@ var _ = Describe("create", Label("machine", "create"), func() {
229229
createInst := mockLinodeClient.EXPECT().
230230
OnAfterResponse(gomock.Any()).
231231
Return()
232+
listInstConfs := mockLinodeClient.EXPECT().
233+
ListInstanceConfigs(ctx, 123, gomock.Any()).
234+
After(createInst).
235+
Return([]linodego.InstanceConfig{{
236+
ID: 1,
237+
}}, nil)
238+
mockLinodeClient.EXPECT().UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
239+
Helpers: &linodego.InstanceConfigHelpers{Network: true},
240+
}).
241+
After(listInstConfs).
242+
Return(nil, nil)
232243
bootInst := mockLinodeClient.EXPECT().
233244
BootInstance(ctx, 123, 0).
234245
After(createInst).
@@ -374,6 +385,17 @@ var _ = Describe("create", Label("machine", "create"), func() {
374385
createInst := mockLinodeClient.EXPECT().
375386
OnAfterResponse(gomock.Any()).
376387
Return()
388+
listInstConfs := mockLinodeClient.EXPECT().
389+
ListInstanceConfigs(ctx, 123, gomock.Any()).
390+
After(createInst).
391+
Return([]linodego.InstanceConfig{{
392+
ID: 1,
393+
}}, nil)
394+
mockLinodeClient.EXPECT().UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
395+
Helpers: &linodego.InstanceConfigHelpers{Network: true},
396+
}).
397+
After(listInstConfs).
398+
Return(nil, nil)
377399
bootInst := mockLinodeClient.EXPECT().
378400
BootInstance(ctx, 123, 0).
379401
After(createInst).
@@ -441,6 +463,17 @@ var _ = Describe("create", Label("machine", "create"), func() {
441463
mockLinodeClient.EXPECT().
442464
OnAfterResponse(gomock.Any()).
443465
Return()
466+
listInstConfs := mockLinodeClient.EXPECT().
467+
ListInstanceConfigs(ctx, 123, gomock.Any()).
468+
After(createInst).
469+
Return([]linodego.InstanceConfig{{
470+
ID: 1,
471+
}}, nil)
472+
mockLinodeClient.EXPECT().UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
473+
Helpers: &linodego.InstanceConfigHelpers{Network: true},
474+
}).
475+
After(listInstConfs).
476+
Return(nil, nil)
444477
bootInst := mockLinodeClient.EXPECT().
445478
BootInstance(ctx, 123, 0).
446479
After(createInst).
@@ -527,6 +560,17 @@ var _ = Describe("create", Label("machine", "create"), func() {
527560
mockLinodeClient.EXPECT().
528561
OnAfterResponse(gomock.Any()).
529562
Return()
563+
listInstConfs := mockLinodeClient.EXPECT().
564+
ListInstanceConfigs(ctx, 123, gomock.Any()).
565+
After(createInst).
566+
Return([]linodego.InstanceConfig{{
567+
ID: 1,
568+
}}, nil)
569+
mockLinodeClient.EXPECT().UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
570+
Helpers: &linodego.InstanceConfigHelpers{Network: true},
571+
}).
572+
After(listInstConfs).
573+
Return(nil, nil)
530574
bootInst := mockLinodeClient.EXPECT().
531575
BootInstance(ctx, 123, 0).
532576
After(listInst).
@@ -727,7 +771,7 @@ var _ = Describe("create", Label("machine", "create"), func() {
727771
GetImage(ctx, gomock.Any()).
728772
After(getRegion).
729773
Return(&linodego.Image{Capabilities: []string{"cloud-init"}}, nil)
730-
createInst := mockLinodeClient.EXPECT().
774+
mockLinodeClient.EXPECT().
731775
CreateInstance(ctx, gomock.Any()).
732776
After(getImage).
733777
Return(&linodego.Instance{
@@ -739,17 +783,19 @@ var _ = Describe("create", Label("machine", "create"), func() {
739783
mockLinodeClient.EXPECT().
740784
OnAfterResponse(gomock.Any()).
741785
Return()
742-
listInstConfs := mockLinodeClient.EXPECT().
786+
mockLinodeClient.EXPECT().
743787
ListInstanceConfigs(ctx, 123, gomock.Any()).
744-
After(createInst).
745788
Return([]linodego.InstanceConfig{{
789+
ID: 1,
746790
Devices: &linodego.InstanceConfigDeviceMap{
747791
SDA: &linodego.InstanceConfigDevice{DiskID: 100},
748792
},
749-
}}, nil).MaxTimes(2)
793+
}}, nil).MaxTimes(3)
794+
mockLinodeClient.EXPECT().UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
795+
Helpers: &linodego.InstanceConfigHelpers{Network: true},
796+
}).Return(nil, nil)
750797
getInstDisk := mockLinodeClient.EXPECT().
751798
GetInstanceDisk(ctx, 123, 100).
752-
After(listInstConfs).
753799
Return(&linodego.InstanceDisk{ID: 100, Size: 15000}, nil)
754800
resizeInstDisk := mockLinodeClient.EXPECT().
755801
ResizeInstanceDisk(ctx, 123, 100, 4262).
@@ -767,12 +813,13 @@ var _ = Describe("create", Label("machine", "create"), func() {
767813
ListInstanceConfigs(ctx, 123, gomock.Any()).
768814
After(createEtcdDisk).
769815
Return([]linodego.InstanceConfig{{
816+
ID: 1,
770817
Devices: &linodego.InstanceConfigDeviceMap{
771818
SDA: &linodego.InstanceConfigDevice{DiskID: 100},
772819
},
773-
}}, nil).MaxTimes(2)
820+
}}, nil).MaxTimes(3)
774821
createInstanceProfile := mockLinodeClient.EXPECT().
775-
UpdateInstanceConfig(ctx, 123, 0, linodego.InstanceConfigUpdateOptions{
822+
UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
776823
Devices: &linodego.InstanceConfigDeviceMap{
777824
SDA: &linodego.InstanceConfigDevice{DiskID: 100},
778825
SDB: &linodego.InstanceConfigDevice{DiskID: 101},
@@ -890,10 +937,16 @@ var _ = Describe("create", Label("machine", "create"), func() {
890937
ListInstanceConfigs(ctx, 123, gomock.Any()).
891938
After(createInst).
892939
Return([]linodego.InstanceConfig{{
940+
ID: 1,
893941
Devices: &linodego.InstanceConfigDeviceMap{
894942
SDA: &linodego.InstanceConfigDevice{DiskID: 100},
895943
},
896944
}}, nil)
945+
mockLinodeClient.EXPECT().UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
946+
Helpers: &linodego.InstanceConfigHelpers{Network: true},
947+
}).
948+
After(listInstConfs).
949+
Return(nil, nil)
897950
getInstDisk := mockLinodeClient.EXPECT().
898951
GetInstanceDisk(ctx, 123, 100).
899952
After(listInstConfs).
@@ -933,6 +986,17 @@ var _ = Describe("create", Label("machine", "create"), func() {
933986
Expect(rutil.ConditionTrue(&linodeMachine, ConditionPreflightConfigured)).To(BeFalse())
934987
Expect(rutil.ConditionTrue(&linodeMachine, ConditionPreflightAdditionalDisksCreated)).To(BeFalse())
935988

989+
mockLinodeClient.EXPECT().
990+
ListInstanceConfigs(ctx, 123, gomock.Any()).
991+
Return([]linodego.InstanceConfig{{
992+
ID: 1,
993+
Devices: &linodego.InstanceConfigDeviceMap{
994+
SDA: &linodego.InstanceConfigDevice{DiskID: 100},
995+
},
996+
}}, nil).AnyTimes()
997+
mockLinodeClient.EXPECT().UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
998+
Helpers: &linodego.InstanceConfigHelpers{Network: true},
999+
}).Return(nil, nil).AnyTimes()
9361000
getInst := mockLinodeClient.EXPECT().
9371001
GetInstance(ctx, 123).
9381002
After(createFailedEtcdDisk).
@@ -954,12 +1018,13 @@ var _ = Describe("create", Label("machine", "create"), func() {
9541018
ListInstanceConfigs(ctx, 123, gomock.Any()).
9551019
After(createEtcdDisk).
9561020
Return([]linodego.InstanceConfig{{
1021+
ID: 1,
9571022
Devices: &linodego.InstanceConfigDeviceMap{
9581023
SDA: &linodego.InstanceConfigDevice{DiskID: 100},
9591024
},
960-
}}, nil)
1025+
}}, nil).AnyTimes()
9611026
createInstanceProfile := mockLinodeClient.EXPECT().
962-
UpdateInstanceConfig(ctx, 123, 0, linodego.InstanceConfigUpdateOptions{
1027+
UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
9631028
Devices: &linodego.InstanceConfigDeviceMap{
9641029
SDA: &linodego.InstanceConfigDevice{DiskID: 100},
9651030
SDB: &linodego.InstanceConfigDevice{DiskID: 101},
@@ -1135,6 +1200,17 @@ var _ = Describe("createDNS", Label("machine", "createDNS"), func() {
11351200
mockLinodeClient.EXPECT().
11361201
OnAfterResponse(gomock.Any()).
11371202
Return()
1203+
listInstConfs := mockLinodeClient.EXPECT().
1204+
ListInstanceConfigs(ctx, 123, gomock.Any()).
1205+
After(createInst).
1206+
Return([]linodego.InstanceConfig{{
1207+
ID: 1,
1208+
}}, nil)
1209+
mockLinodeClient.EXPECT().UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
1210+
Helpers: &linodego.InstanceConfigHelpers{Network: true},
1211+
}).
1212+
After(listInstConfs).
1213+
Return(nil, nil)
11381214
bootInst := mockLinodeClient.EXPECT().
11391215
BootInstance(ctx, 123, 0).
11401216
After(createInst).
@@ -2435,6 +2511,17 @@ var _ = Describe("machine in vlan", Label("machine", "vlan"), Ordered, func() {
24352511
mockLinodeClient.EXPECT().
24362512
OnAfterResponse(gomock.Any()).
24372513
Return()
2514+
listInstConfs := mockLinodeClient.EXPECT().
2515+
ListInstanceConfigs(ctx, 123, gomock.Any()).
2516+
After(createInst).
2517+
Return([]linodego.InstanceConfig{{
2518+
ID: 1,
2519+
}}, nil)
2520+
mockLinodeClient.EXPECT().UpdateInstanceConfig(ctx, 123, 1, linodego.InstanceConfigUpdateOptions{
2521+
Helpers: &linodego.InstanceConfigHelpers{Network: true},
2522+
}).
2523+
After(listInstConfs).
2524+
Return(nil, nil)
24382525
bootInst := mockLinodeClient.EXPECT().
24392526
BootInstance(ctx, 123, 0).
24402527
After(createInst).
@@ -2601,6 +2688,10 @@ var _ = Describe("create machine with direct VPCID", Label("machine", "VPCID"),
26012688
},
26022689
}, nil).
26032690
AnyTimes()
2691+
mockLinodeClient.EXPECT().
2692+
UpdateInstanceConfig(gomock.Any(), 12345, 1, gomock.Any()).
2693+
Return(nil, nil).
2694+
AnyTimes()
26042695
mockLinodeClient.EXPECT().
26052696
GetInstanceIPAddresses(gomock.Any(), gomock.Any()).
26062697
Return(&linodego.InstanceIPAddressResponse{

templates/flavors/kubeadm/flatcar/patch-flatcar.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ spec:
117117
configuration:
118118
kernel: linode/direct-disk
119119
diskEncryption: disabled
120+
networkHelper: false
120121
---
121122
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha2
122123
kind: LinodeMachineTemplate
@@ -129,3 +130,4 @@ spec:
129130
configuration:
130131
kernel: linode/direct-disk
131132
diskEncryption: disabled
133+
networkHelper: false

0 commit comments

Comments
 (0)