Skip to content

Commit 12ba433

Browse files
authored
[feat] adding vpcref to linodemachine (#553)
* feat: adding vpcref to linodemachine which is prioritized over linodecluster vpcref * Update e2e test * Add envtest test cases for VPCref
1 parent ab23ac2 commit 12ba433

22 files changed

+625
-10
lines changed

api/v1alpha1/zz_generated.conversion.go

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v1alpha2/linodemachine_types.go

+5
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ type LinodeMachineSpec struct {
101101
// +optional
102102
// FirewallRef is a reference to a firewall object. This makes the linode use the specified firewall.
103103
FirewallRef *corev1.ObjectReference `json:"firewallRef,omitempty"`
104+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
105+
// +optional
106+
// VPCRef is a reference to a LinodeVPC resource. If specified, this takes precedence over
107+
// the cluster-level VPC configuration for multi-region support.
108+
VPCRef *corev1.ObjectReference `json:"vpcRef,omitempty"`
104109
}
105110

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

api/v1alpha2/zz_generated.deepcopy.go

+5
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

+49
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,55 @@ spec:
744744
x-kubernetes-validations:
745745
- message: Value is immutable
746746
rule: self == oldSelf
747+
vpcRef:
748+
description: |-
749+
VPCRef is a reference to a LinodeVPC resource. If specified, this takes precedence over
750+
the cluster-level VPC configuration for multi-region support.
751+
properties:
752+
apiVersion:
753+
description: API version of the referent.
754+
type: string
755+
fieldPath:
756+
description: |-
757+
If referring to a piece of an object instead of an entire object, this string
758+
should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2].
759+
For example, if the object reference is to a container within a pod, this would take on a value like:
760+
"spec.containers{name}" (where "name" refers to the name of the container that triggered
761+
the event) or if no container name is specified "spec.containers[2]" (container with
762+
index 2 in this pod). This syntax is chosen only to have some well-defined way of
763+
referencing a part of an object.
764+
TODO: this design is not final and this field is subject to change in the future.
765+
type: string
766+
kind:
767+
description: |-
768+
Kind of the referent.
769+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
770+
type: string
771+
name:
772+
description: |-
773+
Name of the referent.
774+
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
775+
type: string
776+
namespace:
777+
description: |-
778+
Namespace of the referent.
779+
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/
780+
type: string
781+
resourceVersion:
782+
description: |-
783+
Specific resourceVersion to which this reference is made, if any.
784+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
785+
type: string
786+
uid:
787+
description: |-
788+
UID of the referent.
789+
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids
790+
type: string
791+
type: object
792+
x-kubernetes-map-type: atomic
793+
x-kubernetes-validations:
794+
- message: Value is immutable
795+
rule: self == oldSelf
747796
required:
748797
- region
749798
- type

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

+49
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,55 @@ spec:
614614
x-kubernetes-validations:
615615
- message: Value is immutable
616616
rule: self == oldSelf
617+
vpcRef:
618+
description: |-
619+
VPCRef is a reference to a LinodeVPC resource. If specified, this takes precedence over
620+
the cluster-level VPC configuration for multi-region support.
621+
properties:
622+
apiVersion:
623+
description: API version of the referent.
624+
type: string
625+
fieldPath:
626+
description: |-
627+
If referring to a piece of an object instead of an entire object, this string
628+
should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2].
629+
For example, if the object reference is to a container within a pod, this would take on a value like:
630+
"spec.containers{name}" (where "name" refers to the name of the container that triggered
631+
the event) or if no container name is specified "spec.containers[2]" (container with
632+
index 2 in this pod). This syntax is chosen only to have some well-defined way of
633+
referencing a part of an object.
634+
TODO: this design is not final and this field is subject to change in the future.
635+
type: string
636+
kind:
637+
description: |-
638+
Kind of the referent.
639+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
640+
type: string
641+
name:
642+
description: |-
643+
Name of the referent.
644+
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
645+
type: string
646+
namespace:
647+
description: |-
648+
Namespace of the referent.
649+
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/
650+
type: string
651+
resourceVersion:
652+
description: |-
653+
Specific resourceVersion to which this reference is made, if any.
654+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
655+
type: string
656+
uid:
657+
description: |-
658+
UID of the referent.
659+
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids
660+
type: string
661+
type: object
662+
x-kubernetes-map-type: atomic
663+
x-kubernetes-validations:
664+
- message: Value is immutable
665+
rule: self == oldSelf
617666
required:
618667
- region
619668
- type

