k8s-node-tagger: add azure cloud provider scaffold - #70
Conversation
Scaffold Azure cloud provider support modeled on the existing aws and gcp providers, unblocking the ick azure provider overlay (planetscale/infra-config-kubernetes#9519). What's scaffolded (compiles, lint-clean, tests pass): - azure.go: azureComputeClient interface + stub implementation, and a parseAzureProviderID stub. - controller.go: AzureComputeClient field on NodeLabelController, an "azure" case in SetupCloudProvider that wires the stub client, and an "azure" case in Reconcile dispatching to syncAzureTags (implemented against the interface, so it will work once the stub is replaced with a real SDK client). - main.go: accept "azure" in the -cloud validation and update the flag help text. - README.md: document azure as a supported -cloud value. What's TODO (left for the finishing agent): - Choose the Azure SDK package (armcompute vs. instance metadata service) and implement azureComputeClient behind the interface. - Implement parseAzureProviderID for the real Azure provider ID format. - Confirm which Azure node attributes to tag and the RBAC the UAMI needs. This is a stub: the azure provider is selectable end-to-end but every Azure compute call returns "not yet implemented".
Replace the not-yet-implemented stub with a real azure provider modeled on aws.go and gcp.go. azure.go adds azureVMResource, parseAzureProviderID (handles standalone-VM and VMSS-instance IDs), azureComputeClient using armcompute/v8 (VirtualMachinesClient and VirtualMachineScaleSetVMsClient), and newAzureComputeClient via azidentity.NewDefaultAzureCredential (workload-identity-friendly). controller.go wires the azure case into SetupCloudProvider and implements syncAzureTags mirroring syncGCPLabels: parse the node's provider ID, fetch the current tags, merge while preserving unmanaged tags, sanitize keys/values, skip the round-trip when nothing changed, and replace the full tag set otherwise. controller_test.go adds mockAzureClient with TestReconcileAzure (7 cases), TestParseAzureProviderID (8 cases), and sanitization tests. Deps: armcompute/v8 v8.2.0, azidentity v1.14.0, azcore v1.22.0.
Open question resolvedUAMI RBAC grant lives in infra — solved by infra#12203 (UAMI + federated credential + Virtual Machine Contributor role for the k8s-node-tagger service account, same effort, tracking infra#12280). The role grant covers |
Open question — needs user inputHuman review of the real |
Open question — needs user inputick overlay blocked on released image — requires a human decision: this PR (#70) must merge, then CI must go green on |
Open question resolveddeploy ApplicationSet — solved by deploy#3459 (ApplicationSet + envsubst wiring for the azure provider, same effort, tracking infra#12280). No action needed in this PR. |
|
tracking issue: https://github.com/planetscale/infra/issues/12280 |
Context
Unblocks the ick Azure provider overlay: https://github.com/planetscale/infra-config-kubernetes/pull/9519
The binary previously hard-rejected anything but
aws/gcp. This PR adds a real Azure cloud provider so the ick overlay can select-cloud azureend-to-end.This is a DRAFT PR.
What's implemented
azure.goazureVMResource,parseAzureProviderID(standalone-VM + VMSS-instance IDs),azureComputeClientbacked by armcompute/v8 (VirtualMachinesClient+VirtualMachineScaleSetVMsClient),newAzureComputeClientviaazidentity.NewDefaultAzureCredential(workload-identity-friendly)controller.goAzureComputeClientfield,azurecase inSetupCloudProvider,syncAzureTagsmirroringsyncGCPLabels(parse → fetch → merge preserving unmanaged tags → sanitize → skip-if-unchanged → replace)main.go-cloudacceptsazure; flag help updatedREADME.mdazuredocumented as a supported-cloudvaluecontroller_test.gomockAzureClientwithTestReconcileAzure(7 cases),TestParseAzureProviderID(8 cases), sanitization testsarmcompute/v8v8.2.0,azidentityv1.14.0,azcorev1.22.0Design decisions (resolves the original open questions)
armcompute/v8(ARM API), mirroring how the AWS provider uses the EC2 SDK directly and GCP uses the compute API.Microsoft.Compute/virtualMachines(standalone) andMicrosoft.Compute/virtualMachineScaleSets/<vmss>/virtualMachines/<instance>(VMSS, the AKS default). Tags are read from / written to the k8s node'sspec.ProviderID.azidentity.NewDefaultAzureCredential, which honors workload identity when run in-cluster with a UAMI federated credential).parseAzureProviderIDhandles theazure:///subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Compute/...provider ID format that the AKS cloud provider emits.Microsoft.Compute/virtualMachines/read+Microsoft.Compute/virtualMachines/write(and the VMSS VM equivalents) for tag reads/writes.RBAC/UAMI/federated-credential setup lives in(solved by infra#12203 — UAMI + federated credential + Virtual Machine Contributor role, same effort infra#12280)infraand is out of scope for this repo.Verification
go build ./...✅go test -race ./...✅golangci-lint run ./...✅ (0 issues)gofmt -l .✅ (clean)Out of scope
infra-config-kubernetes) — ick#9519 is genuine-open, blocked on this PR merging + Autotag cutting a released image (see comment).Terraform / UAMI / federated credentials (live in(solved by infra#12203)infra).deploy ApplicationSet wiring.(solved by deploy#3459)Open questions (status)
azure.goSee the follow-on comments for detail. The PR stays draft until the human review (H4) is done.
Notes