database

package
v0.7.0-rc.1 Latest Latest
Warning

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

Go to latest
Published: Mar 25, 2026 License: PostgreSQL Imports: 34 Imported by: 0

Documentation

Index

Constants

View Source
const (
	TargetSessionAttrsPrimary       = "primary"
	TargetSessionAttrsPreferStandby = "prefer-standby"
	TargetSessionAttrsStandby       = "standby"
	TargetSessionAttrsReadWrite     = "read-write"
	TargetSessionAttrsAny           = "any"
)

libpq target_session_attrs values (PG 14+). See: https://www.postgresql.org/docs/current/libpq-connect.html

View Source
const InstanceMonitorRefreshInterval = 5 * time.Second
View Source
const ResourceTypeInstance resource.Type = "database.instance"
View Source
const ResourceTypeLagTrackerCommitTS resource.Type = "database.lag_tracker_commit_ts"
View Source
const ResourceTypeNode resource.Type = "database.node"
View Source
const ResourceTypeReplicationSlot resource.Type = "database.replication_slot"
View Source
const ResourceTypeReplicationSlotAdvanceFromCTS resource.Type = "database.replication_slot_advance_from_cts"
View Source
const ResourceTypeReplicationSlotCreate resource.Type = "database.replication_slot_create"
View Source
const ResourceTypeServiceInstance = "swarm.service_instance"

ResourceTypeServiceInstance is the resource type identifier for service instances. This constant is defined here to avoid import cycles between the orchestrator and workflow packages.

View Source
const ResourceTypeSubscription resource.Type = "database.subscription"
View Source
const ResourceTypeSwitchover resource.Type = "database.switchover"
View Source
const ResourceTypeSyncEvent resource.Type = "database.sync_event"
View Source
const ResourceTypeWaitForSyncEvent resource.Type = "database.wait_for_sync_event"
View Source
const ServiceInstanceMonitorRefreshInterval = 10 * time.Second

Variables

View Source
var (
	ErrDatabaseAlreadyExists   = errors.New("database already exists")
	ErrDatabaseNotFound        = errors.New("database not found")
	ErrDatabaseNotModifiable   = errors.New("database not modifiable")
	ErrInstanceNotFound        = errors.New("instance not found")
	ErrInstanceStopped         = errors.New("instance stopped")
	ErrInvalidDatabaseUpdate   = errors.New("invalid database update")
	ErrInvalidSourceNode       = errors.New("invalid source node")
	ErrServiceInstanceNotFound = errors.New("service instance not found")
)
View Source
var ErrNodeNotInDBSpec = errors.New("node not in db spec")

Functions

func ConnectToInstance

func ConnectToInstance(ctx context.Context, opts *ConnectionOptions) (*pgx.Conn, error)

func DatabaseStateModifiable

func DatabaseStateModifiable(state DatabaseState) bool

func GenerateDatabaseNetworkID added in v0.7.0

func GenerateDatabaseNetworkID(databaseID string) string

GenerateDatabaseNetworkID creates the overlay network ID for a database. Format: {database_id}

func GenerateServiceInstanceID added in v0.7.0

func GenerateServiceInstanceID(databaseID, serviceID, hostID string) string

GenerateServiceInstanceID creates a unique ID for a service instance. Format: {database_id}-{service_id}-{host_id}

func GenerateServiceUsername added in v0.7.0

func GenerateServiceUsername(serviceID string, mode string) string

GenerateServiceUsername creates a deterministic username for a service.

Username Format

The username follows the pattern: "svc_{service_id}_{mode}"

Example:

service_id: "mcp-server", mode: "ro"
Generated username: "svc_mcp_server_ro"

Rationale

- "svc_" prefix: Clearly identifies service accounts vs. application users - service_id: Uniquely identifies the service within the database - mode: Distinguishes RO ("ro") from RW ("rw") users for the same service - Deterministic: Same service_id + mode always generates the same username - Shared: One database user role per service per mode, shared across all instances

Uniqueness

Service IDs are unique within a database. By using the service_id and mode, we guarantee uniqueness even when multiple services exist on the same database.

PostgreSQL Compatibility

PostgreSQL identifier length limit is 63 characters. For short names the full service_id is used directly. When the username exceeds 63 characters, the function appends an 8-character hex hash (from SHA-256 of the full untruncated name) to a truncated prefix. This guarantees uniqueness even when two inputs share a long common prefix.

Short name format: svc_{service_id}_{mode} Long name format: svc_{truncated service_id}_{8-hex-hash}_{mode}

func GetPrimaryInstanceID

func GetPrimaryInstanceID(ctx context.Context, patroniClient *patroni.Client, timeout time.Duration) (string, error)

func InstanceIDFor

func InstanceIDFor(hostID, databaseID, nodeName string) string

func InstanceResourceIdentifier

func InstanceResourceIdentifier(instanceID string) resource.Identifier

func LagTrackerCommitTSIdentifier

func LagTrackerCommitTSIdentifier(originNode, receiverNode string) resource.Identifier

func NodeResourceIdentifier

func NodeResourceIdentifier(nodeName string) resource.Identifier

func Provide

func Provide(i *do.Injector)

func RegisterResourceTypes

func RegisterResourceTypes(registry *resource.Registry)

func ReplicationSlotAdvanceFromCTSResourceIdentifier

func ReplicationSlotAdvanceFromCTSResourceIdentifier(providerNode, subscriberNode string) resource.Identifier

ReplicationSlotAdvanceFromCTSResourceIdentifier creates a stable identifier for this resource.

func ReplicationSlotCreateResourceIdentifier

func ReplicationSlotCreateResourceIdentifier(databaseName, providerNode, subscriberNode string) resource.Identifier

func ReplicationSlotResourceIdentifier added in v0.7.0

func ReplicationSlotResourceIdentifier(providerNode, subscriberNode string) resource.Identifier

func SubscriptionResourceIdentifier

func SubscriptionResourceIdentifier(providerNode, subscriberNode string) resource.Identifier

func SwitchoverResourceIdentifier

func SwitchoverResourceIdentifier(nodeName string) resource.Identifier

func SyncEventResourceIdentifier

func SyncEventResourceIdentifier(providerNode, subscriberNode string) resource.Identifier

func ValidateChangedSpec

func ValidateChangedSpec(current, updated *Spec) error

func WaitForPatroniRunning

func WaitForPatroniRunning(ctx context.Context, patroniClient *patroni.Client, timeout time.Duration) error

func WaitForSyncEventResourceIdentifier

func WaitForSyncEventResourceIdentifier(providerNode, subscriberNode string) resource.Identifier

Types

type BackupConfig

type BackupConfig struct {
	Repositories []*pgbackrest.Repository `json:"repositories"`
	Schedules    []*BackupSchedule        `json:"schedules"`
}

func (*BackupConfig) Clone

func (b *BackupConfig) Clone() *BackupConfig

func (*BackupConfig) DefaultOptionalFieldsFrom

func (b *BackupConfig) DefaultOptionalFieldsFrom(other *BackupConfig)

DefaultOptionalFieldsFrom will default this config's optional fields to the values from the given config.

type BackupSchedule

type BackupSchedule struct {
	ID             string             `json:"id"`
	Type           BackupScheduleType `json:"type"`
	CronExpression string             `json:"cron_expression"`
}

func (*BackupSchedule) Clone

func (b *BackupSchedule) Clone() *BackupSchedule

type BackupScheduleType

type BackupScheduleType string
const (
	BackupScheduleTypeFull        BackupScheduleType = "full"
	BackupScheduleTypeIncremental BackupScheduleType = "incr"
)

type BuildServiceHostListParams added in v0.7.0

type BuildServiceHostListParams struct {
	ServiceHostID      string           // Host where the service instance runs
	NodeInstances      []*NodeInstances // All database instances, grouped by node
	TargetNodes        []string         // Optional ordered node filter (from database_connection.target_nodes)
	TargetSessionAttrs string           // Caller-provided: "primary", "prefer-standby", etc.
}

BuildServiceHostListParams holds the inputs for BuildServiceHostList.

