Documentation
¶
Overview ¶
actions.go — the two GitOps write actions.
POST /v1/deploy/{name}/rollback — pin the CR image tag to a prior clean semver.
It REUSES the P1 release seam (cloud.OnServiceRelease → clients/paas
releaseService), so the clean-semver gate + idempotent spec.image patch live
in exactly ONE place; the operator reconciles the rollout.
POST /v1/deploy/{name}/sync — request an operator reconcile now by touching the
CR (an annotation bump the operator's watch observes). Today the CR is the
desired source, so sync = nudge-reconcile; when git.hanzo.ai is the source it
becomes apply-desired-from-git, same endpoint.
applications.go — GET /v1/deploy/applications: the fleet list. Each operator Service CR is one Application row: its declared image version, the running version observed from the live Deployment, the reconciled health, and the sync verdict (declared == running ⇒ Synced, else OutOfSync). The console renders this as the ArgoCD application list.
Package gitops mounts the native GitOps control plane at /v1/deploy — the ArgoCD-grade deploy dashboard for the operator-managed fleet, made native to the cloud binary and parallel to /v1/git (the native git server).
Each operator hanzo.ai/v1 App CR IS a GitOps Application: the desired state declared for one workload, which the Hanzo operator reconciles into a Deployment + Service + Ingress (+ HPA/PDB/Pods). This plane OBSERVES that reconciliation the way ArgoCD observes a synced Application —
GET /v1/deploy/applications — the fleet list: name, declared version,
health, sync, per app.
GET /v1/deploy/{name}/tree — the owned-resource tree (ownerRef edges)
with per-node health + sync.
GET /v1/deploy/{name}/resource/{ref} — one node's live manifest + a
desired-vs-live diff.
GET /v1/deploy/{name}/logs — the app's current pod logs.
POST /v1/deploy/{name}/rollback — pin the CR image tag to a prior semver
(the operator reconciles the rollout).
POST /v1/deploy/{name}/sync — request an operator reconcile now.
SECURITY — every route is SUPERADMIN ONLY, fail-closed, on the SAME predicate the rest of cloud uses (c.IsAdmin()): the plane reads and mutates SYSTEM Service CRs across the whole fleet, so a tenant must never reach it. Secret objects are never surfaced (no node, no manifest) so the tree can never leak materialized env. The user-facing per-org PaaS is /v1/platform; this is the platform-operator console the admin dashboard consumes.
GitOps note (the follow-on seam): today the CR is the desired-state source and a rollback/rollout PATCHES it directly (P1's RegisterServiceReleaser), so deploys work now. The end-state is true GitOps on OUR native git — RegisterPushBuilder commits the CR image-tag change to the manifest repo on git.hanzo.ai (github.com/hanzoai/git) and this engine syncs that repo → cluster with self-heal. The desired-vs-live diff below is already structured for that: it reads a desired source that is "cluster last-applied" now and becomes the git.hanzo.ai manifest later, with no shape change. See deployDesiredTODO.
health.go — per-resource health, the ArgoCD `pkg/health` vocabulary made native (Healthy / Progressing / Degraded / Suspended / Missing / Unknown). It is a PURE function over one live object, so the list + tree derive an honest per-node health with no cluster round-trip beyond the object already read.
P2b swaps the internals for github.com/argoproj/gitops-engine pkg/health (health.GetResourceHealth) for exact ArgoCD parity; the CODES emitted here are already those strings, so the wire contract the console consumes does not change.
logs.go — GET /v1/deploy/{name}/logs: the app's current pod logs, streamed from the newest running pod via the typed CoreV1 GetLogs subresource. The operator labels the workload it renders for an App CR with app.kubernetes.io/instance=<name>, so that selects the app's pods; the most-recently-started pod is read (the current rollout). Optional ?container= selects a container; ?tail= bounds the lines. Never fabricates output — an unreachable cluster or absent pod yields an honest 200 with an empty tail + the reason, not invented logs.
resource.go — GET /v1/deploy/{name}/resource/{ref}: one tree node's live manifest plus a desired-vs-live diff.
{ref} is the canonical "group:kind:namespace:name" token the tree emits on each node, so the console round-trips it back verbatim. The kind must be in the closed registry (kindGVR) and the namespace a platform namespace, and the object must belong to {name}'s tree (it IS the CR, or carries an ownerRef/label tying it to the app) — so the endpoint can never be steered at an arbitrary cluster object. Secrets are not in the registry, so their manifests are never returned.
desiredSource: today "last-applied" (the object's kubectl last-applied-config annotation) or "none". When git.hanzo.ai becomes the manifest source of truth (RegisterPushBuilder → commit → engine sync), desiredSource becomes "git" with the SAME diff shape. P2b replaces the field-strip diff with gitops-engine pkg/diff (three-way) for exact ArgoCD parity.
tree.go — GET /v1/deploy/{name}/tree: the owned-resource tree for one Application, the ArgoCD ApplicationTree shape (a FLAT node list with parentRefs edges; the console renders the DAG). The root is the Service CR; depth-1 nodes are the operator-owned Deployment/Service/Ingress/HPA/PDB/ConfigMap; depth-2 are the Deployment's ReplicaSets and their Pods. Ownership is by ownerReferences.uid with a name-equals-app fallback (some operator-rendered children are named after the CR). Secret objects are never included — the tree cannot leak env.
P2b swaps buildTree's cluster walk for github.com/argoproj/gitops-engine pkg/cache (ClusterCache.GetManagedLiveObjs / hierarchy) for a watch-backed tree; the Node shape the console consumes does not change.
Index ¶
Constants ¶
const ( SyncSynced = "synced" SyncOutOfSync = "out-of-sync" SyncUnknown = "unknown" )
Sync codes — the ArgoCD sync vocabulary, lowercased for the wire.
const ( HealthHealthy = "healthy" HealthProgressing = "progressing" HealthDegraded = "degraded" HealthSuspended = "suspended" HealthMissing = "missing" HealthUnknown = "unknown" )
Health codes — the ArgoCD health vocabulary, lowercased for the wire.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Application ¶
type Application struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
Env string `json:"env"` // main|test|dev
Role string `json:"role,omitempty"` // spec.role after the kind collapse (App)
Repository string `json:"repository"`
Version string `json:"version"` // declared: spec.image.tag
RunningVersion string `json:"runningVersion"` // observed from the Deployment
Health string `json:"health"` // healthy|progressing|degraded|suspended|missing|unknown
HealthMessage string `json:"healthMessage,omitempty"`
Sync string `json:"sync"` // synced|out-of-sync|unknown
Phase string `json:"phase,omitempty"`
Endpoints []string `json:"endpoints"`
}
Application is one fleet row. Shapes the exact fields the console list consumes.
type Node ¶
type Node struct {
ResourceRef
UID string `json:"uid,omitempty"`
CreatedAt string `json:"createdAt,omitempty"`
Health string `json:"health"`
HealthMessage string `json:"healthMessage,omitempty"`
Sync string `json:"sync,omitempty"`
Version string `json:"version,omitempty"` // image tag for a workload node
ParentRefs []ResourceRef `json:"parentRefs,omitempty"`
}
Node is one resource in the tree: its ref, ownerRef parents, and derived health/sync (+ image version for a workload). ArgoCD ResourceNode shape.
type ResourceRef ¶
type ResourceRef struct {
Group string `json:"group"`
Version string `json:"version"`
Kind string `json:"kind"`
Namespace string `json:"namespace"`
Name string `json:"name"`
Ref string `json:"ref"`
}
ResourceRef identifies one node — the round-trip token the resource endpoint parses. Ref is the canonical "group:kind:namespace:name" string.