Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
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