type ConnectionInfo

type ConnectionInfo struct {
	AdminHost        string
	AdminPort        int
	PeerHost         string
	PeerPort         int
	PeerSSLCert      string
	PeerSSLKey       string
	PeerSSLRootCert  string
	PatroniPort      int
	ClientAddresses  []string
	ClientPort       int
	InstanceHostname string
}

func (*ConnectionInfo) AdminDSN

func (c *ConnectionInfo) AdminDSN(dbName string) *postgres.DSN

func (*ConnectionInfo) PatroniURL

func (c *ConnectionInfo) PatroniURL() *url.URL

func (*ConnectionInfo) PeerDSN

func (c *ConnectionInfo) PeerDSN(dbName string) *postgres.DSN

type ConnectionOptions

type ConnectionOptions struct {
	DSN *postgres.DSN
	TLS *tls.Config
}

type Database

type Database struct {
	DatabaseID       string
	TenantID         *string
	CreatedAt        time.Time
	UpdatedAt        time.Time
	State            DatabaseState
	Spec             *Spec
	Instances        []*Instance
	ServiceInstances []*ServiceInstance
}

type DatabaseConnection added in v0.7.0

type DatabaseConnection struct {
	TargetNodes        []string `json:"target_nodes,omitempty"`
	TargetSessionAttrs string   `json:"target_session_attrs,omitempty"`
}

DatabaseConnection controls how a service connects to the database.

func (*DatabaseConnection) Clone added in v0.7.0

type DatabaseState

type DatabaseState string
const (
	DatabaseStateCreating  DatabaseState = "creating"
	DatabaseStateModifying DatabaseState = "modifying"
	DatabaseStateAvailable DatabaseState = "available"
	DatabaseStateDeleting  DatabaseState = "deleting"
	DatabaseStateDegraded  DatabaseState = "degraded"
	DatabaseStateFailed    DatabaseState = "failed"
	DatabaseStateBackingUp DatabaseState = "backing_up"
	DatabaseStateRestoring DatabaseState = "restoring"
	DatabaseStateStopped   DatabaseState = "stopped"
	DatabaseStateUnknown   DatabaseState = "unknown"
)

type DatabaseStore

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

func NewDatabaseStore

func NewDatabaseStore(client *clientv3.Client, root string) *DatabaseStore

func (*DatabaseStore) Create

func (*DatabaseStore) Delete

func (*DatabaseStore) ExistsByKey

func (s *DatabaseStore) ExistsByKey(databaseID string) storage.ExistsOp

func (*DatabaseStore) GetAll

func (*DatabaseStore) GetByKey

func (s *DatabaseStore) GetByKey(databaseID string) storage.GetOp[*StoredDatabase]

func (*DatabaseStore) GetByKeys

func (s *DatabaseStore) GetByKeys(databaseIDs ...string) storage.GetMultipleOp[*StoredDatabase]

func (*DatabaseStore) Key

func (s *DatabaseStore) Key(databaseID string) string

func (*DatabaseStore) Prefix

func (s *DatabaseStore) Prefix() string

func (*DatabaseStore) Update

type Extension

type Extension struct {
	Name    string `json:"name"`
	Version string `json:"version"`
}

type ExtraNetworkSpec

type ExtraNetworkSpec struct {
	ID         string            `json:"id"`                    // required
	Aliases    []string          `json:"aliases,omitempty"`     // optional
	DriverOpts map[string]string `json:"driver_opts,omitempty"` // optional
}

type ExtraVolumesSpec

type ExtraVolumesSpec struct {
	HostPath        string `json:"host_path"`
	DestinationPath string `json:"destination_path"`
}

type HealthCheckResult added in v0.7.0

type HealthCheckResult struct {
	Status    string    `json:"status"`
	Message   string    `json:"message,omitempty"`
	CheckedAt time.Time `json:"checked_at"`
}

type Instance

type Instance struct {
	InstanceID string          `json:"instance_id"`
	DatabaseID string          `json:"database_id"`
	HostID     string          `json:"host_id"`
	NodeName   string          `json:"node_name"`
	State      InstanceState   `json:"state"`
	Status     *InstanceStatus `json:"status"`
	CreatedAt  time.Time       `json:"created_at"`
	UpdatedAt  time.Time       `json:"updated_at"`
	Error      string          `json:"error,omitempty"`
}

type InstanceResource

type InstanceResource struct {
	Spec                     *InstanceSpec         `json:"spec"`
	InstanceHostname         string                `json:"instance_hostname"`
	PrimaryInstanceID        string                `json:"primary_instance_id"`
	OrchestratorDependencies []resource.Identifier `json:"dependencies"`
	ConnectionInfo           *ConnectionInfo       `json:"connection_info"`
}

func GetAllInstances

func GetAllInstances(ctx context.Context, rc *resource.Context, nodeName string) ([]*InstanceResource, error)

func GetPrimaryInstance

func GetPrimaryInstance(ctx context.Context, rc *resource.Context, nodeName string) (*InstanceResource, error)

func (*InstanceResource) Connection

func (r *InstanceResource) Connection(ctx context.Context, rc *resource.Context, dbName string) (*pgx.Conn, error)

func (*InstanceResource) Create

func (r *InstanceResource) Create(ctx context.Context, rc *resource.Context) error

func (*InstanceResource) Delete

func (r *InstanceResource) Delete(ctx context.Context, rc *resource.Context) error

func (*InstanceResource) Dependencies

func (r *InstanceResource) Dependencies() []resource.Identifier

func (*InstanceResource) DiffIgnore

func (r *InstanceResource) DiffIgnore() []string

func (*InstanceResource) Executor

func (r *InstanceResource) Executor() resource.Executor

func (*InstanceResource) Identifier

func (r *InstanceResource) Identifier() resource.Identifier

func (*InstanceResource) Refresh

func (r *InstanceResource) Refresh(ctx context.Context, rc *resource.Context) error

func (*InstanceResource) ResourceVersion

func (r *InstanceResource) ResourceVersion() string

func (*InstanceResource) TypeDependencies added in v0.7.0

func (r *InstanceResource) TypeDependencies() []resource.Type

func (*InstanceResource) Update

func (r *InstanceResource) Update(ctx context.Context, rc *resource.Context) error

func (*InstanceResource) Validate

func (r *InstanceResource) Validate() error

type InstanceResources

type InstanceResources struct {
	Instance  *InstanceResource
	Resources []*resource.ResourceData
}

func NewInstanceResources

func NewInstanceResources(instance *InstanceResource, resources []resource.Resource) (*InstanceResources, error)

func (*InstanceResources) DatabaseID

func (r *InstanceResources) DatabaseID() string

func (*InstanceResources) DatabaseName

func (r *InstanceResources) DatabaseName() string

func (*InstanceResources) HostID

func (r *InstanceResources) HostID() string

func (*InstanceResources) InstanceID

func (r *InstanceResources) InstanceID() string

func (*InstanceResources) NodeName

func (r *InstanceResources) NodeName() string

func (*InstanceResources) State

func (r *InstanceResources) State() (*resource.State, error)

type InstanceSpec

type InstanceSpec struct {
	InstanceID       string              `json:"instance_id"`
	TenantID         *string             `json:"tenant_id,omitempty"`
	DatabaseID       string              `json:"database_id"`
	HostID           string              `json:"host_id"`
	DatabaseName     string              `json:"database_name"`
	NodeName         string              `json:"node_name"`
	NodeOrdinal      int                 `json:"node_ordinal"`
	PgEdgeVersion    *host.PgEdgeVersion `json:"pg_edge_version"`
	Port             *int                `json:"port"`
	PatroniPort      *int                `json:"patroni_port"`
	CPUs             float64             `json:"cpus"`
	MemoryBytes      uint64              `json:"memory"`
	DatabaseUsers    []*User             `json:"database_users"`
	BackupConfig     *BackupConfig       `json:"backup_config"`
	RestoreConfig    *RestoreConfig      `json:"restore_config"`
	PostgreSQLConf   map[string]any      `json:"postgresql_conf"`
	ClusterSize      int                 `json:"cluster_size"`
	OrchestratorOpts *OrchestratorOpts   `json:"orchestrator_opts,omitempty"`
	InPlaceRestore   bool                `json:"in_place_restore,omitempty"`
}

