object

package
v1.108.26 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 14, 2026 License: Apache-2.0 Imports: 31 Imported by: 0

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

View Source
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.
View Source
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.

View Source
const (
	FleetWorkerConnected    = "connected"
	FleetWorkerDisconnected = "disconnected"
)

Worker connection states.

View Source
const (
	NoConnect    = "no_connect"
	Connecting   = "connecting"
	Connected    = "connected"
	Disconnected = "disconnected"
)
View Source
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.

View Source
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).

View Source
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 AddAsset

func AddAsset(asset *Asset) (bool, error)

func AddMachine

func AddMachine(machine *Machine) (bool, error)

func AddNodePool

func AddNodePool(pool *NodePool) (bool, error)

func AddPlan

func AddPlan(plan *Plan) (bool, error)

func AddProvider

func AddProvider(provider *Provider) (bool, error)

func AddRecord

func AddRecord(record *Record) bool

func AddSession

func AddSession(session *Session) (bool, error)

func AddVolume

func AddVolume(volume *Volume) (bool, error)

func AdvanceCostCursor

func AdvanceCostCursor(owner, provider, month string, currentMTDCents int64) (int64, error)

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 AttachVolumeCloud(owner string, providerName string, volumeCloudID string, machineCloudID string) error

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

func ClaimBillingUnit(unit string, now time.Time) bool

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

func ClaimMeterHour(now time.Time) bool

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 CloseDBSession

func CloseDBSession(id string, code int, msg string) error

func CloseSession

func CloseSession(id string, code int, msg string) error

func CommitRecord

func CommitRecord(record *Record) (bool, error)

func DBPath

func DBPath(root, owner string) string

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 DeleteAsset(asset *Asset) (bool, error)

func DeleteMachine

func DeleteMachine(machine *Machine) (bool, error)

func DeleteNodePool

func DeleteNodePool(pool *NodePool) (bool, error)

func DeleteNodePoolCloud

func DeleteNodePoolCloud(pool *NodePool) (bool, error)

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 DeletePlan(plan *Plan) (bool, error)

func DeleteProvider

func DeleteProvider(provider *Provider) (bool, error)

func DeleteRecord

func DeleteRecord(record *Record) (bool, error)

func DeleteSession

func DeleteSession(session *Session) (bool, error)

func DeleteSessionById

func DeleteSessionById(id string) (bool, error)

func DeleteVolume

func DeleteVolume(volume *Volume) (bool, error)

func DeleteVolumeCloud

func DeleteVolumeCloud(owner string, providerName string, volumeCloudID string) error

func DetachVolumeCloud

func DetachVolumeCloud(owner string, providerName string, volumeCloudID string) error

func DisconnectFleetWorker

func DisconnectFleetWorker(owner, name string) (bool, error)

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

func ForgetClusterPools(org, clusterID string) error

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

func GetAllNodePools(pools *[]*NodePool) error

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 GetAssetCount(owner, field, value string) (int64, error)

func GetBearerUser

func GetBearerUser(authHeader string) *iamsdk.User

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

func GetKubernetesNodesCloud(owner string) ([]*service.Machine, error)

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 GetMachineCount(owner, field, value string) (int64, error)

func GetNodePoolCount

func GetNodePoolCount(owner, field, value string) (int64, error)

func GetProviderCount

func GetProviderCount(owner, field, value string) (int64, error)

func GetRecordCount

func GetRecordCount(owner, field, value string) (int64, error)

func GetSession

func GetSession(owner string, offset, limit int, field, value, sortField, sortOrder string) *relational.Session

func GetSessionCount

func GetSessionCount(owner, status, field, value string) (int64, error)

func GetTenantActorID

func GetTenantActorID(c *zip.Ctx) string

GetTenantActorID returns the request's acting principal scope (or "").

func GetTenantAppID

func GetTenantAppID(c *zip.Ctx) string

GetTenantAppID returns the request's optional app scope beneath org (or "").

func GetTenantContextValue

func GetTenantContextValue(c *zip.Ctx, key string) string

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

func GetTenantEnv(c *zip.Ctx) string

GetTenantEnv returns the request's environment scope (or "").

func GetTenantOrgID

func GetTenantOrgID(c *zip.Ctx) string

GetTenantOrgID returns the request's owning org scope (or "").

func GetTenantProjectID

func GetTenantProjectID(c *zip.Ctx) string

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 QueryRecord(id string) (string, error)

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

func RecordSeedPool(p service.SeedPool) error

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 ResizeVolumeCloud(owner string, providerName string, volumeCloudID string, sizeGB int) error

func SeedDefaultPlans

func SeedDefaultPlans(owner string) error

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

func SetTenantContextValue(c *zip.Ctx, key, value string)

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 SyncMachinesCloud(owner string) (bool, error)

func SyncNodePoolsCloud

func SyncNodePoolsCloud(owner string) (bool, error)

SyncNodePoolsCloud fetches node pools from DO for all active DigitalOcean providers with a ClusterID and upserts them into the DB.

func UnbindAgent

func UnbindAgent(machineId string) (bool, error)

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 UpdateAsset

