Add the GCP provider: four-call surface, fire-and-forget ops, zone-qualified IDs

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-09 15:36:14 +02:00
parent 4aa3d47e3c
commit 8176a5eef8
10 changed files with 1018 additions and 66 deletions

View File

@@ -1,6 +1,6 @@
# Architecture
> **Status:** the operator is built through Step 7 (discovery API) of
> **Status:** the operator is built through Step 8 (GCP provider) of
> [docs/plans/2026-08-07-1747-proxy-operator.md](plans/2026-08-07-1747-proxy-operator.md).
> This document currently covers the event/reconcile flow and the
> HTTP-driven lease/discovery path; the components table and the Decisions
@@ -117,20 +117,32 @@ reconcileDelete(ctx, p) reconcileExternal(ctx, p)
──► RequeueAfter: DeletionPoll (poll until gone)
```
### 5. What provider calls do back in the cluster (kubernetes pod provider)
### 5. What provider calls do in the outside world
```text
kubernetes pod provider (internal/provider/kubernetes/)
prov.Create ──► buildPod (pure) ──► client.Create(corev1.Pod) ─┐ these cause Pod events,
prov.Get ──► client.Get(Pod) → phase/IP → InstanceState │ but the operator does NOT
prov.Delete ──► client.Delete(Pod, tolerate NotFound) │ watch Pods — it observes
prov.ListByTag ─► client.List(Pods by labels, all namespaces) ─┘ them by polling prov.Get
on each RequeueAfter tick
gcp provider (internal/provider/gcp/) — instances.{Insert,Get,Delete,AggregatedList}, nothing else
prov.Create ──► buildInsertRequest (pure) ──► instances.Insert ─┐ fire-and-forget:
409 alreadyExists = success (idempotent retry) │ Operation.Wait is never
prov.Get ──► instances.Get → status/NatIP → InstanceState │ called; readiness is
RUNNING without NatIP = still Provisioning │ discovered by Get polls,
prov.Delete ──► instances.Delete (404 = success) │ exactly like the pod
prov.ListByTag ─► AggregatedList(label filter, ─┘ provider
ReturnPartialSuccess: true)
providerID = zones/<zone>/instances/<name> — zone-qualified, so Get/Delete
stay correct even mid-replacement after a zone edit
```
The reconciler never watches provider-side resources (Pods now, GCP VMs
later). All instance-state observation is poll-based through the
`Provider` interface, so the same flow works identically for a cloud API
that has no watch mechanism at all.
The reconciler never watches provider-side resources (Pods or GCP VMs).
All instance-state observation is poll-based through the `Provider`
interface, so the same flow works identically for a cloud API that has no
watch mechanism at all.
### 6. Health engine (`internal/health/`) — probes and transitions