func (*InstanceSpec) Clone

func (s *InstanceSpec) Clone() *InstanceSpec

func (*InstanceSpec) CopySettingsFrom added in v0.7.0

func (s *InstanceSpec) CopySettingsFrom(current *InstanceSpec)

type InstanceSpecChange added in v0.5.1

type InstanceSpecChange struct {
	Previous *InstanceSpec
	Current  *InstanceSpec
}

type InstanceSpecStore added in v0.7.0

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

func NewInstanceSpecStore added in v0.7.0

func NewInstanceSpecStore(client *clientv3.Client, root string) *InstanceSpecStore

func (*InstanceSpecStore) DatabasePrefix added in v0.7.0

func (s *InstanceSpecStore) DatabasePrefix(databaseID string) string

func (*InstanceSpecStore) DeleteByDatabaseID added in v0.7.0

func (s *InstanceSpecStore) DeleteByDatabaseID(databaseID string) storage.DeleteOp

func (*InstanceSpecStore) DeleteByKey added in v0.7.0

func (s *InstanceSpecStore) DeleteByKey(databaseID, instanceID string) storage.DeleteOp

func (*InstanceSpecStore) GetAll added in v0.7.0

func (*InstanceSpecStore) GetByDatabaseID added in v0.7.0

func (s *InstanceSpecStore) GetByDatabaseID(databaseID string) storage.GetMultipleOp[*StoredInstanceSpec]

func (*InstanceSpecStore) GetByKey added in v0.7.0

func (s *InstanceSpecStore) GetByKey(databaseID, instanceID string) storage.GetOp[*StoredInstanceSpec]

func (*InstanceSpecStore) Key added in v0.7.0

func (s *InstanceSpecStore) Key(databaseID, instanceID string) string

func (*InstanceSpecStore) Prefix added in v0.7.0

func (s *InstanceSpecStore) Prefix() string

func (*InstanceSpecStore) Update added in v0.7.0

type InstanceState

type InstanceState string
const (
	InstanceStateCreating  InstanceState = "creating"
	InstanceStateModifying InstanceState = "modifying"
	InstanceStateDeleting  InstanceState = "deleting"
	InstanceStateBackingUp InstanceState = "backing_up"
	InstanceStateAvailable InstanceState = "available"
	InstanceStateDegraded  InstanceState = "degraded"
	InstanceStateFailed    InstanceState = "failed"
	InstanceStateStopped   InstanceState = "stopped"
	InstanceStateUnknown   InstanceState = "unknown"
)

func (InstanceState) IsInProgress added in v0.7.0

func (i InstanceState) IsInProgress() bool

type InstanceStatus

type InstanceStatus struct {
	PostgresVersion *string               `json:"postgres_version,omitempty"`
	SpockVersion    *string               `json:"spock_version,omitempty"`
	Addresses       []string              `json:"addresses,omitempty"`
	Port            *int                  `json:"port,omitempty"`
	PatroniState    *patroni.State        `json:"patroni_state,omitempty"`
	Role            *patroni.InstanceRole `json:"role,omitempty"`
	ReadOnly        *string               `json:"read_only,omitempty"`
	PendingRestart  *bool                 `json:"pending_restart,omitempty"`
	PatroniPaused   *bool                 `json:"patroni_paused,omitempty"`
	StatusUpdatedAt *time.Time            `json:"status_updated_at,omitempty"`
	Stopped         *bool                 `json:"stopped,omitempty"`
	Subscriptions   []SubscriptionStatus  `json:"subscriptions,omitempty"`
	Error           *string               `json:"error,omitempty"`
}

func (*InstanceStatus) IsPrimary

func (s *InstanceStatus) IsPrimary() bool

type InstanceStatusStore

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

func NewInstanceStatusStore

func NewInstanceStatusStore(client *clientv3.Client, root string) *InstanceStatusStore

func (*InstanceStatusStore) DatabasePrefix

func (s *InstanceStatusStore) DatabasePrefix(databaseID string) string

func (*InstanceStatusStore) DeleteByDatabaseID added in v0.7.0

func (s *InstanceStatusStore) DeleteByDatabaseID(databaseID string) storage.DeleteOp

func (*InstanceStatusStore) DeleteByKey

func (s *InstanceStatusStore) DeleteByKey(databaseID, instanceID string) storage.DeleteOp

func (*InstanceStatusStore) GetAll

func (*InstanceStatusStore) GetByDatabaseID

func (s *InstanceStatusStore) GetByDatabaseID(databaseID string) storage.GetMultipleOp[*StoredInstanceStatus]

func (*InstanceStatusStore) GetByKey

func (s *InstanceStatusStore) GetByKey(databaseID, instanceID string) storage.GetOp[*StoredInstanceStatus]

func (*InstanceStatusStore) Key

func (s *InstanceStatusStore) Key(databaseID, instanceID string) string

func (*InstanceStatusStore) Prefix

func (s *InstanceStatusStore) Prefix() string

func (*InstanceStatusStore) Put

type InstanceStore

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

func NewInstanceStore

func NewInstanceStore(client *clientv3.Client, root string) *InstanceStore

func (*InstanceStore) DatabasePrefix

func (s *InstanceStore) DatabasePrefix(databaseID string) string

func (*InstanceStore) DeleteByDatabaseID added in v0.7.0

func (s *InstanceStore) DeleteByDatabaseID(databaseID string) storage.DeleteOp

func (*InstanceStore) DeleteByKey

func (s *InstanceStore) DeleteByKey(databaseID, instanceID string) storage.DeleteOp

func (*InstanceStore) GetAll

func (*InstanceStore) GetByDatabaseID

func (s *InstanceStore) GetByDatabaseID(databaseID string) storage.GetMultipleOp[*StoredInstance]

func (*InstanceStore) GetByKey

func (s *InstanceStore) GetByKey(databaseID, instanceID string) storage.GetOp[*StoredInstance]

func (*InstanceStore) Key

func (s *InstanceStore) Key(databaseID, instanceID string) string

func (*InstanceStore) Prefix

func (s *InstanceStore) Prefix() string

func (*InstanceStore) Put

type InstanceUpdateOptions

type InstanceUpdateOptions struct {
	InstanceID string        `json:"instance_id"`
	DatabaseID string        `json:"database_id"`
	HostID     string        `json:"host_id"`
	NodeName   string        `json:"node_name"`
	State      InstanceState `json:"state"`
	Error      string        `json:"error,omitempty"`
	Now        time.Time     `json:"now"`
}

type LagTrackerCommitTimestampResource

type LagTrackerCommitTimestampResource struct {
	// Planner fields
	OriginNode   string `json:"origin_node"`
	ReceiverNode string `json:"receiver_node"`

	// Dependency wiring
	ExtraDependencies []resource.Identifier `json:"dependent_resources,omitempty"`

	// Output (filled at Refresh/Create time)
	CommitTimestamp *time.Time `json:"commit_timestamp,omitempty"`
}

func NewLagTrackerCommitTimestampResource

func NewLagTrackerCommitTimestampResource(originNode, receiverNode string) *LagTrackerCommitTimestampResource

func (*LagTrackerCommitTimestampResource) Create

func (*LagTrackerCommitTimestampResource) Delete

func (*LagTrackerCommitTimestampResource) Dependencies

func (*LagTrackerCommitTimestampResource) DiffIgnore

func (r *LagTrackerCommitTimestampResource) DiffIgnore() []string

func (*LagTrackerCommitTimestampResource) Executor

func (*LagTrackerCommitTimestampResource) Identifier

func (*LagTrackerCommitTimestampResource) Refresh

func (*LagTrackerCommitTimestampResource) ResourceVersion

func (r *LagTrackerCommitTimestampResource) ResourceVersion() string

func (*LagTrackerCommitTimestampResource) TypeDependencies added in v0.7.0

