Documentation
¶
Overview ¶
tenant_context.go is the ONE source of truth for the tenant-hierarchy request scope (org > app > project, plus tenant/actor/env). The router filter (routers.TenantContextFilter) copies the gateway-injected X-*-ID headers onto the zip request context (Ctx locals) under these keys; every consumer (controllers) reads them back through the getters here. Keeping the keys and their accessors in one shared place — imported by both routers and controllers — means no consumer re-derives a key string: the scope is a value, not a place.
Org and project OVERLAP zip.CallerOf, deliberately and not by accident: zip reads the same X-Org-Id / X-Project-Id off the same request, so a typed op can have the caller's org without any of this. What zip does NOT carry is the rest of visor's hierarchy — app, tenant, actor, env — nor the two rules underneath it: org falls back to the whitelabel hostname's filter, and tenant defaults to org. Those are visor's, so this stays until an op needs only org, and then it should ask zip rather than grow a second accessor here.
Index ¶
- Constants
- func AddAgentBinding(binding *AgentBinding) (bool, error)
- func AddAsset(asset *Asset) (bool, error)
- func AddMachine(machine *Machine) (bool, error)
- func AddNodePool(pool *NodePool) (bool, error)
- func AddPlan(plan *Plan) (bool, error)
- func AddProvider(provider *Provider) (bool, error)
- func AddRecord(record *Record) bool
- func AddSession(session *Session) (bool, error)
- func AddVolume(volume *Volume) (bool, error)
- func AdvanceCostCursor(owner, provider, month string, currentMTDCents int64) (int64, error)
- func AttachVolumeCloud(owner string, providerName string, volumeCloudID string, machineCloudID string) error
- func BuildMembership() ha.Membership
- func ClaimBillingUnit(unit string, now time.Time) bool
- func ClaimMeterHour(now time.Time) bool
- func CloseDBSession(id string, code int, msg string) error
- func CloseSession(id string, code int, msg string) error
- func CommitRecord(record *Record) (bool, error)
- func DBPath(root, owner string) string
- func DeleteAgentBinding(binding *AgentBinding) (bool, error)
- func DeleteAsset(asset *Asset) (bool, error)
- func DeleteMachine(machine *Machine) (bool, error)
- func DeleteNodePool(pool *NodePool) (bool, error)
- func DeleteNodePoolCloud(pool *NodePool) (bool, error)
- func DeletePlan(plan *Plan) (bool, error)
- func DeleteProvider(provider *Provider) (bool, error)
- func DeleteRecord(record *Record) (bool, error)
- func DeleteSession(session *Session) (bool, error)
- func DeleteSessionById(id string) (bool, error)
- func DeleteVolume(volume *Volume) (bool, error)
- func DeleteVolumeCloud(owner string, providerName string, volumeCloudID string) error
- func DetachVolumeCloud(owner string, providerName string, volumeCloudID string) error
- func DisconnectFleetWorker(owner, name string) (bool, error)
- func EngineFor(owner string) (*relational.Engine, error)
- func ForgetClusterPools(org, clusterID string) error
- func GetAllNodePools(pools *[]*NodePool) error
- func GetAssetCount(owner, field, value string) (int64, error)
- func GetBearerUser(authHeader string) *iamsdk.User
- func GetKubernetesNodesCloud(owner string) ([]*service.Machine, error)
- func GetMachineCount(owner, field, value string) (int64, error)
- func GetNodePoolCount(owner, field, value string) (int64, error)
- func GetProviderCount(owner, field, value string) (int64, error)
- func GetRecordCount(owner, field, value string) (int64, error)
- func GetSession(owner string, offset, limit int, field, value, sortField, sortOrder string) *relational.Session
- func GetSessionCount(owner, status, field, value string) (int64, error)
- func GetTenantActorID(c *zip.Ctx) string
- func GetTenantAppID(c *zip.Ctx) string
- func GetTenantContextValue(c *zip.Ctx, key string) string
- func GetTenantEnv(c *zip.Ctx) string
- func GetTenantOrgID(c *zip.Ctx) string
- func GetTenantProjectID(c *zip.Ctx) string
- func InitAdapter()
- func InitConfig()
- func InitStore()
- func IsBillingOwner() bool
- func QueryRecord(id string) (string, error)
- func Ready() error
- func RecordSeedPool(p service.SeedPool) error
- func RegisterMembership(m ha.Membership)
- func ResizeVolumeCloud(owner string, providerName string, volumeCloudID string, sizeGB int) error
- func SeedDefaultPlans(owner string) error
- func SelfID() string
- func SetTenantContextValue(c *zip.Ctx, key, value string)
- func Shared() *relational.Engine
- func SyncMachinesCloud(owner string) (bool, error)
- func SyncNodePoolsCloud(owner string) (bool, error)
- func UnbindAgent(machineId string) (bool, error)
- func UpdateAgentBinding(binding *AgentBinding) (bool, error)
- func UpdateAsset(id string, asset *Asset) (bool, error)
- func UpdateMachine(id string, machine *Machine) (bool, error)
- func UpdateNodePool(id string, pool *NodePool) (bool, error)
- func UpdatePlan(owner string, name string, plan *Plan) (bool, error)
- func UpdateProvider(id string, provider *Provider) (bool, error)
- func UpdateRecord(id string, record *Record) (bool, error)
- func UpdateSession(id string, session *Session, columns ...string) (bool, error)
- func UpdateVolume(owner string, name string, volume *Volume) (bool, error)
- func WriteCloseMessage(session *guacamole.Session, mode string, code int, msg string)
- type Adapter
- type AgentBinding
- type Asset
- func GetAsset(id string) (*Asset, error)
- func GetAssets(owner string) ([]*Asset, error)
- func GetMaskedAsset(asset *Asset, errs ...error) (*Asset, error)
- func GetMaskedAssets(assets []*Asset, errs ...error) ([]*Asset, error)
- func GetPaginationAssets(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*Asset, error)
- type BillingLease
- type CostCursor
- type FleetWorker
- type Machine
- func CreateMachineCloud(owner string, providerName string, spec *service.CreateMachineSpec) (*Machine, error)
- func GetMachine(id string) (*Machine, error)
- func GetMachines(owner string) ([]*Machine, error)
- func GetMaskedMachine(machine *Machine, errs ...error) (*Machine, error)
- func GetMaskedMachines(machines []*Machine, errs ...error) ([]*Machine, error)
- func GetPaginationMachines(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*Machine, error)
- type MeterLease
- type MigrationReport
- type NodePool
- func CreateNodePoolCloud(owner, providerName, clusterID string, spec *service.CreateNodePoolSpec) (*NodePool, error)
- func GetNodePool(id string) (*NodePool, error)
- func GetNodePools(owner string) ([]*NodePool, error)
- func GetPaginationNodePools(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*NodePool, error)
- func ScaleNodePoolCloud(owner, providerName, clusterID, poolID string, count int) (*NodePool, error)
- type Param
- type Patch
- type Plan
- type Provider
- func GetAllActiveCloudProviders() ([]*Provider, error)
- func GetMaskedProvider(provider *Provider, errs ...error) (*Provider, error)
- func GetMaskedProviders(providers []*Provider, errs ...error) ([]*Provider, error)
- func GetPaginationProviders(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*Provider, error)
- func GetProvider(id string) (*Provider, error)
- func GetProviders(owner string) ([]*Provider, error)
- type Record
- type RemoteApp
- type Response
- type Service
- type Session
- func CreateSession(session *Session, machineId string, mode string) (*Session, error)
- func GetConnSession(id string) (*Session, error)
- func GetPaginationSessions(owner, status string, offset, limit int, ...) ([]*Session, error)
- func GetSessions(owner string) ([]*Session, error)
- func GetSessionsByStatus(statuses []string) ([]*Session, error)
- type StorageBackend
- type Volume
- type WhitelabelConfig
Constants ¶
const ( AgentBindingPending = "Pending" AgentBindingBound = "Bound" AgentBindingError = "Error" )
Agent binding lifecycle states. Honest — each reflects a real, observable condition, never an optimistic guess:
- Pending: binding recorded; the machine's @hanzo/bot runtime has not yet been confirmed running (machine still provisioning, or bot cloud-init not yet observed on the instance tags).
- Bound: the machine is Active AND is tagged as running the @hanzo/bot runtime for this agent (the launch cloud-init path stamps a `hanzo-bot:<agentName>` provider tag).
- Unbound: the binding was explicitly deleted; retained transiently only as a return value, never persisted (DELETE removes the row).
- Error: the machine is in a terminal/failed cloud state, so the runtime cannot be running.
const ( FleetWorkerBYOHardware = "byo-hardware" FleetWorkerValidator = "validator" )
Fleet worker kinds — the BILLING LINEAGE of a connected compute source, resolved once at connect. It is exactly the fleet-billing tier the source belongs to:
- FleetWorkerBYOHardware: a bare-metal / GPU / device box NOT on a cloud → flat $1/mo per connected device (DeviceCount), armed on connect and stopped on disconnect.
- FleetWorkerValidator: a box whose validator address is in the hanzo.network mainnet validator set → FREE / native (it already earns validator economics and secures the chain), so it is never metered.
A BYOC cloud ACCOUNT is a Provider, not a worker — it is billed at 1% of its cloud spend by the daily cost collector — so the worker registry is exactly the non-cloud tiers (b) and (c). One source, one kind, one rate.
const ( FleetWorkerConnected = "connected" FleetWorkerDisconnected = "disconnected" )
Worker connection states.
const ( NoConnect = "no_connect" Connecting = "connecting" Connected = "connected" Disconnected = "disconnected" )
const ( TenantContextOrgIDKey = "tenant.orgId" TenantContextAppIDKey = "tenant.appId" TenantContextProjectIDKey = "tenant.projectId" TenantContextTenantIDKey = "tenant.tenantId" TenantContextActorIDKey = "tenant.actorId" TenantContextEnvKey = "tenant.env" )
Tenant-scope keys under which the filter stows each header on the request context (zip.Ctx locals). Exported so the single writer (the routers filter) and every reader (controllers) share the exact same key — never a duplicated literal.
const BotRuntimeTag = "hanzo-bot"
BotRuntimeTag is the provider tag that marks a machine as running the @hanzo/bot runtime for a given agent. The launch cloud-init path is the single writer; reconcile is the single reader. The value is the agent name so one machine hosts exactly one agent's bot (the machine IS the bot's identity).
const RecordResponseKey = "record.responseJson"
RecordResponseKey is the request-context local under which a handler stashes its JSON response envelope (via ResponseOk/ResponseError). The record filter reads it back after the handler returns to build the audit record — the ONE key shared by the writer (controllers) and the reader (routers).
Variables ¶
This section is empty.
Functions ¶
func AddAgentBinding ¶
func AddAgentBinding(binding *AgentBinding) (bool, error)
AddAgentBinding inserts a binding. Callers set identity + timestamps first.
func AddMachine ¶
func AddNodePool ¶
func AddProvider ¶
func AddSession ¶
func AdvanceCostCursor ¶
AdvanceCostCursor advances the (owner, provider, month) watermark to the account's current month-to-date spend and returns the newly-billable spend INCREMENT (the month-to-date spend that had not yet been 1%-billed). It advances the watermark BEFORE the caller debits, so a debit failure UNDER-bills that increment — the safe direction for a paid product (a missed fee is reconcilable; a double debit is not). A zero/negative delta (no new spend, or a spend that only decreased via credits) advances nothing and returns 0.
func AttachVolumeCloud ¶
func BuildMembership ¶ added in v1.108.22
func BuildMembership() ha.Membership
BuildMembership returns the registered source, or the unavailable default. It never returns nil: a nil source would push a nil-check onto every call site, and the one that got forgotten would panic inside a billing tick instead of skipping the hour.
func ClaimBillingUnit ¶
ClaimBillingUnit claims a billing unit cluster-wide for exactly-once metering. It returns true to EXACTLY ONE caller for a given unit; every other replica — and any replay of the same unit — gets false and must skip. Best-effort prune of stale rows runs only for the winner, so it costs nothing on the hot skip path.
func ClaimMeterHour ¶
ClaimMeterHour attempts to claim the hourly metering sweep for the wall-clock hour containing now, cluster-wide. It returns true to EXACTLY ONE caller per hour (the elected owner whose Insert wins the Hour primary key); every other replica — a non-owner, or any re-entry within the same hour after a restart — gets false and must skip the sweep.
Exactly-once is the shared claimLease primitive: the single-writer gate (only the elected `_global` owner claims), a hydrate of the prior owner's leases before the insert, and a synchronous ship of the winning claim before the caller debits. Any failure (not owner, hydrate/ship failed, PK lost, DB error) yields false: fail SAFE for a paid product means NOT sweeping (a missed hour is reconciled; a duplicate debit is not). Best-effort prune of stale rows runs only for the winner, so it costs nothing on the hot skip path.
func CommitRecord ¶
func DBPath ¶
DBPath is the HIP-0302 per-org SQLite path for a visor org DB. It mirrors the layout hanzo/cloud uses (orgs/<org>/<service>.db) so every Hanzo service that moves onto Base shares one on-disk convention.
DBPath("/data", "acme") -> /data/orgs/acme/visor.db
The empty owner (catalog / cluster-global rows that no org owns) routes to the _global sentinel, matching hanzo/cloud's fail-loud migration bucket.
func DeleteAgentBinding ¶
func DeleteAgentBinding(binding *AgentBinding) (bool, error)
DeleteAgentBinding removes a binding by PK (unbind). It does NOT touch the machine — unbinding severs the agent↔machine record; tearing down the machine is a separate DeleteMachine call so the two lifecycles stay orthogonal.
func DeleteAsset ¶
func DeleteMachine ¶
func DeleteNodePool ¶
func DeleteNodePoolCloud ¶
DeleteNodePoolCloud deletes a node pool from its cloud provider and, only once the provider confirms the pool is gone, removes the DB row. A pool with no cloud linkage is a DB-only record and is removed directly. A provider error other than 404 (e.g. a transient 422 during provisioning) is propagated and the DB row is left intact so a retry can reconcile once the pool settles.
EVERY field it acts on comes from the STORED ROW. The caller's pool argument says WHICH row (owner+name, and the owner is the authenticated org — the handler overwrites it); it never says which upstream pool that is, on whose account, in which cluster.
It used to gate the whole upstream round-trip on the BODY's PoolID and Provider being non-empty. Omit either — send `{"name":"gpu"}` and nothing else — and visor skipped the provider entirely and deleted the row: the cluster kept running on Hanzo's house account and the row that billed it was gone. The body is the customer's, so opting out of the upstream check was one absent JSON field away. It also resolved the Provider from the body, and treated a Provider it could not find as permission to drop the row.
func DeletePlan ¶
func DeleteProvider ¶
func DeleteRecord ¶
func DeleteSession ¶
func DeleteSessionById ¶
func DeleteVolume ¶
func DeleteVolumeCloud ¶
func DetachVolumeCloud ¶
func DisconnectFleetWorker ¶
DisconnectFleetWorker marks a worker disconnected (stopping its device fee), returning whether a connected worker was present. The row is retained (not deleted) so its history and last DeviceCount survive for the closing month's bill; the meter simply stops counting it.
func EngineFor ¶
func EngineFor(owner string) (*relational.Engine, error)
EngineFor returns the storage engine that serves owner under the configured backend. This is the single entry point backend-agnostic code MUST use so a query works unchanged on either backend.
func ForgetClusterPools ¶ added in v1.108.24
ForgetClusterPools removes every billable row belonging to a cluster — the object half of service's forgetCluster seam. A row that outlives its cluster keeps invoicing nodes that no longer exist, so a teardown clears them.
func GetAllNodePools ¶
GetAllNodePools fetches all Active node pools across ALL owners for billing reporting. Under Postgres this is one query over the single engine; under Base it unions the per-org SQLite DBs (allEngines), since no single table spans tenants.
func GetAssetCount ¶
func GetBearerUser ¶
GetBearerUser validates an "Authorization: Bearer <IAM JWT>" header and returns the authenticated user, or nil. iamsdk.ParseJwtToken verifies the token SIGNATURE (jwt.ParseWithClaims + x509), so a forged/tampered token is rejected.
Signature alone is NOT sufficient: Hanzo IAM publishes ONE shared JWKS holding every brand's cert (hanzo/lux/zoo/pars/...), so a validly-signed token from any brand — including public self-service signups — passes the signature check. We therefore bind the token to THIS deployment by BRAND (issuer), not by a single org:
- owner (org) must be non-empty (an empty-org token can't be scoped), and
- issuer must match the configured brand issuer(s) in iamIssuer, so a sibling brand's token (lux.id/zoo.id/pars.id) is rejected even though its signature verifies.
EVERY org within this brand is accepted — the resell compute surface is multi-tenant (org "hanzo", "maxpower", and every self-service customer org). Each request is org-scoped downstream: resolveComputeOrg pins org = user.Owner (no ?owner override for real users) and Casbin enforces subOwner==objOwner, so one org can never reach another's machines. This is how API/console callers authenticate as a user (org = user.Owner) from a forwarded short-lived Bearer, without a browser cookie session.
func GetKubernetesNodesCloud ¶
GetKubernetesNodesCloud returns DOKS worker nodes — as service.Machines — for every active BYOC DigitalOcean provider that names a cluster (Provider.ClusterID). This is the Provider-record cluster→org association; the house-account tag association lives in service.ListOrgKubernetesNodes and the controller unions both, so a cluster discovered by either path surfaces its nodes (deduped by droplet id) exactly once. The DO provider selection mirrors SyncNodePoolsCloud (Type=="DigitalOcean" && ClusterID!=""), so nodes come from the same clusters visor already reconciles pools for.
func GetMachineCount ¶
func GetNodePoolCount ¶
func GetProviderCount ¶
func GetRecordCount ¶
func GetSession ¶
func GetSession(owner string, offset, limit int, field, value, sortField, sortOrder string) *relational.Session
func GetSessionCount ¶
func GetTenantActorID ¶
GetTenantActorID returns the request's acting principal scope (or "").
func GetTenantAppID ¶
GetTenantAppID returns the request's optional app scope beneath org (or "").
func GetTenantContextValue ¶
GetTenantContextValue reads a scope value back, trimmed; "" when unset or when c is nil. This is the ONE read-back; the typed getters below are thin adapters.
func GetTenantEnv ¶
GetTenantEnv returns the request's environment scope (or "").
func GetTenantOrgID ¶
GetTenantOrgID returns the request's owning org scope (or "").
func GetTenantProjectID ¶
GetTenantProjectID returns the request's optional project scope beneath app (or "").
func InitAdapter ¶
func InitAdapter()
func InitConfig ¶
func InitConfig()
InitConfig is retained as the config+store bootstrap entry point. Config now loads lazily on first read (conf package), so this simply opens the store.
func InitStore ¶
func InitStore()
InitStore installs the pgStore engine provider for the Postgres backend. Base mode is wired directly in InitAdapter (it never opens a Postgres adapter), so this runs only on the opt-in Postgres path.
func IsBillingOwner ¶
func IsBillingOwner() bool
IsBillingOwner is the exported ownership gate the metering ticker checks before it arms an hourly sweep, so non-owner replicas never even enumerate machines or call commerce. It is an optimization layered over the authoritative per-claim gate inside ClaimMeterHour / ClaimBillingUnit — both consult the SAME predicate, so the ticker gate can never admit a claim the lease path would refuse.
func QueryRecord ¶
func Ready ¶ added in v1.108.24
func Ready() error
Ready reports whether visor can still reach the store every route depends on. It is the question a readiness probe asks, answered in the ONE package that can answer it: the backend is chosen here and `store` is unexported, so no caller outside object could form the answer without a second copy of the selection rule.
It pings the SHARED engine and not every org's, because the shared engine is the one both backends always have, and a fan-out over per-org SQLite would turn a probe that runs every ten seconds into one file open per tenant — a health check whose cost grows with the customer list is an outage waiting for a big enough customer list.
A nil store is unready rather than an error to shout about: it is what visor looks like between process start and InitAdapter, which is exactly the window a readiness probe exists to keep traffic out of.
func RecordSeedPool ¶ added in v1.108.24
RecordSeedPool persists a cluster's seed pool as the row the hourly sweep bills. It is the object half of service's recordSeed seam, handed to the metered cluster provision at the composition root.
The row is written with the rate the org was authorized at (CostPerHour) and CreatedTime NOW, which is what makes the hour exactly-once: the provision path debited this hour, and the sweep's one launch-hour rule (service.CreatedInHour) skips a pool created in the current hour. Hour two is the sweep's, and every hour after.
Idempotent on (Owner, Name) FOR THE SAME CLUSTER: a re-recorded pool updates in place rather than failing the PK, so a retried create never leaves the cluster unbilled.
A DIFFERENT cluster under the same (Owner, Name) is a COLLISION and is refused. The name is the customer's — it comes straight out of the cluster-create body — so two clusters asking for the same seed-pool name is a thing any tenant can do twice in a row, by accident or otherwise. Updating in place there repointed the first cluster's row at the second cluster, and the first cluster stopped being a row anybody could bill.
The refusal is safe precisely because the row is no longer the meter of record for a house cluster: the hourly sweep bills the provider's live pools, so the second cluster is billed whether or not this row lands. What the refusal buys is that the FIRST cluster's row — its rate, its project, its create hour — is not silently overwritten by the second.
func RegisterMembership ¶ added in v1.108.22
func RegisterMembership(m ha.Membership)
RegisterMembership installs the live replica-set source election runs over. It is the ONE seam by which a deployment that can enumerate visor's replicas (a cluster controller, an operator sidecar) teaches this process who its peers are. A single-process deployment registers ha.Static(id): the sole process is the sole writer, so it correctly elects itself.
func ResizeVolumeCloud ¶
func SeedDefaultPlans ¶
SeedDefaultPlans inserts default plans if none exist for the given owner.
func SelfID ¶ added in v1.108.22
func SelfID() string
SelfID is this replica's stable identity for HRW weighting: POD_NAME (Downward API) when set, else the container hostname (which is the pod name in a Deployment pod). A stable, unique-per-replica string is all HRW needs.
Exported so the composition root can build ha.Static from the SAME identity the election weighs. Two spellings of "who am I" is one spelling too many.
func SetTenantContextValue ¶
SetTenantContextValue stows a non-empty scope value on the request context locals. Empty values are skipped so an absent header leaves the key unset and every getter falls through to "" — the caller decides whether a missing scope is fatal (org) or optional (app/project).
func Shared ¶
func Shared() *relational.Engine
Shared returns the engine holding the shared tables (the Plan catalog and the MeterLease coordination lease).
It is cross-POD only under the Postgres backend, where it is the one durable linearizable store and the insert-once lease PK therefore holds cluster-wide. Under Base (the default) it is the pod-local `_global` SQLite coord, hydrated from and shipped to the object store — durable across a restart, but NOT shared between concurrent pods. There, exactly-once rests on the single-writer election in coordinator.go, not on the PK.
This comment used to read "Postgres under both backends", which is false for Base and is precisely why the billing gate's importance was invisible: it made the election look like belt-and-braces over a global constraint when it is in fact the only thing standing between two pods and a double debit.
func SyncMachinesCloud ¶
func SyncNodePoolsCloud ¶
SyncNodePoolsCloud fetches node pools from DO for all active DigitalOcean providers with a ClusterID and upserts them into the DB.
func UnbindAgent ¶
UnbindAgent removes the binding for a machine. Returns whether a binding was present. Orthogonal to the machine lifecycle — it never deletes the machine.
func UpdateAgentBinding ¶
func UpdateAgentBinding(binding *AgentBinding) (bool, error)
UpdateAgentBinding writes all columns of an existing binding by PK.
func UpdateNodePool ¶
UpdateNodePool applies a client's edit to a node pool — and the row it writes is the STORED row with the editable fields applied, never the request body.
The difference is the whole meter. The hourly sweep decides what to bill from State, Count and CostPerHour; the create path decides ownership from Owner and OrgID; the provider is identified by ClusterID and PoolID. Writing the body's columns handed all of those to the customer: `{"state":"Deleted"}` removed a running GPU pool from billing forever, `{"costPerHour":1}` re-priced it to a cent an hour, and a body naming another owner/name rewrote the primary key and corrupted a second row. The pool kept running either way — DigitalOcean never heard about any of it.
So there are exactly three editable fields, and they are the autoscale bounds: nothing the meter reads is reachable from a request. Size, Count, State and CostPerHour are the PROVIDER's answer, written only by the paths that ask it (CreateNodePoolCloud, ScaleNodePoolCloud, SyncNodePoolsCloud, RecordSeedPool).
func UpdateSession ¶
Types ¶
type Adapter ¶
type Adapter struct {
// contains filtered or unexported fields
}
Adapter represents the database adapter for policy storage.
func NewAdapter ¶
NewAdapter is the constructor for Adapter.
type AgentBinding ¶
type AgentBinding struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
// Project is the attribution dimension alongside Owner: the project WITHIN the
// org this agent binding belongs to. Additive, Sync2-safe, defaults to "".
Project string `xorm:"varchar(100)" json:"project"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"`
// Bound cloud Agent identity. `Org` is the cloud/IAM organization that owns
// the Agent (`<org>-<agent>` service-account naming); `AgentName` is the
// Agent's name in the cloud `/v1/agents` registry.
Org string `xorm:"varchar(100)" json:"org"`
AgentName string `xorm:"varchar(100)" json:"agentName"`
// MachineId is the machine's id (`owner/machine-name`), duplicated from the
// PK for a stable JSON field the operator can echo without re-splitting.
MachineId string `xorm:"varchar(200)" json:"machineId"`
// Provider + PublicIp are denormalized snapshots of the bound machine for
// quick status reads without a second machine lookup.
Provider string `xorm:"varchar(100)" json:"provider"`
PublicIp string `xorm:"varchar(100)" json:"publicIp"`
// BotVersion is the @hanzo/bot npm version the runtime targets. Empty means
// "track the machine's launch default" (the cloud-init installs `@hanzo/bot`
// latest at provision time); a pinned semver is recorded verbatim.
BotVersion string `xorm:"varchar(100)" json:"botVersion"`
// Status is the reconciled lifecycle state (Pending/Bound/Error). Message
// carries the human-readable reason behind the current Status.
Status string `xorm:"varchar(100)" json:"status"`
Message string `xorm:"varchar(500)" json:"message"`
}
AgentBinding records that a machine runs the @hanzo/bot runtime for a specific cloud Agent. It is the vm half of the Bot lifecycle: a Bot = Agent (execution_mode=long-running) + a bound compute running @hanzo/bot. The operator's AgentDeployment controller drives this over `POST /v1/machines/:id/bind-agent`.
The machine is the identity: PK is (Owner, Name) where Name == the machine id (`owner/machine-name`). One machine hosts one agent's bot runtime, so the binding is 1:1 with the machine — re-binding a different agent replaces the prior binding rather than layering.
func BindAgent ¶
func BindAgent(machineId string, org string, agentName string, botVersion string) (*AgentBinding, error)
BindAgent provisions/marks a machine as running the @hanzo/bot runtime for a cloud Agent. It is idempotent: binding a machine that is already bound to the same agent re-reconciles status; binding it to a DIFFERENT agent replaces the prior binding (the machine hosts exactly one agent's bot). The returned binding carries the freshly reconciled honest Status.
It does not itself install the runtime — the runtime is installed by the machine's launch cloud-init, which the operator drives via a machine launch with a `hanzo-bot:<agent>` tag before calling this. BindAgent records the agent↔machine relation and reports the observed convergence state.
func GetAgentBindings ¶
func GetAgentBindings(owner string) ([]*AgentBinding, error)
GetAgentBindings lists every binding owned by `owner`, newest first.
func ReconcileAgentBinding ¶
func ReconcileAgentBinding(machineId string) (*AgentBinding, error)
ReconcileAgentBinding re-derives and persists the honest Status of an existing binding against the live machine state. Used by the GET path so a read always reflects current convergence, and returns nil when the machine has no binding.
type Asset ¶
type Asset struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Category string `xorm:"varchar(100)" json:"category"`
Type string `xorm:"varchar(100)" json:"type"`
Tag string `xorm:"varchar(100)" json:"tag"`
MachineName string `xorm:"varchar(100)" json:"machineName"`
Os string `xorm:"varchar(100)" json:"os"`
PublicIp string `xorm:"varchar(100)" json:"publicIp"`
PrivateIp string `xorm:"varchar(100)" json:"privateIp"`
Size string `xorm:"varchar(100)" json:"size"`
CpuSize string `xorm:"varchar(100)" json:"cpuSize"`
MemSize string `xorm:"varchar(100)" json:"memSize"`
RemoteProtocol string `xorm:"varchar(100)" json:"remoteProtocol"`
RemotePort int `json:"remotePort"`
RemoteUsername string `xorm:"varchar(100)" json:"remoteUsername"`
RemotePassword string `xorm:"varchar(100)" json:"remotePassword"`
AutoQuery bool `json:"autoQuery"`
IsPermanent bool `json:"isPermanent"`
Language string `xorm:"varchar(100)" json:"language"`
EnableRemoteApp bool `json:"enableRemoteApp"`
RemoteApps []*RemoteApp `json:"remoteApps"`
Services []*Service `json:"services"`
Patches []*Patch `json:"patches"`
}
type BillingLease ¶
type BillingLease struct {
Unit string `xorm:"varchar(128) notnull pk" json:"unit"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
}
BillingLease is the generic single-flight lease for a billable UNIT — a daily BYOC-cost line ("byoc:<owner>:<provider>:<YYYYMMDD>") or a monthly per-device line ("device:<owner>:<worker>:<YYYYMM>"). It is the money-safety twin of MeterLease: visor runs replicas: 2 with no leader election and commerce does NOT dedup the withdraw on requestId, so without a cluster-wide claim BOTH replicas would meter the same unit and double-bill it.
It is a SEPARATE table from MeterLease on purpose: the hourly compute sweep keeps using MeterLease unchanged, so a rolling deploy of this change can never make one replica claim an hour in `meter_lease` while another claims the same hour in a renamed column — which would double-bill every hour spanning the rollout. Unit is varchar(128) (MeterLease.Hour is varchar(12)); the daily/monthly keys do not fit the hour column, which is the other reason for a distinct table.
type CostCursor ¶
type CostCursor struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Provider string `xorm:"varchar(100) notnull pk" json:"provider"`
Month string `xorm:"varchar(6) notnull pk" json:"month"` // UTC "YYYYMM"
BilledSpendCents int64 `json:"billedSpendCents"` // account MTD spend already 1%-billed
UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"`
}
CostCursor is the per-account watermark for BYOC cost billing (fleet tier a). It records how much of a BYOC provider's month-to-date cloud spend has ALREADY had the 1% fee applied, so each daily collector run meters only the INCREMENT since the last run — totaling 1% of the month's spend, idempotently. Month rollover is implicit in the PK: a new month starts a fresh cursor at zero, so the first run of a month bills 1% of that month's spend-to-date and no more.
The daily BillingLease serializes the read-modify-write across replicas (only the lease winner advances the cursor), so this row only needs to persist the advancing watermark — no compare-and-set is required.
type FleetWorker ¶
type FleetWorker struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
// Project is the attribution dimension alongside Owner (empty == default project).
Project string `xorm:"varchar(100)" json:"project"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"`
Kind string `xorm:"varchar(50)" json:"kind"` // FleetWorkerBYOHardware | FleetWorkerValidator
DeviceCount int `json:"deviceCount"` // GPUs/devices → the $1/mo multiplier (tier b)
GpuModel string `xorm:"varchar(100)" json:"gpuModel"` // informational (e.g. "H100")
// ValidatorAddress is the box's hanzo.network validator address; when Kind is
// FleetWorkerValidator it is matched against the on-chain validator set to grant
// the free-tier exemption. Empty for a plain BYO-hardware box.
ValidatorAddress string `xorm:"varchar(100)" json:"validatorAddress"`
State string `xorm:"varchar(50)" json:"state"` // FleetWorkerConnected | FleetWorkerDisconnected
LastSeen string `xorm:"varchar(100)" json:"lastSeen"`
}
FleetWorker is a BYO compute box connected to the Hanzo cloud fleet (the `hanzo gpu connect` / desktop-link path). It is keyed by (Owner, Name) — Owner is the org boundary, Name a stable per-box id (hostname/uuid) — with Project as the second attribution dimension so device billing is per org+project. The device meter reads DeviceCount while State==connected; the validator exemption reads Kind + ValidatorAddress.
func ConnectFleetWorker ¶
func ConnectFleetWorker(worker *FleetWorker) (*FleetWorker, error)
ConnectFleetWorker upserts a worker on connect (arming its billing), idempotent on (Owner, Name): a reconnect refreshes DeviceCount/Kind/LastSeen and flips State back to connected while preserving CreatedTime. It never fabricates identity — Owner/Name/Kind/DeviceCount are supplied by the caller (the connect handler, org-scoped and validated) and only timestamps + State are stamped here.
func GetConnectedFleetWorkers ¶
func GetConnectedFleetWorkers() ([]*FleetWorker, error)
GetConnectedFleetWorkers returns every CONNECTED worker across ALL orgs — the set the monthly device meter bills. Like the running-machine sweep, it lists cross-tenant and recovers the org from each row, so one pass meters every org's connected devices. A disconnected worker is excluded (device fee stops on disconnect).
func GetFleetWorkers ¶
func GetFleetWorkers(owner string) ([]*FleetWorker, error)
GetFleetWorkers lists an org's workers, newest first.
func (*FleetWorker) GetId ¶
func (w *FleetWorker) GetId() string
type Machine ¶
type Machine struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
// Project is the second attribution dimension alongside Owner (the tenant
// boundary): the project WITHIN the org that owns this machine. Not part of the
// (Owner, Name) primary key — an additive, Sync2-safe column that defaults to
// "" (the org's default project), so existing rows and callers are unaffected.
Project string `xorm:"varchar(100)" json:"project"`
Id string `xorm:"varchar(100)" json:"id"`
Provider string `xorm:"varchar(100)" json:"provider"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"`
ExpireTime string `xorm:"varchar(100)" json:"expireTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Region string `xorm:"varchar(100)" json:"region"`
Zone string `xorm:"varchar(100)" json:"zone"`
Category string `xorm:"varchar(100)" json:"category"`
Type string `xorm:"varchar(100)" json:"type"`
Size string `xorm:"varchar(100)" json:"size"`
Tag string `xorm:"varchar(500)" json:"tag"`
State string `xorm:"varchar(100)" json:"state"`
Image string `xorm:"varchar(100)" json:"image"`
Os string `xorm:"varchar(100)" json:"os"`
PublicIp string `xorm:"varchar(100)" json:"publicIp"`
PrivateIp string `xorm:"varchar(100)" json:"privateIp"`
CpuSize string `xorm:"varchar(100)" json:"cpuSize"`
MemSize string `xorm:"varchar(100)" json:"memSize"`
// DB info
RemoteProtocol string `xorm:"varchar(100)" json:"remoteProtocol"`
RemotePort int `json:"remotePort"`
RemoteUsername string `xorm:"varchar(100)" json:"remoteUsername"`
RemotePassword string `xorm:"varchar(100)" json:"remotePassword"`
}
func CreateMachineCloud ¶
func CreateMachineCloud(owner string, providerName string, spec *service.CreateMachineSpec) (*Machine, error)
CreateMachineCloud launches a new VM via the cloud provider and registers it in the DB.
func GetMachine ¶
func GetMachines ¶
func GetMaskedMachines ¶
func GetPaginationMachines ¶
type MeterLease ¶
type MeterLease struct {
Hour string `xorm:"varchar(12) notnull pk" json:"hour"` // UTC "YYYYMMDDHH" bucket — the billable unit.
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
}
MeterLease is a single-flight lease for the hourly compute-metering sweep. Its whole purpose is a MONEY-SAFETY invariant: the visor Deployment runs replicas: 2 with no leader election, so without a lease BOTH replicas would run service.MeterRunningMachines every hour and debit every running machine twice (the per-machine hour-bucketed RequestID is only a dedup HINT — commerce's RecordUsage does NOT dedup the withdraw transaction on requestId, so the client key alone does not stop a duplicate debit). The lease makes exactly one replica perform the sweep per wall-clock hour, cluster-wide.
The mechanism is the same insert-once-wins primitive the rest of object uses: Hour is the PK, so only the FIRST Insert for a given hour succeeds; a concurrent replica's Insert fails the unique-key constraint and that replica skips the hour. It survives a mid-hour restart too — a restarted replica finds the hour already claimed and does not re-sweep (so a rollout cannot re-bill the hour).
type MigrationReport ¶
type MigrationReport struct {
Table string
SourceRows int
WrittenRows int
Orgs int // distinct owner DBs the rows fanned into
}
MigrationReport records what MigratePostgresToBase copied for one table.
func MigratePostgresToBase ¶
func MigratePostgresToBase(src *relational.Engine, dst *baseStore) ([]MigrationReport, error)
MigratePostgresToBase copies the per-tenant visor tables from the shared Postgres engine into per-org Base SQLite files, routing each row to DBPath(owner). It iterates perOrgModels() -- the SAME registry the Base schema sync uses -- so it can never drift from what an org DB actually holds. The shared tables (Plan catalog, MeterLease lease) are deliberately NOT migrated: they stay on the shared Postgres coordination engine under Base mode (see LLM.md, Base backend: shared vs per-org).
It NEVER runs at boot: an operator invokes it explicitly during the cutover window (e.g. a `visor migrate` subcommand). Rows are grouped by their Owner field; the rare row with an empty Owner (e.g. a Record whose Organization was unset) routes to the _global sentinel DB. This mirrors hanzo/cloud's introspective migration/pg_to_sqlite.go, but is schema-aware because visor owns its models rather than a drifted upstream schema.
type NodePool ¶
type NodePool struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"`
ClusterID string `xorm:"varchar(100)" json:"clusterId"`
PoolID string `xorm:"varchar(100)" json:"poolId"`
Provider string `xorm:"varchar(100)" json:"provider"`
Size string `xorm:"varchar(100)" json:"size"`
Count int `json:"count"`
MinNodes int `json:"minNodes"`
MaxNodes int `json:"maxNodes"`
AutoScale bool `json:"autoScale"`
State string `xorm:"varchar(100)" json:"state"`
CostPerHour int64 `json:"costPerHour"` // cents
OrgID string `xorm:"varchar(100)" json:"orgId"`
ProjectID string `xorm:"varchar(100)" json:"projectId"`
}
func CreateNodePoolCloud ¶
func CreateNodePoolCloud(owner, providerName, clusterID string, spec *service.CreateNodePoolSpec) (*NodePool, error)
CreateNodePoolCloud creates a new node pool in DOKS via the cloud provider and persists it.
Money gate: the pool is priced from the resale catalog and the owner is authorized for its FULL first hour (hourly × node count) BEFORE anything is provisioned. A size that cannot be priced and an owner that cannot be authorized both provision nothing — the pool used to be created with no gate at all and then billed at CostPerHour, which was never computed here, so a GPU pool ran at $0/hr for as long as it stayed up.
func GetNodePool ¶
func GetNodePools ¶
func GetPaginationNodePools ¶
func ScaleNodePoolCloud ¶
func ScaleNodePoolCloud(owner, providerName, clusterID, poolID string, count int) (*NodePool, error)
ScaleNodePoolCloud updates the node count of an existing DOKS node pool.
Money gate: scaling UP is a provision, so the owner is authorized for the first hour of the ADDED nodes before the upstream is touched. Scaling down (or to the same count) adds no cost and is never gated — refusing to shrink a pool because a balance is low would keep the meter running on nodes the customer asked to release.
type Patch ¶
type Patch struct {
Name string `json:"name"`
Category string `json:"category"`
Title string `json:"title"`
Url string `json:"url"`
Size string `json:"size"`
ExpectedStatus string `json:"expectedStatus"`
Status string `json:"status"`
InstallTime string `json:"installTime"`
Message string `json:"message"`
}
type Plan ¶
type Plan struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Description string `xorm:"varchar(500)" json:"description"`
Category string `xorm:"varchar(100)" json:"category"` // "bot", "standard", "pro", "power"
State string `xorm:"varchar(100)" json:"state"` // "Active", "Inactive"
// Specs advertised to the customer
VCpu int `json:"vCpu"`
Ram int `json:"ram"` // MB
Disk int `json:"disk"` // GB
CpuType string `xorm:"varchar(50)" json:"cpuType"` // "shared", "dedicated"
// Pricing (cents/mo)
PriceMonthly int `json:"priceMonthly"` // customer price in cents USD
// Region availability
Regions string `xorm:"varchar(500)" json:"regions"` // comma-separated: "us,eu,sg"
// Provider mapping per region (JSON)
// e.g. {"us":{"provider":"Hetzner","serverType":"cpx31","location":"ash"},...}
ProviderMapping string `xorm:"mediumtext" json:"providerMapping"`
// Traffic included (GB)
TrafficIncluded int `json:"trafficIncluded"`
SortOrder int `json:"sortOrder"`
}
Plan represents a resale VM plan available to customers.
func DefaultPlans ¶
DefaultPlans returns the Hanzo Cloud plan catalog. Provider mapping is internal — customers never see backend provider names.
Regions: "us" (ash/hil), "eu" (fsn1/nbg1), "sg" (sin) Pricing aligned with hanzo/pricing cloudPlans.
func GetAllPlans ¶
func GetPlans ¶
Plan is a global read-only catalog: identical for every org, so it lives on the shared engine (Shared(), Postgres under both backends), never duplicated into per-org SQLite. The owner column is retained so white-label brands can scope their own catalog, but the physical table is shared. All Plan CRUD therefore routes through Shared().
type Provider ¶
type Provider struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
// Project is the attribution dimension alongside Owner: the project WITHIN the
// org that owns this BYOC provider. Additive, Sync2-safe, defaults to "".
Project string `xorm:"varchar(100)" json:"project"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Category string `xorm:"varchar(100)" json:"category"`
Type string `xorm:"varchar(100)" json:"type"`
ClientId string `xorm:"varchar(100)" json:"clientId"`
ClientSecret string `xorm:"varchar(100)" json:"clientSecret"`
Region string `xorm:"varchar(100)" json:"region"`
Network string `xorm:"varchar(100)" json:"network"`
Chain string `xorm:"varchar(100)" json:"chain"`
BrowserUrl string `xorm:"varchar(200)" json:"browserUrl"`
State string `xorm:"varchar(100)" json:"state"`
ProviderUrl string `xorm:"varchar(200)" json:"providerUrl"`
ClusterID string `xorm:"varchar(100)" json:"clusterId"` // DOKS cluster UUID
// CostReadScope carries the per-cloud identifier the fleet-billing cost collector
// needs to read this BYOC account's spend, beyond the (ClientId, ClientSecret,
// Region) triple used to manage machines. It is cloud-specific and additive
// (Sync2-safe, defaults ""):
// AWS — ignored (Cost Explorer is account-wide from the access key).
// DO — ignored (the balance endpoint is account-wide from the token).
// Azure— "<tenantId>/<subscriptionId>" (Cost Management query scope + auth tenant).
// GCP — "<project>.<dataset>.<table>" of the BigQuery billing-export table.
// Empty means "cost-read not configured": the collector honestly skips this
// provider (no fee) rather than fabricating spend.
CostReadScope string `xorm:"varchar(300)" json:"costReadScope"`
}
func GetAllActiveCloudProviders ¶
GetAllActiveCloudProviders returns every org's active BYOC cloud provider — the set the daily fleet cost collector bills 1% of spend against. Like the running- machine sweep it scans cross-tenant and each row carries its own Owner/Project, so one pass attributes every org's cloud fee correctly.
func GetMaskedProvider ¶
func GetMaskedProviders ¶
func GetPaginationProviders ¶
func GetProvider ¶
func GetProviders ¶
type Record ¶
type Record struct {
Id int `xorm:"int notnull pk autoincr" json:"id"`
Owner string `xorm:"varchar(100) index" json:"owner"`
Name string `xorm:"varchar(100) index" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
Organization string `xorm:"varchar(100)" json:"organization"`
ClientIp string `xorm:"varchar(100)" json:"clientIp"`
UserAgent string `xorm:"varchar(100)" json:"userAgent"`
User string `xorm:"varchar(100)" json:"user"`
Method string `xorm:"varchar(100)" json:"method"`
RequestUri string `xorm:"varchar(1000)" json:"requestUri"`
Action string `xorm:"varchar(1000)" json:"action"`
Language string `xorm:"varchar(100)" json:"language"`
Object string `xorm:"mediumtext" json:"object"`
Response string `xorm:"mediumtext" json:"response"`
Provider string `xorm:"varchar(100)" json:"provider"`
Block string `xorm:"varchar(100)" json:"block"`
Transaction string `xorm:"varchar(500)" json:"transaction"`
IsTriggered bool `json:"isTriggered"`
}
func GetPaginationRecords ¶
func GetRecords ¶
func NewRecord ¶
NewRecord builds an audit record from the ZAP request context and the response payload the handler produced (respJSON — the value ResponseOk/ ResponseError stashed for the record filter). respJSON stands in for Beego's ctx.Input.Data()["json"]: the ONE thing the record needs from the response is its {status,msg} envelope.
type Session ¶
type Session struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
StartTime string `xorm:"varchar(100)" json:"startTime"`
EndTime string `xorm:"varchar(100)" json:"endTime"`
Protocol string `xorm:"varchar(20)" json:"protocol"`
ConnectionId string `xorm:"varchar(50)" json:"connectionId"`
Asset string `xorm:"varchar(200) index" json:"asset"`
Creator string `xorm:"varchar(36) index" json:"creator"`
ClientIp string `xorm:"varchar(200)" json:"clientIp"`
UserAgent string `xorm:"varchar(200)" json:"userAgent"`
ClientIpDesc string `xorm:"varchar(100)" json:"clientIpDesc"`
UserAgentDesc string `xorm:"varchar(100)" json:"userAgentDesc"`
Width int `json:"width"`
Height int `json:"height"`
Status string `xorm:"varchar(20) index" json:"status"`
Recording string `xorm:"varchar(1000)" json:"recording"`
Code int `json:"code"`
Message string `json:"message"`
Mode string `xorm:"varchar(10)" json:"mode"`
Operations []string `xorm:"json varchar(1000)" json:"operations"`
Reviewed bool `json:"reviewed"`
CommandCount int64 `json:"commandCount"`
}
func CreateSession ¶
func GetConnSession ¶
func GetPaginationSessions ¶
func GetSessions ¶
func GetSessionsByStatus ¶
GetSessionsByStatus lists sessions in any of the given statuses across ALL orgs -- a cluster-wide sweep the stale-session GC ticker runs. Under Postgres this is one query over the single engine; under Base it unions the per-org SQLite DBs (allEngines), since there is no single table spanning tenants.
type StorageBackend ¶
type StorageBackend string
StorageBackend names the configured persistence backend.
const ( // BackendPostgres is the historical shared-Postgres backend (default). BackendPostgres StorageBackend = "postgres" // BackendBase is the per-org SQLite substrate (hanzoai/base, HIP-0302). BackendBase StorageBackend = "base" )
func ConfiguredBackend ¶
func ConfiguredBackend() StorageBackend
ConfiguredBackend reads the storageBackend config knob. Default is Base (SQLite for everything — the house rule); a multi-instance deployment opts INTO Postgres with storageBackend=postgres.
type Volume ¶
type Volume struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
// Project is the attribution dimension alongside Owner: the project WITHIN the
// org that owns this volume. Additive, Sync2-safe, defaults to "".
Project string `xorm:"varchar(100)" json:"project"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Id string `xorm:"varchar(100)" json:"id"` // Cloud provider volume ID
Provider string `xorm:"varchar(100)" json:"provider"` // Provider name
Machine string `xorm:"varchar(100)" json:"machine"` // Attached machine name (empty if detached)
Region string `xorm:"varchar(100)" json:"region"`
Size int `json:"size"` // GB
State string `xorm:"varchar(100)" json:"state"` // "Available", "Attached", "Creating"
Format string `xorm:"varchar(50)" json:"format"` // "ext4", "xfs", etc.
MountPoint string `xorm:"varchar(200)" json:"mountPoint"` // e.g. "/mnt/data"
}
Volume represents a block storage volume attached to a machine.
func CreateVolumeCloud ¶
func GetVolumes ¶
type WhitelabelConfig ¶
type WhitelabelConfig struct {
AppName string `json:"appName"`
LogoUrl string `json:"logoUrl"`
FaviconUrl string `json:"faviconUrl"`
PrimaryColor string `json:"primaryColor"`
SupportUrl string `json:"supportUrl"`
DocsUrl string `json:"docsUrl"`
OrgFilter string `json:"orgFilter"`
}
WhitelabelConfig holds per-hostname branding configuration.
func GetWhitelabelConfig ¶
func GetWhitelabelConfig(host string) *WhitelabelConfig
GetWhitelabelConfig returns the branding config for a given hostname. Falls back to the default (Hanzo) config if no match is found.
Source Files
¶
- adapter.go
- agent_binding.go
- asset.go
- auth.go
- billing_lease.go
- coordinator.go
- cost_cursor.go
- fleet_worker.go
- machine.go
- machine_cloud.go
- meter_lease.go
- migrate_base.go
- node_pool.go
- plan.go
- plan_seed.go
- provider.go
- provider_util.go
- record.go
- record_chain.go
- session.go
- store.go
- store_base.go
- store_pg.go
- store_replica.go
- tenant_context.go
- volume.go
- volume_cloud.go
- whitelabel.go