controller/linodemachine_controller.go

+39
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,16 @@ func (r *LinodeMachineReconciler) reconcileCreate(
260260
}
261261
}
262262

263+
// Should we check if the VPC ref in LinodeCluster is ready? Or is it enough to check if the VPC exists?
264+
if vpcRef := getVPCRefFromScope(machineScope); vpcRef != nil {
265+
if !reconciler.ConditionTrue(machineScope.LinodeMachine, ConditionPreflightLinodeVPCReady) && machineScope.LinodeMachine.Spec.ProviderID == nil {
266+
res, err := r.reconcilePreflightVPC(ctx, logger, machineScope, vpcRef)
267+
if err != nil || !res.IsZero() {
268+
return res, err
269+
}
270+
}
271+
}
272+
263273
if !reconciler.ConditionTrue(machineScope.LinodeMachine, ConditionPreflightMetadataSupportConfigured) && machineScope.LinodeMachine.Spec.ProviderID == nil {
264274
res, err := r.reconcilePreflightMetadataSupportConfigure(ctx, logger, machineScope)
265275
if err != nil || !res.IsZero() {
@@ -305,6 +315,35 @@ func (r *LinodeMachineReconciler) reconcileCreate(
305315
return ctrl.Result{}, nil
306316
}
307317

318+
func (r *LinodeMachineReconciler) reconcilePreflightVPC(ctx context.Context, logger logr.Logger, machineScope *scope.MachineScope, vpcRef *corev1.ObjectReference) (ctrl.Result, error) {
319+
name := vpcRef.Name
320+
namespace := vpcRef.Namespace
321+
if namespace == "" {
322+
namespace = machineScope.LinodeMachine.Namespace
323+
}
324+
linodeVPC := infrav1alpha2.LinodeVPC{
325+
ObjectMeta: metav1.ObjectMeta{
326+
Namespace: namespace,
327+
Name: name,
328+
},
329+
}
330+
if err := machineScope.Client.Get(ctx, client.ObjectKeyFromObject(&linodeVPC), &linodeVPC); err != nil {
331+
logger.Error(err, "Failed to fetch LinodeVPC")
332+
if reconciler.RecordDecayingCondition(machineScope.LinodeMachine,
333+
ConditionPreflightLinodeVPCReady, string(cerrs.CreateClusterError), err.Error(),
334+
reconciler.DefaultTimeout(r.ReconcileTimeout, reconciler.DefaultClusterControllerReconcileTimeout)) {
335+
return ctrl.Result{}, err
336+
}
337+
return ctrl.Result{RequeueAfter: reconciler.DefaultClusterControllerReconcileDelay}, nil
338+
} else if !linodeVPC.Status.Ready {
339+
logger.Info("LinodeVPC is not yet available")
340+
return ctrl.Result{RequeueAfter: reconciler.DefaultClusterControllerReconcileDelay}, nil
341+
}
342+
r.Recorder.Event(machineScope.LinodeMachine, corev1.EventTypeNormal, string(clusterv1.ReadyCondition), "LinodeVPC is now available")
343+
conditions.MarkTrue(machineScope.LinodeMachine, ConditionPreflightLinodeVPCReady)
344+
return ctrl.Result{}, nil
345+
}
346+
308347
func (r *LinodeMachineReconciler) reconcilePreflightLinodeFirewallCheck(ctx context.Context, logger logr.Logger, machineScope *scope.MachineScope) (ctrl.Result, error) {
309348
name := machineScope.LinodeMachine.Spec.FirewallRef.Name
310349
namespace := machineScope.LinodeMachine.Spec.FirewallRef.Namespace

controller/linodemachine_controller_helpers.go

+20-8
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/go-logr/logr"
3030
"github.com/google/uuid"
3131
"github.com/linode/linodego"
32+
corev1 "k8s.io/api/core/v1"
3233
apierrors "k8s.io/apimachinery/pkg/api/errors"
3334
"k8s.io/apimachinery/pkg/api/resource"
3435
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -113,12 +114,11 @@ func newCreateConfig(ctx context.Context, machineScope *scope.MachineScope, logg
113114

114115
fillCreateConfig(createConfig, machineScope)
115116

116-
// if vpc is enabled, attach additional interface as eth0 to linode
117-
if machineScope.LinodeCluster.Spec.VPCRef != nil {
118-
iface, err := getVPCInterfaceConfig(ctx, machineScope, createConfig.Interfaces, logger)
117+
// Check for VPC configuration - first machine level, then cluster level
118+
if vpcRef := getVPCRefFromScope(machineScope); vpcRef != nil {
119+
iface, err := getVPCInterfaceConfig(ctx, machineScope, createConfig.Interfaces, logger, vpcRef)
119120
if err != nil {
120121
logger.Error(err, "Failed to get VPC interface config")
121-
122122
return nil, err
123123
}
124124
if iface != nil {
@@ -380,13 +380,15 @@ func getVlanInterfaceConfig(ctx context.Context, machineScope *scope.MachineScop
380380
}, nil
381381
}
382382

383-
func getVPCInterfaceConfig(ctx context.Context, machineScope *scope.MachineScope, interfaces []linodego.InstanceConfigInterfaceCreateOptions, logger logr.Logger) (*linodego.InstanceConfigInterfaceCreateOptions, error) {
384-
name := machineScope.LinodeCluster.Spec.VPCRef.Name
385-
namespace := machineScope.LinodeCluster.Spec.VPCRef.Namespace
383+
func getVPCInterfaceConfig(ctx context.Context, machineScope *scope.MachineScope, interfaces []linodego.InstanceConfigInterfaceCreateOptions, logger logr.Logger, vpcRef *corev1.ObjectReference) (*linodego.InstanceConfigInterfaceCreateOptions, error) {
384+
// Get namespace from VPC ref or default to machine namespace
385+
namespace := vpcRef.Namespace
386386
if namespace == "" {
387-
namespace = machineScope.LinodeCluster.Namespace
387+
namespace = machineScope.LinodeMachine.Namespace
388388
}
389389

390+
name := vpcRef.Name
391+
390392
logger = logger.WithValues("vpcName", name, "vpcNamespace", namespace)
391393

392394
linodeVPC := infrav1alpha2.LinodeVPC{
@@ -712,3 +714,13 @@ func createInstance(ctx context.Context, logger logr.Logger, machineScope *scope
712714
inst, err := machineScope.LinodeClient.CreateInstance(ctx, *createOpts)
713715
return inst, ctr.RetryAfter(), err
714716
}
717+
718+
// getVPCRefFromScope returns the appropriate VPC reference based on priority:
719+
// 1. Machine-level VPC reference
720+
// 2. Cluster-level VPC reference
721+
func getVPCRefFromScope(machineScope *scope.MachineScope) *corev1.ObjectReference {
722+
if machineScope.LinodeMachine.Spec.VPCRef != nil {
723+
return machineScope.LinodeMachine.Spec.VPCRef
724+
}
725+
return machineScope.LinodeCluster.Spec.VPCRef
726+
}

0 commit comments

Comments
 (0)