func (r *LagTrackerCommitTimestampResource) TypeDependencies() []resource.Type

func (*LagTrackerCommitTimestampResource) Update

type MCPServiceConfig added in v0.7.0

type MCPServiceConfig struct {
	// Optional - LLM proxy for web client (default: false)
	LLMEnabled *bool `json:"llm_enabled,omitempty"`

	// Required when llm_enabled is true
	LLMProvider     string  `json:"llm_provider"`
	LLMModel        string  `json:"llm_model"`
	AnthropicAPIKey *string `json:"anthropic_api_key,omitempty"`
	OpenAIAPIKey    *string `json:"openai_api_key,omitempty"`
	OllamaURL       *string `json:"ollama_url,omitempty"`

	// Optional - security
	AllowWrites *bool            `json:"allow_writes,omitempty"`
	InitToken   *string          `json:"init_token,omitempty"`
	InitUsers   []MCPServiceUser `json:"init_users,omitempty"`

	// Optional - embeddings
	EmbeddingProvider *string `json:"embedding_provider,omitempty"`
	EmbeddingModel    *string `json:"embedding_model,omitempty"`
	EmbeddingAPIKey   *string `json:"embedding_api_key,omitempty"`

	// Optional - LLM tuning (overridable defaults)
	LLMTemperature *float64 `json:"llm_temperature,omitempty"`
	LLMMaxTokens   *int     `json:"llm_max_tokens,omitempty"`

	// Optional - connection pool (overridable defaults)
	PoolMaxConns *int `json:"pool_max_conns,omitempty"`

	// Optional - tool toggles (all enabled by default)
	DisableQueryDatabase       *bool `json:"disable_query_database,omitempty"`
	DisableGetSchemaInfo       *bool `json:"disable_get_schema_info,omitempty"`
	DisableSimilaritySearch    *bool `json:"disable_similarity_search,omitempty"`
	DisableExecuteExplain      *bool `json:"disable_execute_explain,omitempty"`
	DisableGenerateEmbedding   *bool `json:"disable_generate_embedding,omitempty"`
	DisableSearchKnowledgebase *bool `json:"disable_search_knowledgebase,omitempty"`
	DisableCountRows           *bool `json:"disable_count_rows,omitempty"`
}

MCPServiceConfig is the typed internal representation of MCP service configuration. It is parsed from the ServiceSpec.Config map[string]any and validated.

func ParseMCPServiceConfig added in v0.7.0

func ParseMCPServiceConfig(config map[string]any, isUpdate bool) (*MCPServiceConfig, []error)

ParseMCPServiceConfig parses and validates a config map into a typed MCPServiceConfig. If isUpdate is true, bootstrap-only fields (init_token, init_users) are rejected.

type MCPServiceUser added in v0.7.0

type MCPServiceUser struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

MCPServiceUser represents a bootstrap user account for the MCP service.

type Node

type Node struct {
	Name             string            `json:"name"`
	HostIDs          []string          `json:"host_ids"`
	PostgresVersion  string            `json:"postgres_version"`
	Port             *int              `json:"port"`
	PatroniPort      *int              `json:"patroni_port"`
	CPUs             float64           `json:"cpus"`
	MemoryBytes      uint64            `json:"memory"`
	PostgreSQLConf   map[string]any    `json:"postgresql_conf"`
	BackupConfig     *BackupConfig     `json:"backup_config"`
	RestoreConfig    *RestoreConfig    `json:"restore_config"`
	OrchestratorOpts *OrchestratorOpts `json:"orchestrator_opts,omitempty"`
	SourceNode       string            `json:"source_node,omitempty"`
}

func (*Node) Clone

func (n *Node) Clone() *Node

func (*Node) DefaultOptionalFieldsFrom

func (n *Node) DefaultOptionalFieldsFrom(other *Node)

DefaultOptionalFieldsFrom will default this node's optional fields to the values from the given node.

type NodeInstances

type NodeInstances struct {
	NodeName      string          `json:"node_name"`
	SourceNode    string          `json:"source_node"`
	Instances     []*InstanceSpec `json:"instances"`
	RestoreConfig *RestoreConfig  `json:"restore_config"`
}

func (*NodeInstances) InstanceIDs

func (n *NodeInstances) InstanceIDs() []string

type NodeResource

type NodeResource struct {
	Name              string   `json:"name"`
	InstanceIDs       []string `json:"instance_ids"`
	PrimaryInstanceID string   `json:"primary_instance_id"`
}

func (*NodeResource) Create

func (n *NodeResource) Create(ctx context.Context, rc *resource.Context) error

func (*NodeResource) Delete

func (n *NodeResource) Delete(ctx context.Context, rc *resource.Context) error

func (*NodeResource) Dependencies

func (n *NodeResource) Dependencies() []resource.Identifier

func (*NodeResource) DiffIgnore

func (n *NodeResource) DiffIgnore() []string

func (*NodeResource) Executor

func (n *NodeResource) Executor() resource.Executor

func (*NodeResource) Identifier

func (n *NodeResource) Identifier() resource.Identifier

func (*NodeResource) Refresh

func (n *NodeResource) Refresh(ctx context.Context, rc *resource.Context) error

func (*NodeResource) ResourceVersion

func (n *NodeResource) ResourceVersion() string

func (*NodeResource) TypeDependencies added in v0.7.0

func (n *NodeResource) TypeDependencies() []resource.Type

func (*NodeResource) Update

func (n *NodeResource) Update(ctx context.Context, rc *resource.Context) error

type Orchestrator

type Orchestrator interface {
	GenerateInstanceResources(spec *InstanceSpec) (*InstanceResources, error)
	GenerateInstanceRestoreResources(spec *InstanceSpec, taskID uuid.UUID) (*InstanceResources, error)
	GenerateServiceInstanceResources(spec *ServiceInstanceSpec) (*ServiceInstanceResources, error)
	GetInstanceConnectionInfo(ctx context.Context, databaseID, instanceID string) (*ConnectionInfo, error)
	GetServiceInstanceStatus(ctx context.Context, serviceInstanceID string) (*ServiceInstanceStatus, error)
	CreatePgBackRestBackup(ctx context.Context, w io.Writer, instanceID string, options *pgbackrest.BackupOptions) error
	ValidateInstanceSpecs(ctx context.Context, changes []*InstanceSpecChange) ([]*ValidationResult, error)
	StopInstance(ctx context.Context, instanceID string) error
	StartInstance(ctx context.Context, instanceID string) error
}

type OrchestratorOpts

type OrchestratorOpts struct {
	Swarm *SwarmOpts `json:"docker,omitempty"`
}

func (*OrchestratorOpts) Clone

func (o *OrchestratorOpts) Clone() *OrchestratorOpts

type PortMapping added in v0.7.0

type PortMapping struct {
	Name          string `json:"name"`
	ContainerPort int    `json:"container_port"`
	HostPort      *int   `json:"host_port,omitempty"`
}

type PostgRESTServiceConfig added in v0.7.0

type PostgRESTServiceConfig struct {
	DBSchemas                string  `json:"db_schemas"`   // default: "public"
	DBAnonRole               string  `json:"db_anon_role"` // default: "pgedge_application_read_only"
	DBPool                   int     `json:"db_pool"`      // default: 10, range: 1-30
	MaxRows                  int     `json:"max_rows"`     // default: 1000, range: 1-10000
	JWTSecret                *string `json:"jwt_secret,omitempty"`
	JWTAud                   *string `json:"jwt_aud,omitempty"`
	JWTRoleClaimKey          *string `json:"jwt_role_claim_key,omitempty"`
	ServerCORSAllowedOrigins *string `json:"server_cors_allowed_origins,omitempty"`
}

PostgRESTServiceConfig is the typed internal representation of PostgREST service configuration. Parsed from ServiceSpec.Config map[string]any. All fields are optional; defaults are applied when absent.

func ParsePostgRESTServiceConfig added in v0.7.0

func ParsePostgRESTServiceConfig(config map[string]any) (*PostgRESTServiceConfig, []error)

