Documentation
¶
Overview ¶
Package provisioningsvc is the Hanzo Cloud provisioning control plane. It turns "create a database" into a real logical resource inside an already-live, shared product backend, per the unified /v1 binary (HIP-0106).
One HTTP surface, seven kinds, one Provisioner each:
sql -> Postgres sql.hanzo.svc:5432 CREATE DATABASE + ROLE
vector -> Qdrant vector.hanzo.svc:6333 PUT /collections/{name}
datastore -> ClickHouse datastore.hanzo.svc:8123 CREATE DATABASE + USER
kv -> Redis kv.hanzo.svc:6379 ACL SETUSER (keyspace scope)
search -> Meilisearch search.hanzo.svc:7700 POST /indexes
s3 -> S3/MinIO s3.hanzo.svc:9000 MakeBucket
docdb -> MongoDB docdb.hanzo.svc:27017 createCollection + createUser
Tenancy: every request is scoped to the gateway-minted org (X-Org-Id / c.Org()). Empty org is rejected 403 unless the caller is an admin. The physical resource on the shared backend is namespaced "o"<hash(org)>_<name> with a FIXED-WIDTH org hash, so the org→name boundary is unambiguous and two distinct tenants can never fold onto one backend resource. A global UNIQUE(physical_name) guard makes any residual fold fail closed with 409.
Secrets: generated per-resource passwords are sealed in Hanzo KMS (client-side encrypted) and only a secret_ref is persisted. When KMS is not configured the service degrades safely — it returns the password once in the create response and stores NOTHING in plaintext. See kms.go.
Index ¶
- func Mount(app *zip.App, deps cloud.Deps) error
- func Shutdown(context.Context) error
- type Provisioner
- type Resource
- type Store
- func (s *Store) Close() error
- func (s *Store) Delete(ctx context.Context, org, kind, name string) (bool, error)
- func (s *Store) Get(ctx context.Context, org, kind, name string) (Resource, error)
- func (s *Store) Insert(ctx context.Context, r Resource) error
- func (s *Store) List(ctx context.Context, org, kind string) ([]Resource, error)
- func (s *Store) PhysicalExists(ctx context.Context, physical string) (bool, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Provisioner ¶
type Provisioner interface {
Create(ctx context.Context, physicalName, user, password string) (connString, host string, port int, db string, err error)
Drop(ctx context.Context, physicalName, user string) error
}
Provisioner creates and drops one kind of logical resource inside a shared, already-live backend. Create receives the namespaced physical name plus a per-resource user + password (the handler generates these); it returns a client connection string, the public host/port of the backend service, and the logical database/collection/bucket name. Backends without per-resource auth (Qdrant, Meilisearch, S3) ignore user/password and return an empty username via the handler's kind map.
type Resource ¶
type Resource struct {
ID string
Org string
Kind string
Name string
PhysicalName string
SecretRef string
Host string
Port int
Username string
DBName string
Status string
CreatedAt int64
}
Resource is one row of provisioned_resources: the control-plane record for a logical resource (database, bucket, collection, …) created inside a shared backend. It never carries the plaintext password — only secret_ref, the KMS key under which the password is sealed.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is the provisioning metadata database. ONE SQLite file ({DataDir}/provisioning.db) holds every org's records; tenant isolation is by the org column, enforced at the query layer. MaxOpenConns(1) serializes access so multi-step writes never race the SQLite file lock.
func (*Store) Delete ¶
Delete removes the resource row inside a transaction. Reports whether a row was actually deleted.
func (*Store) Insert ¶
Insert writes one resource row inside a transaction. A UNIQUE(org,kind,name) OR UNIQUE(physical_name) violation surfaces as errConflict so the caller can roll back the backend side-effects it already performed.
func (*Store) PhysicalExists ¶
PhysicalExists reports whether ANY org already owns the given physical backend name. This is the global (cross-org) uniqueness pre-check: paired with the UNIQUE(physical_name) index it lets the handler fail closed with 409 BEFORE it touches a backend, so a residual name-fold (or hash collision) can never silently provision over another tenant's physical resource.