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
2 changes: 1 addition & 1 deletion api/v1alpha2/linodemachine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ type LinodeMachineSpec struct {
PrivateIP *bool `json:"privateIP,omitempty"`
// Tags is a list of tags to apply to the Linode instance.
Tags []string `json:"tags,omitempty"`
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
// FirewallID is the id of the cloud firewall to apply to the Linode Instance
FirewallID int `json:"firewallID,omitempty"`
// OSDisk is configuration for the root disk that includes the OS,
// if not specified this defaults to whatever space is not taken up by the DataDisks
Expand Down
4 changes: 4 additions & 0 deletions api/v1alpha2/linodemachinetemplate_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ type LinodeMachineTemplateStatus struct {
// +optional
Tags []string `json:"tags,omitempty"`

// Firewall ID that is currently applied to the LinodeMachineTemplate.
// +optional
FirewallID int `json:"firewallID,omitempty"`

// Conditions represent the latest available observations of a LinodeMachineTemplate's current state.
// +optional
Conditions []metav1.Condition `json:"conditions,omitempty"`
Expand Down
2 changes: 2 additions & 0 deletions clients/clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ type LinodeInstanceClient interface {
GetRegion(ctx context.Context, regionID string) (*linodego.Region, error)
GetImage(ctx context.Context, imageID string) (*linodego.Image, error)
GetType(ctx context.Context, typeID string) (*linodego.LinodeType, error)
ListInstanceFirewalls(ctx context.Context, linodeID int, opts *linodego.ListOptions) ([]linodego.Firewall, error)
UpdateInstanceFirewalls(ctx context.Context, linodeID int, opts linodego.InstanceFirewallUpdateOptions) ([]linodego.Firewall, error)
}

// LinodeVPCClient defines the methods that interact with Linode's VPC service.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,9 @@ spec:
- message: Value is immutable
rule: self == oldSelf
firewallID:
description: FirewallID is the id of the cloud firewall to apply to
the Linode Instance
type: integer
x-kubernetes-validations:
- message: Value is immutable
rule: self == oldSelf
firewallRef:
description: FirewallRef is a reference to a firewall object. This
makes the linode use the specified firewall.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,9 @@ spec:
- message: Value is immutable
rule: self == oldSelf
firewallID:
description: FirewallID is the id of the cloud firewall to
apply to the Linode Instance
type: integer
x-kubernetes-validations:
- message: Value is immutable
rule: self == oldSelf
firewallRef:
description: FirewallRef is a reference to a firewall object.
This makes the linode use the specified firewall.
Expand Down Expand Up @@ -541,6 +540,9 @@ spec:
- type
type: object
type: array
firewallID:
description: Firewall ID that is currently applied to the LinodeMachineTemplate.
type: integer
tags:
description: tags that are currently applied to the LinodeMachineTemplate.
items:
Expand Down
3 changes: 2 additions & 1 deletion docs/src/reference/out.md
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ _Appears in:_
| `backupsEnabled` _boolean_ | | | |
| `privateIP` _boolean_ | | | |
| `tags` _string array_ | Tags is a list of tags to apply to the Linode instance. | | |
| `firewallID` _integer_ | | | |
| `firewallID` _integer_ | FirewallID is the id of the cloud firewall to apply to the Linode Instance | | |
| `osDisk` _[InstanceDisk](#instancedisk)_ | OSDisk is configuration for the root disk that includes the OS,<br />if not specified this defaults to whatever space is not taken up by the DataDisks | | |
| `dataDisks` _object (keys:string, values:[InstanceDisk](#instancedisk))_ | DataDisks is a map of any additional disks to add to an instance,<br />The sum of these disks + the OSDisk must not be more than allowed on a linodes plan | | |
| `diskEncryption` _string_ | DiskEncryption determines if the disks of the instance should be encrypted. The default is disabled. | | Enum: [enabled disabled] <br /> |
Expand Down Expand Up @@ -755,6 +755,7 @@ _Appears in:_
| Field | Description | Default | Validation |
| --- | --- | --- | --- |
| `tags` _string array_ | tags that are currently applied to the LinodeMachineTemplate. | | |
| `firewallID` _integer_ | Firewall ID that is currently applied to the LinodeMachineTemplate. | | |
| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#condition-v1-meta) array_ | Conditions represent the latest available observations of a LinodeMachineTemplate's current state. | | |


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ spec:
- describe:
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha2
kind: LinodeVPC
- podLogs:
namespace: capl-system
selector: control-plane=controller-manager
tail: 250
- name: Create LinodeMachine with VPCRef
try:
- apply:
Expand All @@ -56,6 +60,10 @@ spec:
- describe:
apiVersion: cluster.x-k8s.io/v1beta1
kind: Machine
- podLogs:
namespace: capl-system
selector: control-plane=controller-manager
tail: 250
- name: Check if the Linodes & VPC were created
try:
- script:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ spec:
- describe:
apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
- podLogs:
namespace: capl-system
selector: control-plane=controller-manager
tail: 250
- name: Create LinodeMachine resource
try:
- apply:
Expand All @@ -41,6 +45,10 @@ spec:
- describe:
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha2
kind: LinodeMachineTemplate
- podLogs:
namespace: capl-system
selector: control-plane=controller-manager
tail: 250
- describe:
apiVersion: controlplane.cluster.x-k8s.io/v1beta1
kind: KubeadmControlPlane
Expand Down
12 changes: 6 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ require (
github.com/go-logr/logr v1.4.3
github.com/google/go-cmp v0.7.0
github.com/google/uuid v1.6.0
github.com/linode/linodego v1.53.1-0.20250709175023-9b152d30578c
github.com/linode/linodego v1.53.1-0.20250728194520-172cba1c457a
github.com/onsi/ginkgo/v2 v2.23.4
github.com/onsi/gomega v1.38.0
github.com/stretchr/testify v1.10.0
Expand Down Expand Up @@ -64,7 +64,7 @@ require (
github.com/x448/float16 v0.8.4 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect
golang.org/x/sync v0.15.0 // indirect
golang.org/x/sync v0.16.0 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
k8s.io/apiserver v0.33.0 // indirect
k8s.io/component-base v0.33.0 // indirect
Expand Down Expand Up @@ -130,11 +130,11 @@ require (
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/ratelimit v0.2.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/net v0.42.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/term v0.32.0 // indirect
golang.org/x/text v0.26.0 // indirect
golang.org/x/sys v0.34.0 // indirect
golang.org/x/term v0.33.0 // indirect
golang.org/x/text v0.27.0 // indirect
golang.org/x/time v0.9.0 // indirect
golang.org/x/tools v0.34.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
Expand Down
28 changes: 14 additions & 14 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/linode/linodego v1.53.1-0.20250709175023-9b152d30578c h1:WlZm+YNHBuphycMZG2s2+F04hx2wx1ShuOwPAIInjP8=
github.com/linode/linodego v1.53.1-0.20250709175023-9b152d30578c/go.mod h1:bI949fZaVchjWyKIA08hNyvAcV6BAS+PM2op3p7PAWA=
github.com/linode/linodego v1.53.1-0.20250728194520-172cba1c457a h1:5PaGcDTgxlOZOaYNChSKHnzZp4oKFvzqEn8TQ7hv2Pg=
github.com/linode/linodego v1.53.1-0.20250728194520-172cba1c457a/go.mod h1:VHlFAbhj18634Cd7B7L5D723kFKFQMOxzIutSMcWsB4=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
Expand Down Expand Up @@ -333,8 +333,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
Expand All @@ -346,30 +346,30 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
Expand Down
40 changes: 40 additions & 0 deletions internal/controller/linodemachine_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,11 @@ func (r *LinodeMachineReconciler) reconcileUpdate(ctx context.Context, logger lo
}
}

res, err := r.reconcileFirewallID(ctx, logger, machineScope, instanceID)
if err != nil || !res.IsZero() {
return res, err
}

// Clean up bootstrap data after instance creation.
if linodeInstance.Status == linodego.InstanceRunning && machineScope.Machine.Status.Phase == "Running" {
if err := deleteBootstrapData(ctx, machineScope); err != nil {
Expand All @@ -782,6 +787,41 @@ func (r *LinodeMachineReconciler) reconcileUpdate(ctx context.Context, logger lo
return ctrl.Result{}, nil
}

func (r *LinodeMachineReconciler) reconcileFirewallID(ctx context.Context, logger logr.Logger, machineScope *scope.MachineScope, instanceID int) (ctrl.Result, error) {
// get the instance's firewalls
firewalls, err := machineScope.LinodeClient.ListInstanceFirewalls(ctx, instanceID, nil)
if err != nil {
logger.Error(err, "Failed to list firewalls for Linode instance")
return ctrl.Result{RequeueAfter: reconciler.DefaultMachineControllerWaitForRunningDelay}, nil
}

attachedFWIDs := make([]int, 0, len(firewalls))
for _, fw := range firewalls {
attachedFWIDs = append(attachedFWIDs, fw.ID)
}

var desiredFWIDs []int
if machineScope.LinodeMachine.Spec.FirewallID != 0 {
desiredFWIDs = []int{machineScope.LinodeMachine.Spec.FirewallID}
} else {
desiredFWIDs = []int{}
}

// update the firewallID if needed.
if !slices.Equal(attachedFWIDs, desiredFWIDs) {
_, err := machineScope.LinodeClient.UpdateInstanceFirewalls(ctx, instanceID,
linodego.InstanceFirewallUpdateOptions{
FirewallIDs: desiredFWIDs,
},
)
if err != nil {
logger.Error(err, "Failed to update firewalls for Linode instance")
return ctrl.Result{}, err
}
}
return ctrl.Result{}, nil
}

func (r *LinodeMachineReconciler) reconcileDelete(
ctx context.Context,
logger logr.Logger,
Expand Down
Loading
Loading