ParsePostgRESTServiceConfig parses and validates a config map into a typed PostgRESTServiceConfig. All fields are optional with sensible defaults.

type ReplicationSlotAdvanceFromCTSResource

type ReplicationSlotAdvanceFromCTSResource struct {
	ProviderNode   string `json:"provider_node"`   // slot lives here
	SubscriberNode string `json:"subscriber_node"` // target/receiver node
}

ReplicationSlotAdvanceFromCTSResource advances the replication slot on the provider to the LSN derived from the commit timestamp captured in lag_tracker.

func (*ReplicationSlotAdvanceFromCTSResource) Create

func (*ReplicationSlotAdvanceFromCTSResource) Delete

func (*ReplicationSlotAdvanceFromCTSResource) Dependencies

func (*ReplicationSlotAdvanceFromCTSResource) DiffIgnore

No diff-ignore fields needed; this always executes idempotently when asked.

func (*ReplicationSlotAdvanceFromCTSResource) Executor

Execute on the provider node (the slot exists there).

func (*ReplicationSlotAdvanceFromCTSResource) Identifier

func (*ReplicationSlotAdvanceFromCTSResource) Refresh

func (*ReplicationSlotAdvanceFromCTSResource) ResourceVersion

func (r *ReplicationSlotAdvanceFromCTSResource) ResourceVersion() string

func (*ReplicationSlotAdvanceFromCTSResource) TypeDependencies added in v0.7.0

func (r *ReplicationSlotAdvanceFromCTSResource) TypeDependencies() []resource.Type

func (*ReplicationSlotAdvanceFromCTSResource) Update

type ReplicationSlotCreateResource

type ReplicationSlotCreateResource struct {
	DatabaseName   string `json:"database_name"`
	ProviderNode   string `json:"provider_node"`
	SubscriberNode string `json:"subscriber_node"`
}

func (*ReplicationSlotCreateResource) Create

func (*ReplicationSlotCreateResource) Delete

func (*ReplicationSlotCreateResource) Dependencies

func (*ReplicationSlotCreateResource) DiffIgnore

func (r *ReplicationSlotCreateResource) DiffIgnore() []string

func (*ReplicationSlotCreateResource) Executor

func (*ReplicationSlotCreateResource) Identifier

func (*ReplicationSlotCreateResource) Refresh

func (*ReplicationSlotCreateResource) ResourceVersion

func (r *ReplicationSlotCreateResource) ResourceVersion() string

func (*ReplicationSlotCreateResource) TypeDependencies added in v0.7.0

func (r *ReplicationSlotCreateResource) TypeDependencies() []resource.Type

func (*ReplicationSlotCreateResource) Update

type ReplicationSlotResource added in v0.7.0

type ReplicationSlotResource struct {
	ProviderNode   string `json:"provider_node"`
	SubscriberNode string `json:"subscriber_node"`
}

ReplicationSlotResource represents the replication slot on a provider node that serves a subscription from a subscriber node. It only implements the Delete lifecycle method: when a subscription is removed, this resource ensures the corresponding replication slot is dropped on the provider, preventing orphaned slots from accumulating WAL.

func (*ReplicationSlotResource) Create added in v0.7.0

func (*ReplicationSlotResource) Delete added in v0.7.0

func (*ReplicationSlotResource) Dependencies added in v0.7.0

func (r *ReplicationSlotResource) Dependencies() []resource.Identifier

func (*ReplicationSlotResource) DiffIgnore added in v0.7.0

func (r *ReplicationSlotResource) DiffIgnore() []string

func (*ReplicationSlotResource) Executor added in v0.7.0

func (*ReplicationSlotResource) Identifier added in v0.7.0

func (*ReplicationSlotResource) Refresh added in v0.7.0

func (*ReplicationSlotResource) ResourceVersion added in v0.7.0

func (r *ReplicationSlotResource) ResourceVersion() string

func (*ReplicationSlotResource) TypeDependencies added in v0.7.0

func (r *ReplicationSlotResource) TypeDependencies() []resource.Type

func (*ReplicationSlotResource) Update added in v0.7.0

type RestoreConfig

type RestoreConfig struct {
	SourceDatabaseID   string                 `json:"source_database_id"`
	SourceNodeName     string                 `json:"source_node_name"`
	SourceDatabaseName string                 `json:"source_database_name"`
	Repository         *pgbackrest.Repository `json:"repository"`
	RestoreOptions     map[string]string      `json:"restore_options"`
}

func (*RestoreConfig) Clone

func (r *RestoreConfig) Clone() *RestoreConfig

func (*RestoreConfig) DefaultOptionalFieldsFrom

func (r *RestoreConfig) DefaultOptionalFieldsFrom(other *RestoreConfig)

DefaultOptionalFieldsFrom will default this config's optional fields to the values from the given config.

type Service

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

func NewService

func NewService(
	cfg config.Config,
	orchestrator Orchestrator,
	store *Store,
	hostSvc *host.Service,
	portsSvc *ports.Service,
) *Service

func (*Service) CreateDatabase

func (s *Service) CreateDatabase(ctx context.Context, spec *Spec) (*Database, error)

func (*Service) DeleteDatabase

func (s *Service) DeleteDatabase(ctx context.Context, databaseID string) error

func (*Service) DeleteInstance

func (s *Service) DeleteInstance(ctx context.Context, databaseID, instanceID string) error

func (*Service) DeleteInstanceSpec added in v0.7.0

func (s *Service) DeleteInstanceSpec(ctx context.Context, databaseID, instanceID string) error

func (*Service) DeleteServiceInstance added in v0.7.0

func (s *Service) DeleteServiceInstance(ctx context.Context, databaseID, serviceInstanceID string) error

func (*Service) GetAllInstances

func (s *Service) GetAllInstances(ctx context.Context) ([]*Instance, error)

func (*Service) GetAllServiceInstances added in v0.7.0

func (s *Service) GetAllServiceInstances(ctx context.Context) ([]*ServiceInstance, error)

func (*Service) GetDatabase

func (s *Service) GetDatabase(ctx context.Context, databaseID string) (*Database, error)

func (*Service) GetDatabases

func (s *Service) GetDatabases(ctx context.Context) ([]*Database, error)

func (*Service) GetDatabasesByHostId added in v0.6.0

func (s *Service) GetDatabasesByHostId(ctx context.Context, hostID string) ([]*Database, error)

func (*Service) GetInstance

func (s *Service) GetInstance(ctx context.Context, databaseID, instanceID string) (*Instance, error)

func (*Service) GetInstanceConnectionInfo added in v0.7.0

func (s *Service) GetInstanceConnectionInfo(ctx context.Context, databaseID, instanceID string) (*ConnectionInfo, error)

func (*Service) GetInstances

func (s *Service) GetInstances(ctx context.Context, databaseID string) ([]*Instance, error)

func (*Service) GetServiceInstance added in v0.7.0

func (s *Service) GetServiceInstance(ctx context.Context, databaseID, serviceInstanceID string) (*ServiceInstance, error)

func (*Service) GetServiceInstances added in v0.7.0

func (s *Service) GetServiceInstances(ctx context.Context, databaseID string) ([]*ServiceInstance, error)

func (*Service) GetStoredInstanceState

func (s *Service) GetStoredInstanceState(ctx context.Context, databaseID, instanceID string) (InstanceState, error)

func (*Service) InstanceCountForHost

func (s *Service) InstanceCountForHost(ctx context.Context, hostID string) (int, error)

func (*Service) PopulateSpecDefaults

func (s *Service) PopulateSpecDefaults(ctx context.Context, spec *Spec) error

func (*Service) ReconcileInstanceSpec added in v0.7.0

func (s *Service) ReconcileInstanceSpec(ctx context.Context, spec *InstanceSpec) (*InstanceSpec, error)

func (*Service) SetServiceInstanceState added in v0.7.0

func (s *Service) SetServiceInstanceState(
	ctx context.Context,
	databaseID, serviceInstanceID string,
	state ServiceInstanceState,
) error