func UpdateAsset(id string, asset *Asset) (bool, error)

func UpdateMachine

func UpdateMachine(id string, machine *Machine) (bool, error)

func UpdateNodePool

func UpdateNodePool(id string, pool *NodePool) (bool, error)

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 UpdatePlan

func UpdatePlan(owner string, name string, plan *Plan) (bool, error)

func UpdateProvider

func UpdateProvider(id string, provider *Provider) (bool, error)

func UpdateRecord

func UpdateRecord(id string, record *Record) (bool, error)

func UpdateSession

func UpdateSession(id string, session *Session, columns ...string) (bool, error)

func UpdateVolume

func UpdateVolume(owner string, name string, volume *Volume) (bool, error)

func WriteCloseMessage

func WriteCloseMessage(session *guacamole.Session, mode string, code int, msg string)

Types

type Adapter

type Adapter struct {
	// contains filtered or unexported fields
}

Adapter represents the database adapter for policy storage.

func NewAdapter

func NewAdapter(driverName string, dataSourceName string) *Adapter

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"`
}

func GetAsset

func GetAsset(id string) (*Asset, error)

func GetAssets

func GetAssets(owner string) ([]*Asset, error)

func GetMaskedAsset

func GetMaskedAsset(asset *Asset, errs ...error) (*Asset, error)

func GetMaskedAssets

func GetMaskedAssets(assets []*Asset, errs ...error) ([]*Asset, error)

func GetPaginationAssets

func GetPaginationAssets(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*Asset, error)

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 GetMachine(id string) (*Machine, error)

func GetMachines

func GetMachines(owner string) ([]*Machine, error)

func GetMaskedMachine

func GetMaskedMachine(machine *Machine, errs ...error) (*Machine, error)

func GetMaskedMachines

func GetMaskedMachines(machines []*Machine, errs ...error) ([]*Machine, error)

func GetPaginationMachines

func GetPaginationMachines(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*Machine, error)

func (*Machine) GetId

func (machine *Machine) GetId() string

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 GetNodePool(id string) (*NodePool, error)

func GetNodePools

func GetNodePools(owner string) ([]*NodePool, error)

func GetPaginationNodePools

func GetPaginationNodePools(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*NodePool, error)

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.

func (*NodePool) GetId

func (pool *NodePool) GetId() string

type Param

type Param struct {
	Key   string `json:"key"`
	Field string `json:"field"`
	Value string `json:"value"`
}

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

func DefaultPlans(owner string) []*Plan

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 GetAllPlans(owner string) ([]*Plan, error)

func GetPlan

func GetPlan(owner string, name string) (*Plan, error)

func GetPlans

func GetPlans(owner string) ([]*Plan, error)

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

func GetAllActiveCloudProviders() ([]*Provider, error)

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 GetMaskedProvider(provider *Provider, errs ...error) (*Provider, error)

func GetMaskedProviders

func GetMaskedProviders(providers []*Provider, errs ...error) ([]*Provider, error)

func GetPaginationProviders

func GetPaginationProviders(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*Provider, error)

func GetProvider

func GetProvider(id string) (*Provider, error)

func GetProviders

func GetProviders(owner string) ([]*Provider, error)

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 GetPaginationRecords(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*Record, error)

func GetRecord

func GetRecord(id string) (*Record, error)

func GetRecords

func GetRecords(owner string) ([]*Record, error)

func NewRecord

func NewRecord(c *zip.Ctx, respJSON any) (*Record, error)

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 RemoteApp

type RemoteApp struct {
	No            int    `json:"no"`
	RemoteAppName string `xorm:"varchar(100)" json:"remoteAppName"`
	RemoteAppDir  string `xorm:"varchar(100)" json:"remoteAppDir"`
	RemoteAppArgs string `xorm:"varchar(100)" json:"remoteAppArgs"`
}

type Response

type Response struct {
	Status string `json:"status"`
	Msg    string `json:"msg"`
}

type Service

type Service struct {
	No             int    `json:"no"`
	Name           string `json:"name"`
	Path           string `json:"path"`
	Port           int    `json:"port"`
	ProcessId      int    `json:"processId"`
	ExpectedStatus string `json:"expectedStatus"`
	Status         string `json:"status"`
	SubStatus      string `json:"subStatus"`
	Message        string `json:"message"`
}

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 CreateSession(session *Session, machineId string, mode string) (*Session, error)

func GetConnSession

func GetConnSession(id string) (*Session, error)

func GetPaginationSessions

func GetPaginationSessions(owner, status string, offset, limit int, field, value, sortField, sortOrder string) ([]*Session, error)

func GetSessions

func GetSessions(owner string) ([]*Session, error)

func GetSessionsByStatus

func GetSessionsByStatus(statuses []string) ([]*Session, error)

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.

func (*Session) GetId

func (s *Session) GetId() string

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 CreateVolumeCloud(owner string, providerName string, spec *service.CreateVolumeSpec) (*Volume, error)

func GetVolume

func GetVolume(owner string, name string) (*Volume, error)

func GetVolumes

func GetVolumes(owner string) ([]*Volume, error)

func (*Volume) GetId

func (v *Volume) GetId() string

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL