Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
de51759
Add IPv6 public backends for NodeBalancers
komer3 Mar 12, 2026
37c5a01
Document IPv6 NodeBalancer backends
komer3 Mar 12, 2026
a764399
Add Chainsaw test for IPv6 NodeBalancer backends
komer3 Mar 12, 2026
8f6ae70
Ignore local development artifacts
komer3 Mar 12, 2026
1ab3738
Honor IPv6 backend annotation over VPC backends
komer3 Mar 12, 2026
b336921
Use dual-stack CAPL flavor for IPv6 backend validation
komer3 Mar 12, 2026
9ed47f7
Make IPv6 backend e2e service dual-stack
komer3 Mar 12, 2026
de01740
Fix IPv6 backend Chainsaw reachability check
komer3 Mar 12, 2026
d874876
Document dual-stack requirement for IPv6 backends
komer3 Mar 12, 2026
efe810e
Bump CAPL management cluster toolchain
komer3 Mar 12, 2026
bf11070
Pin devbox clusterctl for v1beta2 CAPL
komer3 Mar 12, 2026
791b6a8
Enable IPv6 auto for generated VPC subnets
komer3 Mar 13, 2026
b6e521f
fix ipv6 backend for vpcs
komer3 Mar 13, 2026
c89d74e
Fix IPv6 backend lint and docs wording
komer3 Mar 13, 2026
808822f
Potential fix for pull request finding
komer3 Mar 13, 2026
cbf9d1b
Potential fix for pull request finding
komer3 Mar 13, 2026
c8f4802
Potential fix for pull request finding
komer3 Mar 13, 2026
2cf942e
Apply suggestions from code review
komer3 Mar 13, 2026
74118be
Address IPv6 backend review comments
komer3 Mar 13, 2026
410a4da
Fix IPv6 backend test vet error
komer3 Mar 13, 2026
4735bcf
Potential fix for pull request finding
komer3 Mar 13, 2026
513ac94
Potential fix for pull request finding
komer3 Mar 13, 2026
8099f2a
use public IPv6 annotation for ipv6 backend. updated tests. Will need…
komer3 Mar 17, 2026
a598b51
Fix ipv6 handling and update the docs with behavior
komer3 Mar 18, 2026
32239c7
Merge branch 'main' into ipv6-backend-support
komer3 Mar 18, 2026
be8cb0b
Refactor NodeBalancer subnet handling to support IPv6 backends and up…
komer3 Mar 18, 2026
16c835c
Temp fix for the dual stack cluster to enable public ipv6 nodeport da…
komer3 Mar 23, 2026
51e6db6
Fix CAPL manifest CCM overrides
komer3 Mar 23, 2026
2327abf
Restore EnsureLoadBalancer contract comment
komer3 Mar 23, 2026
2533b9a
Merge branch 'main' into ipv6-backend-support
komer3 Mar 23, 2026
9498c05
Fix CAPL manifest yq patching
komer3 Mar 23, 2026
3a841c1
Use CAPL v0.10.2 manifests
komer3 Mar 24, 2026
5af9bbf
test
komer3 Mar 24, 2026
ef25bcf
Inject IPv6 source routing into generated CAPL manifests
komer3 Mar 24, 2026
4c25025
Isolate node addition e2e from parallel test runs
komer3 Mar 24, 2026
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
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ jobs:
- name: Run E2E Tests
run: devbox run e2e-test

- name: Run node addition e2e test
run: devbox run e2e-test-node-addition

- name: Run Cilium BGP e2e test
run: devbox run e2e-test-bgp

Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,8 @@ coverage.txt
junit.xml

.DS_Store

# Local cluster artifacts
capl-cluster-manifests.yaml
*-kubeconfig.yaml
.opencode/
52 changes: 30 additions & 22 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ LOCALBIN ?= $(CACHE_BIN)
DEVBOX_BIN ?= $(DEVBOX_PACKAGES_DIR)/bin
HELM ?= $(LOCALBIN)/helm
HELM_VERSION ?= v3.16.3
CLUSTERCTL ?= $(LOCALBIN)/clusterctl
CLUSTERCTL_VERSION ?= v1.12.2

GOLANGCI_LINT ?= $(LOCALBIN)/golangci-lint
GOLANGCI_LINT_NILAWAY ?= $(CACHE_BIN)/golangci-lint-nilaway
Expand All @@ -26,13 +28,13 @@ SUBNET_MANIFEST_NAME ?= subnet-testing-manifests
K8S_VERSION ?= "v1.31.2"

# renovate: datasource=github-tags depName=kubernetes-sigs/cluster-api
CAPI_VERSION ?= "v1.8.5"
CAPI_VERSION ?= "v1.12.3"

# renovate: datasource=github-tags depName=kubernetes-sigs/cluster-api-addon-provider-helm
CAAPH_VERSION ?= "v0.2.1"
CAAPH_VERSION ?= "v0.6.1"

# renovate: datasource=github-tags depName=linode/cluster-api-provider-linode
CAPL_VERSION ?= "v0.8.5"
CAPL_VERSION ?= "v0.10.2"

# renovate: datasource=github-tags depName=golangci/golangci-lint
GOLANGCI_LINT_VERSION ?= "v2.11.3"
Expand Down Expand Up @@ -163,39 +165,40 @@ run-debug: build
mgmt-and-capl-cluster: docker-setup mgmt-cluster capl-cluster

.PHONY: capl-cluster
capl-cluster: generate-capl-cluster-manifests create-capl-cluster patch-linode-ccm
capl-cluster: generate-capl-cluster-manifests create-capl-cluster

.PHONY: generate-capl-cluster-manifests
generate-capl-cluster-manifests:
generate-capl-cluster-manifests: clusterctl
# Create the CAPL cluster manifests without any CSI driver stuff
LINODE_FIREWALL_ENABLED=$(LINODE_FIREWALL_ENABLED) LINODE_OS=$(LINODE_OS) VPC_NAME=$(VPC_NAME) clusterctl generate cluster $(CLUSTER_NAME) \
LINODE_FIREWALL_ENABLED=$(LINODE_FIREWALL_ENABLED) LINODE_OS=$(LINODE_OS) VPC_NAME=$(VPC_NAME) $(CLUSTERCTL) generate cluster $(CLUSTER_NAME) \
--kubernetes-version $(K8S_VERSION) --infrastructure linode-linode:$(CAPL_VERSION) \
--control-plane-machine-count $(CONTROLPLANE_NODES) --worker-machine-count $(WORKER_NODES) > $(MANIFEST_NAME).yaml
yq -i e 'select(.kind == "LinodeVPC").spec.subnets = [{"ipv4": "10.0.0.0/8", "label": "default"}, {"ipv4": "172.16.0.0/16", "label": "testing"}]' $(MANIFEST_NAME).yaml
--control-plane-machine-count $(CONTROLPLANE_NODES) --worker-machine-count $(WORKER_NODES) --flavor kubeadm-dual-stack > $(MANIFEST_NAME).yaml
IMG=$(IMG) ./hack/patch-capl-manifest.sh $(MANIFEST_NAME).yaml

.PHONY: create-capl-cluster
create-capl-cluster:
create-capl-cluster: clusterctl
# Create a CAPL cluster with updated CCM and wait for it to be ready
kubectl apply -f $(MANIFEST_NAME).yaml
kubectl wait --for=condition=ControlPlaneReady cluster/$(CLUSTER_NAME) --timeout=600s || (kubectl get cluster -o yaml; kubectl get linodecluster -o yaml; kubectl get linodemachines -o yaml; kubectl logs -n capl-system deployments/capl-controller-manager --tail=50)
kubectl wait --for=condition=NodeHealthy=true machines -l cluster.x-k8s.io/cluster-name=$(CLUSTER_NAME) --timeout=900s
clusterctl get kubeconfig $(CLUSTER_NAME) > $(KUBECONFIG_PATH)
$(CLUSTERCTL) get kubeconfig $(CLUSTER_NAME) > $(KUBECONFIG_PATH)
KUBECONFIG=$(KUBECONFIG_PATH) kubectl wait --for=condition=Ready nodes --all --timeout=600s
# Remove all taints from control plane node so that pods scheduled on it by tests can run (without this, some tests fail)
KUBECONFIG=$(KUBECONFIG_PATH) kubectl taint nodes -l node-role.kubernetes.io/control-plane node-role.kubernetes.io/control-plane-

.PHONY: patch-linode-ccm
patch-linode-ccm:
KUBECONFIG=$(KUBECONFIG_PATH) kubectl patch -n kube-system daemonset ccm-linode --type='json' -p="[{'op': 'replace', 'path': '/spec/template/spec/containers/0/image', 'value': '${IMG}'}]"
KUBECONFIG=$(KUBECONFIG_PATH) kubectl patch -n kube-system daemonset ccm-linode --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/imagePullPolicy", "value": "Always"}]'
KUBECONFIG=$(KUBECONFIG_PATH) kubectl patch -n kube-system daemonset ccm-linode --type='json' -p='[{"op": "add", "path": "/spec/template/spec/containers/0/env/-", "value": {"name": "LINODE_API_VERSION", "value": "v4beta"}}]'
KUBECONFIG=$(KUBECONFIG_PATH) kubectl rollout status -n kube-system daemonset/ccm-linode --timeout=600s
KUBECONFIG=$(KUBECONFIG_PATH) kubectl -n kube-system get daemonset/ccm-linode -o yaml

.PHONY: mgmt-cluster
mgmt-cluster:
mgmt-cluster: clusterctl
# Create a mgmt cluster
ctlptl apply -f e2e/setup/ctlptl-config.yaml
clusterctl init \
$(CLUSTERCTL) init \
--wait-providers \
--wait-provider-timeout 600 \
--core cluster-api:$(CAPI_VERSION) \
Expand All @@ -220,7 +223,17 @@ e2e-test:
REGION=$(LINODE_REGION) \
LINODE_TOKEN=$(LINODE_TOKEN) \
LINODE_URL=$(LINODE_URL) \
chainsaw test e2e/test --parallel 2 $(E2E_FLAGS)
chainsaw test e2e/test --parallel 2 --selector all $(E2E_FLAGS)

.PHONY: e2e-test-node-addition
e2e-test-node-addition:
CLUSTER_NAME=$(CLUSTER_NAME) \
MGMT_KUBECONFIG=$(MGMT_KUBECONFIG_PATH) \
KUBECONFIG=$(KUBECONFIG_PATH) \
REGION=$(LINODE_REGION) \
LINODE_TOKEN=$(LINODE_TOKEN) \
LINODE_URL=$(LINODE_URL) \
chainsaw test e2e/test --selector node-addition $(E2E_FLAGS)

.PHONY: e2e-test-bgp
e2e-test-bgp:
Expand All @@ -239,16 +252,11 @@ e2e-test-subnet:
# Generate cluster manifests for second cluster
SUBNET_NAME=testing CLUSTER_NAME=$(SUBNET_CLUSTER_NAME) MANIFEST_NAME=$(SUBNET_MANIFEST_NAME) VPC_NAME=$(CLUSTER_NAME) \
VPC_NETWORK_CIDR=172.16.0.0/16 K8S_CLUSTER_CIDR=172.16.64.0/18 make generate-capl-cluster-manifests
# Add subnetNames to HelmChartProxy
yq e 'select(.kind == "HelmChartProxy" and .spec.chartName == "ccm-linode").spec.valuesTemplate' $(SUBNET_MANIFEST_NAME).yaml > tmp.yaml
yq -i e '.routeController += {"subnetNames": "testing"}' tmp.yaml
yq -i e '.routeController.vpcNames = "{{.InfraCluster.spec.vpcRef.name}}"' tmp.yaml
yq -i e 'select(.kind == "HelmChartProxy" and .spec.chartName == "ccm-linode").spec.valuesTemplate = load_str("tmp.yaml")' $(SUBNET_MANIFEST_NAME).yaml
rm tmp.yaml
# Add subnetNames to HelmChartProxy
IMG=$(IMG) ./hack/patch-capl-manifest.sh $(SUBNET_MANIFEST_NAME).yaml testing
# Create the second cluster
MANIFEST_NAME=$(SUBNET_MANIFEST_NAME) CLUSTER_NAME=$(SUBNET_CLUSTER_NAME) KUBECONFIG_PATH=$(SUBNET_KUBECONFIG_PATH) \
make create-capl-cluster
KUBECONFIG_PATH=$(SUBNET_KUBECONFIG_PATH) make patch-linode-ccm
# Run chainsaw test
LINODE_TOKEN=$(LINODE_TOKEN) \
LINODE_URL=$(LINODE_URL) \
Expand Down Expand Up @@ -295,13 +303,13 @@ helm-template: helm
.PHONY: kubectl
kubectl: $(KUBECTL) ## Download kubectl locally if necessary.
$(KUBECTL): $(LOCALBIN)
curl -fsSL https://dl.k8s.io/release/$(KUBECTL_VERSION)/bin/$(OS)/$(ARCH_SHORT)/kubectl -o $(KUBECTL)
curl -fsSL https://dl.k8s.io/release/$(KUBECTL_VERSION)/bin/$(HOSTOS)/$(ARCH_SHORT)/kubectl -o $(KUBECTL)
chmod +x $(KUBECTL)

.PHONY: clusterctl
clusterctl: $(CLUSTERCTL) ## Download clusterctl locally if necessary.
$(CLUSTERCTL): $(LOCALBIN)
curl -fsSL https://github.com/kubernetes-sigs/cluster-api/releases/download/$(CLUSTERCTL_VERSION)/clusterctl-$(OS)-$(ARCH_SHORT) -o $(CLUSTERCTL)
curl -fsSL https://github.com/kubernetes-sigs/cluster-api/releases/download/$(CLUSTERCTL_VERSION)/clusterctl-$(HOSTOS)-$(ARCH_SHORT) -o $(CLUSTERCTL)
chmod +x $(CLUSTERCTL)

.phony: golangci-lint-nilaway
Expand Down
2 changes: 2 additions & 0 deletions cloud/annotations/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ const (
// AnnLinodeEnableIPv6Ingress is the annotation used to specify that a service should include both IPv4 and IPv6
// addresses for its LoadBalancer ingress. When set to "true", both addresses will be included in the status.
AnnLinodeEnableIPv6Ingress = "service.beta.kubernetes.io/linode-loadbalancer-enable-ipv6-ingress"
// AnnLinodeEnableIPv6Backends controls whether a NodeBalancer service should use public IPv6 backend nodes.
AnnLinodeEnableIPv6Backends = "service.beta.kubernetes.io/linode-loadbalancer-enable-ipv6-backends"

AnnLinodeNodePrivateIP = "node.k8s.linode.com/private-ip"
AnnLinodeHostUUID = "node.k8s.linode.com/host-uuid"
Expand Down
Loading
Loading