SetServiceInstanceState performs a targeted state update using a direct key lookup instead of scanning all service instances.

func (*Service) UpdateDatabase

func (s *Service) UpdateDatabase(ctx context.Context, state DatabaseState, spec *Spec) (*Database, error)

func (*Service) UpdateDatabaseState

func (s *Service) UpdateDatabaseState(ctx context.Context, databaseID string, from, to DatabaseState) error

func (*Service) UpdateInstance

func (s *Service) UpdateInstance(ctx context.Context, opts *InstanceUpdateOptions) error

func (*Service) UpdateInstanceStatus

func (s *Service) UpdateInstanceStatus(
	ctx context.Context,
	databaseID string,
	instanceID string,
	status *InstanceStatus,
) error

func (*Service) UpdateServiceInstance added in v0.7.0

func (s *Service) UpdateServiceInstance(ctx context.Context, opts *ServiceInstanceUpdateOptions) error

func (*Service) UpdateServiceInstanceState added in v0.7.0

func (s *Service) UpdateServiceInstanceState(
	ctx context.Context,
	serviceInstanceID string,
	update *ServiceInstanceStateUpdate,
) error

func (*Service) UpdateServiceInstanceStatus added in v0.7.0

func (s *Service) UpdateServiceInstanceStatus(
	ctx context.Context,
	databaseID string,
	serviceInstanceID string,
	status *ServiceInstanceStatus,
) error

type ServiceConnectionInfo added in v0.7.0

type ServiceConnectionInfo struct {
	Hosts              []ServiceHostEntry
	TargetSessionAttrs string
}

ServiceConnectionInfo holds the ordered host list and connection parameters for a service instance's database connection.

func BuildServiceHostList added in v0.7.0

func BuildServiceHostList(params *BuildServiceHostListParams) (*ServiceConnectionInfo, error)

BuildServiceHostList produces an ordered list of database host:port entries for a service instance's connection string. The ordering is determined by co-location with the service host and optional node filtering.

Algorithm:

  1. Determine node list and ordering: - If TargetNodes is set: use only listed nodes in that order, ignoring co-location - If TargetNodes is not set: all nodes, with the local node (containing a co-located instance) first, then remaining nodes in iteration order
  2. Build host list, grouped by node: - For each node group: co-located instance first (same host as service), then remaining - Hostname format: "postgres-{instanceID}" (swarm overlay convention) - Port: always 5432 (internal container port via overlay network)
  3. Pass through TargetSessionAttrs unchanged.

Invariant: Only database instances from NodeInstances generate entries. ServiceHostID affects ordering only, never membership. A service on a dedicated host (no database instance on that host) does not add the service host to the list.

type ServiceHostEntry added in v0.7.0

type ServiceHostEntry struct {
	Host string
	Port int
}

ServiceHostEntry represents a single host:port pair in an ordered host list.

type ServiceInstance added in v0.7.0

type ServiceInstance struct {
	ServiceInstanceID string                 `json:"service_instance_id"`
	ServiceID         string                 `json:"service_id"`
	DatabaseID        string                 `json:"database_id"`
	HostID            string                 `json:"host_id"`
	State             ServiceInstanceState   `json:"state"`
	Status            *ServiceInstanceStatus `json:"status,omitempty"`
	// Credentials is only populated during provisioning workflows. It is not
	// persisted to etcd and will be nil when read from the store.
	Credentials *ServiceUser `json:"credentials,omitempty"`
	CreatedAt   time.Time    `json:"created_at"`
	UpdatedAt   time.Time    `json:"updated_at"`
	Error       string       `json:"error,omitempty"`
}

type ServiceInstanceResources added in v0.7.0

type ServiceInstanceResources struct {
	ServiceInstance *ServiceInstance
	Resources       []*resource.ResourceData
}

type ServiceInstanceSpec added in v0.7.0

type ServiceInstanceSpec struct {
	ServiceInstanceID  string
	ServiceSpec        *ServiceSpec
	PgEdgeVersion      *host.PgEdgeVersion // Database version, used for compatibility validation
	DatabaseID         string
	DatabaseName       string
	HostID             string
	CohortMemberID     string
	Credentials        *ServiceUser
	DatabaseNetworkID  string
	NodeName           string             // Database node name (for ServiceUserRole PrimaryExecutor routing)
	DatabaseHosts      []ServiceHostEntry // Ordered list of Postgres host:port entries
	TargetSessionAttrs string             // libpq target_session_attrs value
	Port               *int               // Service instance published port (optional, 0 = random)
	DatabaseNodes      []*NodeInstances   // All database nodes; used to create per-node ServiceUserRole resources
}

ServiceInstanceSpec contains the specification for generating service instance resources.

type ServiceInstanceState added in v0.7.0

type ServiceInstanceState string
const (
	ServiceInstanceStateCreating ServiceInstanceState = "creating"
	ServiceInstanceStateRunning  ServiceInstanceState = "running"
	ServiceInstanceStateFailed   ServiceInstanceState = "failed"
	ServiceInstanceStateDeleting ServiceInstanceState = "deleting"
)

type ServiceInstanceStateUpdate added in v0.7.0

type ServiceInstanceStateUpdate struct {
	DatabaseID string                 `json:"database_id,omitempty"`
	State      ServiceInstanceState   `json:"state"`
	Status     *ServiceInstanceStatus `json:"status,omitempty"`
	Error      string                 `json:"error,omitempty"`
}

type ServiceInstanceStatus added in v0.7.0

type ServiceInstanceStatus struct {
	ContainerID  *string            `json:"container_id,omitempty"`
	ImageVersion *string            `json:"image_version,omitempty"`
	Addresses    []string           `json:"addresses,omitempty"`
	Ports        []PortMapping      `json:"ports,omitempty"`
	HealthCheck  *HealthCheckResult `json:"health_check,omitempty"`
	LastHealthAt *time.Time         `json:"last_health_at,omitempty"`
	ServiceReady *bool              `json:"service_ready,omitempty"`
}

type ServiceInstanceStatusStore added in v0.7.0

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

func NewServiceInstanceStatusStore added in v0.7.0

func NewServiceInstanceStatusStore(client *clientv3.Client, root string) *ServiceInstanceStatusStore

func (*ServiceInstanceStatusStore) DatabasePrefix added in v0.7.0

func (s *ServiceInstanceStatusStore) DatabasePrefix(databaseID string) string

func (*ServiceInstanceStatusStore) DeleteByKey added in v0.7.0

func (s *ServiceInstanceStatusStore) DeleteByKey(databaseID, serviceInstanceID string) storage.DeleteOp

func (*ServiceInstanceStatusStore) GetAll added in v0.7.0

func (*ServiceInstanceStatusStore) GetByDatabaseID added in v0.7.0

func (*ServiceInstanceStatusStore) GetByKey added in v0.7.0

func (s *ServiceInstanceStatusStore) GetByKey(databaseID, serviceInstanceID string) storage.GetOp[*StoredServiceInstanceStatus]

func (*ServiceInstanceStatusStore) Key added in v0.7.0

func (s *ServiceInstanceStatusStore) Key(databaseID, serviceInstanceID string) string

func (*ServiceInstanceStatusStore) Prefix added in v0.7.0

func (s *ServiceInstanceStatusStore) Prefix() string

func (*ServiceInstanceStatusStore) Put added in v0.7.0

type ServiceInstanceStore added in v0.7.0

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

func NewServiceInstanceStore added in v0.7.0

func NewServiceInstanceStore(client *clientv3.Client, root string) *ServiceInstanceStore

func (*ServiceInstanceStore) DatabasePrefix added in v0.7.0

func (s *ServiceInstanceStore) DatabasePrefix(databaseID string) string

func (*ServiceInstanceStore) DeleteByKey added in v0.7.0

func (s *ServiceInstanceStore) DeleteByKey(databaseID, serviceInstanceID string) storage.DeleteOp

func (*ServiceInstanceStore) GetAll added in v0.7.0

func (*ServiceInstanceStore) GetByDatabaseID added in v0.7.0

func (s *ServiceInstanceStore) GetByDatabaseID(databaseID string) storage.GetMultipleOp[*StoredServiceInstance]

func (*ServiceInstanceStore) GetByKey added in v0.7.0

func (s *ServiceInstanceStore) GetByKey(databaseID, serviceInstanceID string) storage.GetOp[*StoredServiceInstance]

func (*ServiceInstanceStore) Key added in v0.7.0

func (s *ServiceInstanceStore) Key(databaseID, serviceInstanceID string) string

func (*ServiceInstanceStore) Prefix added in v0.7.0

func (s *ServiceInstanceStore) Prefix() string

func (*ServiceInstanceStore) Put added in v0.7.0

type ServiceInstanceUpdateOptions added in v0.7.0

type ServiceInstanceUpdateOptions struct {
	ServiceInstanceID string               `json:"service_instance_id"`
	ServiceID         string               `json:"service_id"`
	DatabaseID        string               `json:"database_id"`
	HostID            string               `json:"host_id"`
	State             ServiceInstanceState `json:"state"`
	Error             string               `json:"error,omitempty"`
}

type ServiceSpec added in v0.7.0

type ServiceSpec struct {
	ServiceID          string              `json:"service_id"`
	ServiceType        string              `json:"service_type"`
	Version            string              `json:"version"`
	HostIDs            []string            `json:"host_ids"`
	Config             map[string]any      `json:"config"`
	Port               *int                `json:"port,omitempty"`
	CPUs               *float64            `json:"cpus,omitempty"`
	MemoryBytes        *uint64             `json:"memory,omitempty"`
	OrchestratorOpts   *OrchestratorOpts   `json:"orchestrator_opts,omitempty"`
	DatabaseConnection *DatabaseConnection `json:"database_connection,omitempty"`
}

func (*ServiceSpec) Clone added in v0.7.0

func (s *ServiceSpec) Clone() *ServiceSpec

type ServiceUser added in v0.7.0

type ServiceUser struct {
	Username string `json:"username"` // Format: "svc_{service_id}_{mode}"
	Password string `json:"password"` // 32-character cryptographically random string
	Role     string `json:"role"`     // Database role, e.g., "pgedge_application_read_only" or "pgedge_application"
}

ServiceUser represents database credentials for a service instance.

Each service instance receives two dedicated database users: one read-only (RO) and one read-write (RW). The active user is selected based on the service's allow_writes setting. This provides security isolation between service instances.

Credential Generation

Credentials are generated during service instance provisioning by the CreateServiceUser workflow activity. The username is deterministic (based on service instance ID and mode), while the password is cryptographically random.

Security Properties

- Unique per service instance (not shared between instances) - 32-character random passwords - Storage in etcd alongside service instance metadata - Injected into service containers via config.yaml

type Spec

type Spec struct {
	DatabaseID       string            `json:"database_id"`
	TenantID         *string           `json:"tenant_id,omitempty"`
	DatabaseName     string            `json:"database_name"`
	PostgresVersion  string            `json:"postgres_version"`
	SpockVersion     string            `json:"spock_version"`
	Port             *int              `json:"port"`
	PatroniPort      *int              `json:"patroni_port"`
	CPUs             float64           `json:"cpus"`
	MemoryBytes      uint64            `json:"memory"`
	Nodes            []*Node           `json:"nodes"`
	DatabaseUsers    []*User           `json:"database_users"`
	Services         []*ServiceSpec    `json:"services,omitempty"`
	BackupConfig     *BackupConfig     `json:"backup_config"`
	RestoreConfig    *RestoreConfig    `json:"restore_config"`
	PostgreSQLConf   map[string]any    `json:"postgresql_conf"`
	OrchestratorOpts *OrchestratorOpts `json:"orchestrator_opts,omitempty"`
}

func (*Spec) Clone

func (s *Spec) Clone() *Spec

func (*Spec) DefaultOptionalFieldsFrom

func (s *Spec) DefaultOptionalFieldsFrom(other *Spec)

DefaultOptionalFieldsFrom will default this spec's optional fields to the values from the given spec.

func (*Spec) Node

func (s *Spec) Node(name string) (*Node, error)

func (*Spec) NodeInstances

func (s *Spec) NodeInstances() ([]*NodeInstances, error)

func (*Spec) NodeNames

func (s *Spec) NodeNames() []string

func (*Spec) NormalizeBackupConfig

func (s *Spec) NormalizeBackupConfig()

NormalizeBackupConfig normalizes the backup config so that its defined per-node rather than at the database level. This is useful as a preliminary step if we need to modify the backup configs on the user's behalf.

func (*Spec) RemoveBackupConfigFrom

func (s *Spec) RemoveBackupConfigFrom(nodes ...string)

RemoveBackupConfigFrom removes backup configuration from the given nodes. It normalizes the backup configuration first to ensure that only the given nodes are affected.

func (*Spec) RemoveHost added in v0.6.0

func (s *Spec) RemoveHost(hostId string) (ok bool)

RemoveHost removes hostId from Spec.Nodes.HostIDs (if present). If this results in an empty Node, then the Node is removed from Spec.Nodes. Return true if hostId was found and removed, false otherwise.

func (*Spec) ValidateNodeNames

func (s *Spec) ValidateNodeNames(names ...string) error

type SpecStore

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

func NewSpecStore

func NewSpecStore(client *clientv3.Client, root string) *SpecStore

func (*SpecStore) Create

func (s *SpecStore) Create(item *StoredSpec) storage.PutOp[*StoredSpec]

func (*SpecStore) Delete

func (*SpecStore) ExistsByKey

func (s *SpecStore) ExistsByKey(databaseID string) storage.ExistsOp

func (*SpecStore) GetAll

func (s *SpecStore) GetAll() storage.GetMultipleOp[*StoredSpec]

func (*SpecStore) GetByKey

func (s *SpecStore) GetByKey(databaseID string) storage.GetOp[*StoredSpec]

func (*SpecStore) GetByKeys

func (s *SpecStore) GetByKeys(databaseIDs ...string) storage.GetMultipleOp[*StoredSpec]

func (*SpecStore) Key

func (s *SpecStore) Key(databaseID string) string

func (*SpecStore) Prefix

func (s *SpecStore) Prefix() string

func (*SpecStore) Update

func (s *SpecStore) Update(item *StoredSpec) storage.PutOp[*StoredSpec]

type Store

type Store struct {
	Spec                  *SpecStore
	Database              *DatabaseStore
	Instance              *InstanceStore
	InstanceStatus        *InstanceStatusStore
	InstanceSpec          *InstanceSpecStore
	ServiceInstance       *ServiceInstanceStore
	ServiceInstanceStatus *ServiceInstanceStatusStore
	// contains filtered or unexported fields
}

func NewStore

func NewStore(client *clientv3.Client, root string) *Store

func (*Store) Txn

func (s *Store) Txn(ops ...storage.TxnOperation) storage.Txn

type StoredDatabase

type StoredDatabase struct {
	storage.StoredValue
	DatabaseID string        `json:"database_id"`
	TenantID   *string       `json:"tenant_id,omitempty"`
	CreatedAt  time.Time     `json:"created_at"`
	UpdatedAt  time.Time     `json:"updated_at"`
	State      DatabaseState `json:"state"`
}

type StoredInstance

type StoredInstance struct {
	storage.StoredValue
	InstanceID string        `json:"instance_id"`
	DatabaseID string        `json:"database_id"`
	HostID     string        `json:"host_id"`
	NodeName   string        `json:"node_name"`
	State      InstanceState `json:"state"`
	CreatedAt  time.Time     `json:"created_at"`
	UpdateAt   time.Time     `json:"updated_at"`
	Error      string        `json:"error,omitempty"`
}

func NewStoredInstance

func NewStoredInstance(opts *InstanceUpdateOptions) *StoredInstance

func (*StoredInstance) Update

func (i *StoredInstance) Update(opts *InstanceUpdateOptions)

type StoredInstanceSpec added in v0.7.0

type StoredInstanceSpec struct {
	storage.StoredValue
	Spec *InstanceSpec `json:"spec"`
}

type StoredInstanceStatus

type StoredInstanceStatus struct {
	storage.StoredValue
	DatabaseID string          `json:"database_id"`
	InstanceID string          `json:"instance_id"`
	Status     *InstanceStatus `json:"status"`
}

type StoredServiceInstance added in v0.7.0

type StoredServiceInstance struct {
	storage.StoredValue
	ServiceInstanceID string               `json:"service_instance_id"`
	ServiceID         string               `json:"service_id"`
	DatabaseID        string               `json:"database_id"`
	HostID            string               `json:"host_id"`
	State             ServiceInstanceState `json:"state"`
	CreatedAt         time.Time            `json:"created_at"`
	UpdatedAt         time.Time            `json:"updated_at"`
	Error             string               `json:"error,omitempty"`
}

func NewStoredServiceInstance added in v0.7.0

func NewStoredServiceInstance(opts *ServiceInstanceUpdateOptions) *StoredServiceInstance

func (*StoredServiceInstance) Update added in v0.7.0

type StoredServiceInstanceStatus added in v0.7.0

type StoredServiceInstanceStatus struct {
	storage.StoredValue
	DatabaseID        string                 `json:"database_id"`
	ServiceInstanceID string                 `json:"service_instance_id"`
	Status            *ServiceInstanceStatus `json:"status"`
}

type StoredSpec

type StoredSpec struct {
	storage.StoredValue
	*Spec
}

type SubscriptionResource

type SubscriptionResource struct {
	SubscriberNode    string                `json:"subscriber_node"`
	ProviderNode      string                `json:"provider_node"`
	Disabled          bool                  `json:"disabled"`
	SyncStructure     bool                  `json:"sync_structure"`
	SyncData          bool                  `json:"sync_data"`
	ExtraDependencies []resource.Identifier `json:"dependent_subscriptions"`
	NeedsUpdate       bool                  `json:"needs_update"`
}

func (*SubscriptionResource) AddDependentResource

func (s *SubscriptionResource) AddDependentResource(dep resource.Identifier)

func (*SubscriptionResource) Create

func (*SubscriptionResource) Delete

func (*SubscriptionResource) Dependencies

func (s *SubscriptionResource) Dependencies() []resource.Identifier

func (*SubscriptionResource) DiffIgnore

func (s *SubscriptionResource) DiffIgnore() []string

func (*SubscriptionResource) Executor

func (s *SubscriptionResource) Executor() resource.Executor

func (*SubscriptionResource) Identifier

func (s *SubscriptionResource) Identifier() resource.Identifier

func (*SubscriptionResource) Refresh

func (*SubscriptionResource) ResourceVersion

func (s *SubscriptionResource) ResourceVersion() string

func (*SubscriptionResource) TypeDependencies added in v0.7.0

func (s *SubscriptionResource) TypeDependencies() []resource.Type

func (*SubscriptionResource) Update

type SubscriptionStatus

type SubscriptionStatus struct {
	ProviderNode string `json:"provider_node"`
	Name         string `json:"name"`
	Status       string `json:"status"`
}

type SwarmOpts

type SwarmOpts struct {
	ExtraVolumes  []ExtraVolumesSpec `json:"extra_volumes,omitempty"`
	ExtraNetworks []ExtraNetworkSpec `json:"extra_networks,omitempty"`
	ExtraLabels   map[string]string  `json:"extra_labels,omitempty"` // optional, used for custom labels on the swarm service
}

func (*SwarmOpts) Clone

func (d *SwarmOpts) Clone() *SwarmOpts

type SwitchoverResource

type SwitchoverResource struct {
	HostID     string               `json:"host_id"`
	InstanceID string               `json:"instance_id"`
	TargetRole patroni.InstanceRole `json:"target_role"`
}

func (*SwitchoverResource) Create

func (*SwitchoverResource) Delete

func (*SwitchoverResource) Dependencies

func (s *SwitchoverResource) Dependencies() []resource.Identifier

func (*SwitchoverResource) DiffIgnore

func (s *SwitchoverResource) DiffIgnore() []string

func (*SwitchoverResource) Executor

func (s *SwitchoverResource) Executor() resource.Executor

func (*SwitchoverResource) Identifier

func (s *SwitchoverResource) Identifier() resource.Identifier

func (*SwitchoverResource) Refresh

func (s *SwitchoverResource) Refresh(ctx context.Context, rc *resource.Context) error

func (*SwitchoverResource) ResourceVersion

func (s *SwitchoverResource) ResourceVersion() string

func (*SwitchoverResource) TypeDependencies added in v0.7.0

func (s *SwitchoverResource) TypeDependencies() []resource.Type

func (*SwitchoverResource) Update

type SyncEventResource

type SyncEventResource struct {
	ProviderNode      string                `json:"provider_node"`
	SubscriberNode    string                `json:"subscriber_node"`
	SyncEventLsn      string                `json:"sync_event_lsn"`
	ExtraDependencies []resource.Identifier `json:"extra_dependencies"`
}

func (*SyncEventResource) Create

func (r *SyncEventResource) Create(ctx context.Context, rc *resource.Context) error

func (*SyncEventResource) Delete

func (r *SyncEventResource) Delete(ctx context.Context, rc *resource.Context) error

func (*SyncEventResource) Dependencies

func (r *SyncEventResource) Dependencies() []resource.Identifier

func (*SyncEventResource) DiffIgnore

func (r *SyncEventResource) DiffIgnore() []string

func (*SyncEventResource) Executor

func (r *SyncEventResource) Executor() resource.Executor

func (*SyncEventResource) Identifier

func (r *SyncEventResource) Identifier() resource.Identifier

func (*SyncEventResource) Refresh

func (r *SyncEventResource) Refresh(ctx context.Context, rc *resource.Context) error

Confirm synchronization by sending sync_event from provider and waiting for it on subscriber

func (*SyncEventResource) ResourceVersion

func (r *SyncEventResource) ResourceVersion() string

func (*SyncEventResource) TypeDependencies added in v0.7.0

func (r *SyncEventResource) TypeDependencies() []resource.Type

func (*SyncEventResource) Update

func (r *SyncEventResource) Update(ctx context.Context, rc *resource.Context) error

type User

type User struct {
	Username   string   `json:"username"`
	Password   string   `json:"password"`
	DBOwner    bool     `json:"db_owner,omitempty"`
	Attributes []string `json:"attributes,omitempty"`
	Roles      []string `json:"roles,omitempty"`
}

func (*User) Clone

func (u *User) Clone() *User

func (*User) DefaultOptionalFieldsFrom

func (u *User) DefaultOptionalFieldsFrom(other *User)

DefaultOptionalFieldsFrom will default this user's optional fields to the values from the given user.

type ValidationResult

type ValidationResult struct {
	InstanceID string   `json:"instance_id"`
	HostID     string   `json:"host_id"`
	NodeName   string   `json:"node_name"`
	Valid      bool     `json:"valid"`
	Errors     []string `json:"errors"`
}

type WaitForSyncEventResource

type WaitForSyncEventResource struct {
	SubscriberNode string `json:"subscriber_node"`
	ProviderNode   string `json:"provider_node"`
}

func (*WaitForSyncEventResource) Create

func (*WaitForSyncEventResource) Delete

func (*WaitForSyncEventResource) Dependencies

func (r *WaitForSyncEventResource) Dependencies() []resource.Identifier

func (*WaitForSyncEventResource) DiffIgnore

func (r *WaitForSyncEventResource) DiffIgnore() []string

func (*WaitForSyncEventResource) Executor

func (*WaitForSyncEventResource) Identifier

func (*WaitForSyncEventResource) Refresh

Confirm synchronization by sending sync_event from provider and waiting for it on subscriber

func (*WaitForSyncEventResource) ResourceVersion

func (r *WaitForSyncEventResource) ResourceVersion() string

func (*WaitForSyncEventResource) TypeDependencies added in v0.7.0

func (r *WaitForSyncEventResource) TypeDependencies() []resource.Type

func (*WaitForSyncEventResource) Update

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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