diff --git a/CLAUDE.md b/CLAUDE.md index dc5cfe62..ddf02f1c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -198,6 +198,7 @@ API lifecycle: Key workflows in `server/internal/workflows/`: - **UpdateDatabase**: Creates/updates database (handles node additions, configuration updates) +- **MajorVersionUpgrade**: Dedicated rolling upgrade of a database's Spock major version, one node at a time; independent of UpdateDatabase's patch/minor upgrade path - **DeleteDatabase**: Removes database and cleanup - **PgBackRestBackup**: Initiates backup operations - **PgBackRestRestore**: Performs in-place restores diff --git a/api/apiv1/design/api.go b/api/apiv1/design/api.go index b56d7254..aae7cb43 100644 --- a/api/apiv1/design/api.go +++ b/api/apiv1/design/api.go @@ -336,6 +336,33 @@ var _ = g.Service("control-plane", func() { }) }) + g.Method("apply-major-upgrade", func() { + g.Description("Applies a dedicated Spock major-version upgrade (e.g. 5.x to 6.x) to a database, rolling through each node one at a time rather than redeploying uniformly. Independent of apply-upgrade, which is restricted to same-major minor/patch bumps and cannot reach a different Spock major.") + g.Meta("openapi:summary", "Apply Spock major-version upgrade") + g.Payload(func() { + g.Attribute("database_id", Identifier, func() { + g.Description("ID of the database to upgrade.") + g.Example("my-app") + }) + g.Attribute("request", ApplyMajorUpgradeRequest) + + g.Required("database_id", "request") + }) + g.Result(ApplyMajorUpgradeResponse) + g.Error("cluster_not_initialized") + g.Error("database_not_modifiable") + g.Error("invalid_input") + g.Error("not_found") + g.Error("operation_already_in_progress") + + g.HTTP(func() { + g.POST("/v1/databases/{database_id}/upgrade-major") + g.Body("request") + + g.Meta("openapi:tag:Database") + }) + }) + g.Method("delete-database", func() { g.Description("Deletes a database from the cluster.") g.Meta("openapi:summary", "Delete database") diff --git a/api/apiv1/design/database.go b/api/apiv1/design/database.go index 52a237d7..56b31423 100644 --- a/api/apiv1/design/database.go +++ b/api/apiv1/design/database.go @@ -36,6 +36,12 @@ var DatabaseNodeSpec = g.Type("DatabaseNodeSpec", func() { g.Example("17.6") g.Meta("struct:tag:json", "postgres_version,omitempty") }) + g.Attribute("spock_version", g.String, func() { + g.Description("The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice.") + g.Pattern(spockVersionPattern) + g.Example("6") + g.Meta("struct:tag:json", "spock_version,omitempty") + }) g.Attribute("port", g.Int, func() { g.Description("The port used by the Postgres database for this node. Overrides the Postgres port set in the DatabaseSpec.") g.Minimum(0) @@ -1366,6 +1372,42 @@ var ApplyUpgradeResponse = g.Type("ApplyUpgradeResponse", func() { }) }) +var ApplyMajorUpgradeRequest = g.Type("ApplyMajorUpgradeRequest", func() { + g.Description("Request to upgrade a database across a Spock major version boundary (e.g. 5.x to 6.x). Deliberately separate from ApplyUpgradeRequest: a major-version bump changes replication protocol behavior and is executed one node at a time (rolling), not redeployed uniformly like a minor/patch bump.") + g.Attribute("target_spock_version", g.String, func() { + g.Description("The Spock major version to upgrade to.") + g.Pattern(spockVersionPattern) + g.Example("6") + g.Meta("struct:tag:json", "target_spock_version") + }) + g.Attribute("image", g.String, func() { + g.Description("Full container image reference of the upgrade target. Must match the image field of a manifest entry whose spock_version is target_spock_version and whose postgres_version matches the database's current postgres_version. Unlike ApplyUpgradeRequest, the target entry is not required to have stability \"stable\" — a Spock major version is expected to still be in a \"dev\" stability window while this action is in use for it.") + g.Example("ghcr.io/pgedge/pgedge-postgres:18.4-spock6.0.0-standard-1") + g.MinLength(1) + g.Meta("struct:tag:json", "image") + }) + g.Attribute("node_order", g.ArrayOf(g.String), func() { + g.Description("Explicit order (by node name) in which nodes are upgraded, one at a time. Defaults to the order nodes appear in the database spec if omitted. Every node in the database must appear exactly once.") + g.Example([]string{"n2", "n1", "n3"}) + g.Meta("struct:tag:json", "node_order,omitempty") + }) + + g.Required("target_spock_version", "image") +}) + +var ApplyMajorUpgradeResponse = g.Type("ApplyMajorUpgradeResponse", func() { + g.Attribute("task", Task, func() { + g.Description("The task tracking the major-version upgrade operation.") + g.Meta("struct:tag:json", "task") + }) + g.Attribute("database", Database, func() { + g.Description("The database being upgraded.") + g.Meta("struct:tag:json", "database") + }) + + g.Required("task", "database") +}) + var BackupDatabaseNodeResponse = g.Type("BackupDatabaseNodeResponse", func() { g.Attribute("task", Task, func() { g.Description("The task that will backup this database node.") diff --git a/api/apiv1/gen/control_plane/client.go b/api/apiv1/gen/control_plane/client.go index 5ff8009b..e14c97cd 100644 --- a/api/apiv1/gen/control_plane/client.go +++ b/api/apiv1/gen/control_plane/client.go @@ -28,6 +28,7 @@ type Client struct { GetDatabaseEndpoint goa.Endpoint UpdateDatabaseEndpoint goa.Endpoint ApplyUpgradeEndpoint goa.Endpoint + ApplyMajorUpgradeEndpoint goa.Endpoint DeleteDatabaseEndpoint goa.Endpoint BackupDatabaseNodeEndpoint goa.Endpoint SwitchoverDatabaseNodeEndpoint goa.Endpoint @@ -48,7 +49,7 @@ type Client struct { } // NewClient initializes a "control-plane" service client given the endpoints. -func NewClient(initCluster, joinCluster, getJoinToken, getJoinOptions, getCluster, listHosts, getHost, removeHost, listDatabases, createDatabase, getDatabase, updateDatabase, applyUpgrade, deleteDatabase, backupDatabaseNode, switchoverDatabaseNode, failoverDatabaseNode, listDatabaseTasks, getDatabaseTask, getDatabaseTaskLog, listHostTasks, getHostTask, getHostTaskLog, listTasks, restoreDatabase, getVersion, restartInstance, stopInstance, startInstance, cancelDatabaseTask goa.Endpoint) *Client { +func NewClient(initCluster, joinCluster, getJoinToken, getJoinOptions, getCluster, listHosts, getHost, removeHost, listDatabases, createDatabase, getDatabase, updateDatabase, applyUpgrade, applyMajorUpgrade, deleteDatabase, backupDatabaseNode, switchoverDatabaseNode, failoverDatabaseNode, listDatabaseTasks, getDatabaseTask, getDatabaseTaskLog, listHostTasks, getHostTask, getHostTaskLog, listTasks, restoreDatabase, getVersion, restartInstance, stopInstance, startInstance, cancelDatabaseTask goa.Endpoint) *Client { return &Client{ InitClusterEndpoint: initCluster, JoinClusterEndpoint: joinCluster, @@ -63,6 +64,7 @@ func NewClient(initCluster, joinCluster, getJoinToken, getJoinOptions, getCluste GetDatabaseEndpoint: getDatabase, UpdateDatabaseEndpoint: updateDatabase, ApplyUpgradeEndpoint: applyUpgrade, + ApplyMajorUpgradeEndpoint: applyMajorUpgrade, DeleteDatabaseEndpoint: deleteDatabase, BackupDatabaseNodeEndpoint: backupDatabaseNode, SwitchoverDatabaseNodeEndpoint: switchoverDatabaseNode, @@ -289,6 +291,25 @@ func (c *Client) ApplyUpgrade(ctx context.Context, p *ApplyUpgradePayload) (res return ires.(*ApplyUpgradeResponse), nil } +// ApplyMajorUpgrade calls the "apply-major-upgrade" endpoint of the +// "control-plane" service. +// ApplyMajorUpgrade may return the following errors: +// - "cluster_not_initialized" (type *goa.ServiceError) +// - "database_not_modifiable" (type *goa.ServiceError) +// - "invalid_input" (type *goa.ServiceError) +// - "not_found" (type *goa.ServiceError) +// - "operation_already_in_progress" (type *goa.ServiceError) +// - "server_error" (type *goa.ServiceError) +// - error: internal error +func (c *Client) ApplyMajorUpgrade(ctx context.Context, p *ApplyMajorUpgradePayload) (res *ApplyMajorUpgradeResponse, err error) { + var ires any + ires, err = c.ApplyMajorUpgradeEndpoint(ctx, p) + if err != nil { + return + } + return ires.(*ApplyMajorUpgradeResponse), nil +} + // DeleteDatabase calls the "delete-database" endpoint of the "control-plane" // service. // DeleteDatabase may return the following errors: diff --git a/api/apiv1/gen/control_plane/endpoints.go b/api/apiv1/gen/control_plane/endpoints.go index 281ef4f0..7c28b5a9 100644 --- a/api/apiv1/gen/control_plane/endpoints.go +++ b/api/apiv1/gen/control_plane/endpoints.go @@ -28,6 +28,7 @@ type Endpoints struct { GetDatabase goa.Endpoint UpdateDatabase goa.Endpoint ApplyUpgrade goa.Endpoint + ApplyMajorUpgrade goa.Endpoint DeleteDatabase goa.Endpoint BackupDatabaseNode goa.Endpoint SwitchoverDatabaseNode goa.Endpoint @@ -63,6 +64,7 @@ func NewEndpoints(s Service) *Endpoints { GetDatabase: NewGetDatabaseEndpoint(s), UpdateDatabase: NewUpdateDatabaseEndpoint(s), ApplyUpgrade: NewApplyUpgradeEndpoint(s), + ApplyMajorUpgrade: NewApplyMajorUpgradeEndpoint(s), DeleteDatabase: NewDeleteDatabaseEndpoint(s), BackupDatabaseNode: NewBackupDatabaseNodeEndpoint(s), SwitchoverDatabaseNode: NewSwitchoverDatabaseNodeEndpoint(s), @@ -99,6 +101,7 @@ func (e *Endpoints) Use(m func(goa.Endpoint) goa.Endpoint) { e.GetDatabase = m(e.GetDatabase) e.UpdateDatabase = m(e.UpdateDatabase) e.ApplyUpgrade = m(e.ApplyUpgrade) + e.ApplyMajorUpgrade = m(e.ApplyMajorUpgrade) e.DeleteDatabase = m(e.DeleteDatabase) e.BackupDatabaseNode = m(e.BackupDatabaseNode) e.SwitchoverDatabaseNode = m(e.SwitchoverDatabaseNode) @@ -232,6 +235,15 @@ func NewApplyUpgradeEndpoint(s Service) goa.Endpoint { } } +// NewApplyMajorUpgradeEndpoint returns an endpoint function that calls the +// method "apply-major-upgrade" of service "control-plane". +func NewApplyMajorUpgradeEndpoint(s Service) goa.Endpoint { + return func(ctx context.Context, req any) (any, error) { + p := req.(*ApplyMajorUpgradePayload) + return s.ApplyMajorUpgrade(ctx, p) + } +} + // NewDeleteDatabaseEndpoint returns an endpoint function that calls the method // "delete-database" of service "control-plane". func NewDeleteDatabaseEndpoint(s Service) goa.Endpoint { diff --git a/api/apiv1/gen/control_plane/service.go b/api/apiv1/gen/control_plane/service.go index ffda432b..4a258eb3 100644 --- a/api/apiv1/gen/control_plane/service.go +++ b/api/apiv1/gen/control_plane/service.go @@ -44,6 +44,11 @@ type Service interface { // current version and strictly newer. Container pull and restart happen // asynchronously; this endpoint returns once redeployment is triggered. ApplyUpgrade(context.Context, *ApplyUpgradePayload) (res *ApplyUpgradeResponse, err error) + // Applies a dedicated Spock major-version upgrade (e.g. 5.x to 6.x) to a + // database, rolling through each node one at a time rather than redeploying + // uniformly. Independent of apply-upgrade, which is restricted to same-major + // minor/patch bumps and cannot reach a different Spock major. + ApplyMajorUpgrade(context.Context, *ApplyMajorUpgradePayload) (res *ApplyMajorUpgradeResponse, err error) // Deletes a database from the cluster. DeleteDatabase(context.Context, *DeleteDatabasePayload) (res *DeleteDatabaseResponse, err error) // Initiates a backup for a database node. @@ -96,7 +101,7 @@ const ServiceName = "control-plane" // MethodNames lists the service method names as defined in the design. These // are the same values that are set in the endpoint request contexts under the // MethodKey key. -var MethodNames = [30]string{"init-cluster", "join-cluster", "get-join-token", "get-join-options", "get-cluster", "list-hosts", "get-host", "remove-host", "list-databases", "create-database", "get-database", "update-database", "apply-upgrade", "delete-database", "backup-database-node", "switchover-database-node", "failover-database-node", "list-database-tasks", "get-database-task", "get-database-task-log", "list-host-tasks", "get-host-task", "get-host-task-log", "list-tasks", "restore-database", "get-version", "restart-instance", "stop-instance", "start-instance", "cancel-database-task"} +var MethodNames = [31]string{"init-cluster", "join-cluster", "get-join-token", "get-join-options", "get-cluster", "list-hosts", "get-host", "remove-host", "list-databases", "create-database", "get-database", "update-database", "apply-upgrade", "apply-major-upgrade", "delete-database", "backup-database-node", "switchover-database-node", "failover-database-node", "list-database-tasks", "get-database-task", "get-database-task-log", "list-host-tasks", "get-host-task", "get-host-task-log", "list-tasks", "restore-database", "get-version", "restart-instance", "stop-instance", "start-instance", "cancel-database-task"} // A Control Plane API error. type APIError struct { @@ -106,6 +111,43 @@ type APIError struct { Message string `json:"message"` } +// ApplyMajorUpgradePayload is the payload type of the control-plane service +// apply-major-upgrade method. +type ApplyMajorUpgradePayload struct { + // ID of the database to upgrade. + DatabaseID Identifier + Request *ApplyMajorUpgradeRequest +} + +// Request to upgrade a database across a Spock major version boundary (e.g. +// 5.x to 6.x). Deliberately separate from ApplyUpgradeRequest: a major-version +// bump changes replication protocol behavior and is executed one node at a +// time (rolling), not redeployed uniformly like a minor/patch bump. +type ApplyMajorUpgradeRequest struct { + // The Spock major version to upgrade to. + TargetSpockVersion string `json:"target_spock_version"` + // Full container image reference of the upgrade target. Must match the image + // field of a manifest entry whose spock_version is target_spock_version and + // whose postgres_version matches the database's current postgres_version. + // Unlike ApplyUpgradeRequest, the target entry is not required to have + // stability "stable" — a Spock major version is expected to still be in a + // "dev" stability window while this action is in use for it. + Image string `json:"image"` + // Explicit order (by node name) in which nodes are upgraded, one at a time. + // Defaults to the order nodes appear in the database spec if omitted. Every + // node in the database must appear exactly once. + NodeOrder []string `json:"node_order,omitempty"` +} + +// ApplyMajorUpgradeResponse is the result type of the control-plane service +// apply-major-upgrade method. +type ApplyMajorUpgradeResponse struct { + // The task tracking the major-version upgrade operation. + Task *Task `json:"task"` + // The database being upgraded. + Database *Database `json:"database"` +} + // ApplyUpgradePayload is the payload type of the control-plane service // apply-upgrade method. type ApplyUpgradePayload struct { @@ -386,6 +428,13 @@ type DatabaseNodeSpec struct { // The Postgres version for this node in 'major.minor' format. Overrides the // Postgres version set in the DatabaseSpec. PostgresVersion *string `json:"postgres_version,omitempty"` + // The major version of the Spock extension for this node. Overrides the Spock + // version set in the DatabaseSpec. Only settable through the dedicated + // major-version upgrade action — rejected on create-database and on the + // general update-database path, since a per-node major mismatch is only ever a + // deliberate, transient state during a rolling major-version upgrade, never a + // steady-state topology choice. + SpockVersion *string `json:"spock_version,omitempty"` // The port used by the Postgres database for this node. Overrides the Postgres // port set in the DatabaseSpec. Port *int `json:"port,omitempty"` diff --git a/api/apiv1/gen/http/cli/control_plane/cli.go b/api/apiv1/gen/http/cli/control_plane/cli.go index 80eebed1..7cdd8eed 100644 --- a/api/apiv1/gen/http/cli/control_plane/cli.go +++ b/api/apiv1/gen/http/cli/control_plane/cli.go @@ -23,7 +23,7 @@ import ( // command (subcommand1|subcommand2|...) func UsageCommands() []string { return []string{ - "control-plane (init-cluster|join-cluster|get-join-token|get-join-options|get-cluster|list-hosts|get-host|remove-host|list-databases|create-database|get-database|update-database|apply-upgrade|delete-database|backup-database-node|switchover-database-node|failover-database-node|list-database-tasks|get-database-task|get-database-task-log|list-host-tasks|get-host-task|get-host-task-log|list-tasks|restore-database|get-version|restart-instance|stop-instance|start-instance|cancel-database-task)", + "control-plane (init-cluster|join-cluster|get-join-token|get-join-options|get-cluster|list-hosts|get-host|remove-host|list-databases|create-database|get-database|update-database|apply-upgrade|apply-major-upgrade|delete-database|backup-database-node|switchover-database-node|failover-database-node|list-database-tasks|get-database-task|get-database-task-log|list-host-tasks|get-host-task|get-host-task-log|list-tasks|restore-database|get-version|restart-instance|stop-instance|start-instance|cancel-database-task)", } } @@ -87,6 +87,10 @@ func ParseEndpoint( controlPlaneApplyUpgradeBodyFlag = controlPlaneApplyUpgradeFlags.String("body", "REQUIRED", "") controlPlaneApplyUpgradeDatabaseIDFlag = controlPlaneApplyUpgradeFlags.String("database-id", "REQUIRED", "ID of the database to upgrade.") + controlPlaneApplyMajorUpgradeFlags = flag.NewFlagSet("apply-major-upgrade", flag.ExitOnError) + controlPlaneApplyMajorUpgradeBodyFlag = controlPlaneApplyMajorUpgradeFlags.String("body", "REQUIRED", "") + controlPlaneApplyMajorUpgradeDatabaseIDFlag = controlPlaneApplyMajorUpgradeFlags.String("database-id", "REQUIRED", "ID of the database to upgrade.") + controlPlaneDeleteDatabaseFlags = flag.NewFlagSet("delete-database", flag.ExitOnError) controlPlaneDeleteDatabaseDatabaseIDFlag = controlPlaneDeleteDatabaseFlags.String("database-id", "REQUIRED", "ID of the database to delete.") controlPlaneDeleteDatabaseForceFlag = controlPlaneDeleteDatabaseFlags.String("force", "", "") @@ -186,6 +190,7 @@ func ParseEndpoint( controlPlaneGetDatabaseFlags.Usage = controlPlaneGetDatabaseUsage controlPlaneUpdateDatabaseFlags.Usage = controlPlaneUpdateDatabaseUsage controlPlaneApplyUpgradeFlags.Usage = controlPlaneApplyUpgradeUsage + controlPlaneApplyMajorUpgradeFlags.Usage = controlPlaneApplyMajorUpgradeUsage controlPlaneDeleteDatabaseFlags.Usage = controlPlaneDeleteDatabaseUsage controlPlaneBackupDatabaseNodeFlags.Usage = controlPlaneBackupDatabaseNodeUsage controlPlaneSwitchoverDatabaseNodeFlags.Usage = controlPlaneSwitchoverDatabaseNodeUsage @@ -277,6 +282,9 @@ func ParseEndpoint( case "apply-upgrade": epf = controlPlaneApplyUpgradeFlags + case "apply-major-upgrade": + epf = controlPlaneApplyMajorUpgradeFlags + case "delete-database": epf = controlPlaneDeleteDatabaseFlags @@ -389,6 +397,9 @@ func ParseEndpoint( case "apply-upgrade": endpoint = c.ApplyUpgrade() data, err = controlplanec.BuildApplyUpgradePayload(*controlPlaneApplyUpgradeBodyFlag, *controlPlaneApplyUpgradeDatabaseIDFlag) + case "apply-major-upgrade": + endpoint = c.ApplyMajorUpgrade() + data, err = controlplanec.BuildApplyMajorUpgradePayload(*controlPlaneApplyMajorUpgradeBodyFlag, *controlPlaneApplyMajorUpgradeDatabaseIDFlag) case "delete-database": endpoint = c.DeleteDatabase() data, err = controlplanec.BuildDeleteDatabasePayload(*controlPlaneDeleteDatabaseDatabaseIDFlag, *controlPlaneDeleteDatabaseForceFlag) @@ -468,6 +479,7 @@ func controlPlaneUsage() { fmt.Fprintln(os.Stderr, ` get-database: Returns information about a particular database in the cluster.`) fmt.Fprintln(os.Stderr, ` update-database: Updates a database with the given specification.`) fmt.Fprintln(os.Stderr, ` apply-upgrade: Applies a minor-version upgrade to a database. The target image must be a stable manifest entry in the same Postgres major / Spock major bucket as the current version and strictly newer. Container pull and restart happen asynchronously; this endpoint returns once redeployment is triggered.`) + fmt.Fprintln(os.Stderr, ` apply-major-upgrade: Applies a dedicated Spock major-version upgrade (e.g. 5.x to 6.x) to a database, rolling through each node one at a time rather than redeploying uniformly. Independent of apply-upgrade, which is restricted to same-major minor/patch bumps and cannot reach a different Spock major.`) fmt.Fprintln(os.Stderr, ` delete-database: Deletes a database from the cluster.`) fmt.Fprintln(os.Stderr, ` backup-database-node: Initiates a backup for a database node.`) fmt.Fprintln(os.Stderr, ` switchover-database-node: Performs a planned switchover for a node's primary to a replica candidate.`) @@ -729,6 +741,26 @@ func controlPlaneApplyUpgradeUsage() { fmt.Fprintf(os.Stderr, " %s %s\n", os.Args[0], "control-plane apply-upgrade --body '{\n \"image\": \"ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.8-standard-1\"\n }' --database-id \"76f9b8c0-4958-11f0-a489-3bb29577c696\"") } +func controlPlaneApplyMajorUpgradeUsage() { + // Header with flags + fmt.Fprintf(os.Stderr, "%s [flags] control-plane apply-major-upgrade", os.Args[0]) + fmt.Fprint(os.Stderr, " -body JSON") + fmt.Fprint(os.Stderr, " -database-id STRING") + fmt.Fprintln(os.Stderr) + + // Description + fmt.Fprintln(os.Stderr) + fmt.Fprintln(os.Stderr, `Applies a dedicated Spock major-version upgrade (e.g. 5.x to 6.x) to a database, rolling through each node one at a time rather than redeploying uniformly. Independent of apply-upgrade, which is restricted to same-major minor/patch bumps and cannot reach a different Spock major.`) + + // Flags list + fmt.Fprintln(os.Stderr, ` -body JSON: `) + fmt.Fprintln(os.Stderr, ` -database-id STRING: ID of the database to upgrade.`) + + fmt.Fprintln(os.Stderr) + fmt.Fprintln(os.Stderr, "Example:") + fmt.Fprintf(os.Stderr, " %s %s\n", os.Args[0], "control-plane apply-major-upgrade --body '{\n \"image\": \"ghcr.io/pgedge/pgedge-postgres:18.4-spock6.0.0-standard-1\",\n \"node_order\": [\n \"n2\",\n \"n1\",\n \"n3\"\n ],\n \"target_spock_version\": \"6\"\n }' --database-id \"76f9b8c0-4958-11f0-a489-3bb29577c696\"") +} + func controlPlaneDeleteDatabaseUsage() { // Header with flags fmt.Fprintf(os.Stderr, "%s [flags] control-plane delete-database", os.Args[0]) diff --git a/api/apiv1/gen/http/control_plane/client/cli.go b/api/apiv1/gen/http/control_plane/client/cli.go index 743009be..5e2bcebc 100644 --- a/api/apiv1/gen/http/control_plane/client/cli.go +++ b/api/apiv1/gen/http/control_plane/client/cli.go @@ -414,6 +414,55 @@ func BuildApplyUpgradePayload(controlPlaneApplyUpgradeBody string, controlPlaneA return res, nil } +// BuildApplyMajorUpgradePayload builds the payload for the control-plane +// apply-major-upgrade endpoint from CLI flags. +func BuildApplyMajorUpgradePayload(controlPlaneApplyMajorUpgradeBody string, controlPlaneApplyMajorUpgradeDatabaseID string) (*controlplane.ApplyMajorUpgradePayload, error) { + var err error + var body ApplyMajorUpgradeRequestBody + { + err = json.Unmarshal([]byte(controlPlaneApplyMajorUpgradeBody), &body) + if err != nil { + return nil, fmt.Errorf("invalid JSON for body, \nerror: %s, \nexample of valid JSON:\n%s", err, "'{\n \"image\": \"ghcr.io/pgedge/pgedge-postgres:18.4-spock6.0.0-standard-1\",\n \"node_order\": [\n \"n2\",\n \"n1\",\n \"n3\"\n ],\n \"target_spock_version\": \"6\"\n }'") + } + err = goa.MergeErrors(err, goa.ValidatePattern("body.target_spock_version", body.TargetSpockVersion, "^\\d{1}$")) + if utf8.RuneCountInString(body.Image) < 1 { + err = goa.MergeErrors(err, goa.InvalidLengthError("body.image", body.Image, utf8.RuneCountInString(body.Image), 1, true)) + } + if err != nil { + return nil, err + } + } + var databaseID string + { + databaseID = controlPlaneApplyMajorUpgradeDatabaseID + if utf8.RuneCountInString(databaseID) < 1 { + err = goa.MergeErrors(err, goa.InvalidLengthError("database_id", databaseID, utf8.RuneCountInString(databaseID), 1, true)) + } + if utf8.RuneCountInString(databaseID) > 36 { + err = goa.MergeErrors(err, goa.InvalidLengthError("database_id", databaseID, utf8.RuneCountInString(databaseID), 36, false)) + } + if err != nil { + return nil, err + } + } + v := &controlplane.ApplyMajorUpgradeRequest{ + TargetSpockVersion: body.TargetSpockVersion, + Image: body.Image, + } + if body.NodeOrder != nil { + v.NodeOrder = make([]string, len(body.NodeOrder)) + for i, val := range body.NodeOrder { + v.NodeOrder[i] = val + } + } + res := &controlplane.ApplyMajorUpgradePayload{ + Request: v, + } + res.DatabaseID = controlplane.Identifier(databaseID) + + return res, nil +} + // BuildDeleteDatabasePayload builds the payload for the control-plane // delete-database endpoint from CLI flags. func BuildDeleteDatabasePayload(controlPlaneDeleteDatabaseDatabaseID string, controlPlaneDeleteDatabaseForce string) (*controlplane.DeleteDatabasePayload, error) { diff --git a/api/apiv1/gen/http/control_plane/client/client.go b/api/apiv1/gen/http/control_plane/client/client.go index cdf440f1..01592a75 100644 --- a/api/apiv1/gen/http/control_plane/client/client.go +++ b/api/apiv1/gen/http/control_plane/client/client.go @@ -69,6 +69,10 @@ type Client struct { // apply-upgrade endpoint. ApplyUpgradeDoer goahttp.Doer + // ApplyMajorUpgrade Doer is the HTTP client used to make requests to the + // apply-major-upgrade endpoint. + ApplyMajorUpgradeDoer goahttp.Doer + // DeleteDatabase Doer is the HTTP client used to make requests to the // delete-database endpoint. DeleteDatabaseDoer goahttp.Doer @@ -171,6 +175,7 @@ func NewClient( GetDatabaseDoer: doer, UpdateDatabaseDoer: doer, ApplyUpgradeDoer: doer, + ApplyMajorUpgradeDoer: doer, DeleteDatabaseDoer: doer, BackupDatabaseNodeDoer: doer, SwitchoverDatabaseNodeDoer: doer, @@ -488,6 +493,30 @@ func (c *Client) ApplyUpgrade() goa.Endpoint { } } +// ApplyMajorUpgrade returns an endpoint that makes HTTP requests to the +// control-plane service apply-major-upgrade server. +func (c *Client) ApplyMajorUpgrade() goa.Endpoint { + var ( + encodeRequest = EncodeApplyMajorUpgradeRequest(c.encoder) + decodeResponse = DecodeApplyMajorUpgradeResponse(c.decoder, c.RestoreResponseBody) + ) + return func(ctx context.Context, v any) (any, error) { + req, err := c.BuildApplyMajorUpgradeRequest(ctx, v) + if err != nil { + return nil, err + } + err = encodeRequest(req, v) + if err != nil { + return nil, err + } + resp, err := c.ApplyMajorUpgradeDoer.Do(req) + if err != nil { + return nil, goahttp.ErrRequestError("control-plane", "apply-major-upgrade", err) + } + return decodeResponse(resp) + } +} + // DeleteDatabase returns an endpoint that makes HTTP requests to the // control-plane service delete-database server. func (c *Client) DeleteDatabase() goa.Endpoint { diff --git a/api/apiv1/gen/http/control_plane/client/encode_decode.go b/api/apiv1/gen/http/control_plane/client/encode_decode.go index 5907dae1..a0a9a9f3 100644 --- a/api/apiv1/gen/http/control_plane/client/encode_decode.go +++ b/api/apiv1/gen/http/control_plane/client/encode_decode.go @@ -1690,6 +1690,187 @@ func DecodeApplyUpgradeResponse(decoder func(*http.Response) goahttp.Decoder, re } } +// BuildApplyMajorUpgradeRequest instantiates a HTTP request object with method +// and path set to call the "control-plane" service "apply-major-upgrade" +// endpoint +func (c *Client) BuildApplyMajorUpgradeRequest(ctx context.Context, v any) (*http.Request, error) { + var ( + databaseID string + ) + { + p, ok := v.(*controlplane.ApplyMajorUpgradePayload) + if !ok { + return nil, goahttp.ErrInvalidType("control-plane", "apply-major-upgrade", "*controlplane.ApplyMajorUpgradePayload", v) + } + databaseID = string(p.DatabaseID) + } + u := &url.URL{Scheme: c.scheme, Host: c.host, Path: ApplyMajorUpgradeControlPlanePath(databaseID)} + req, err := http.NewRequest("POST", u.String(), nil) + if err != nil { + return nil, goahttp.ErrInvalidURL("control-plane", "apply-major-upgrade", u.String(), err) + } + if ctx != nil { + req = req.WithContext(ctx) + } + + return req, nil +} + +// EncodeApplyMajorUpgradeRequest returns an encoder for requests sent to the +// control-plane apply-major-upgrade server. +func EncodeApplyMajorUpgradeRequest(encoder func(*http.Request) goahttp.Encoder) func(*http.Request, any) error { + return func(req *http.Request, v any) error { + p, ok := v.(*controlplane.ApplyMajorUpgradePayload) + if !ok { + return goahttp.ErrInvalidType("control-plane", "apply-major-upgrade", "*controlplane.ApplyMajorUpgradePayload", v) + } + body := NewApplyMajorUpgradeRequestBody(p) + if err := encoder(req).Encode(&body); err != nil { + return goahttp.ErrEncodingError("control-plane", "apply-major-upgrade", err) + } + return nil + } +} + +// DecodeApplyMajorUpgradeResponse returns a decoder for responses returned by +// the control-plane apply-major-upgrade endpoint. restoreBody controls whether +// the response body should be restored after having been read. +// DecodeApplyMajorUpgradeResponse may return the following errors: +// - "cluster_not_initialized" (type *controlplane.APIError): http.StatusConflict +// - "database_not_modifiable" (type *controlplane.APIError): http.StatusConflict +// - "operation_already_in_progress" (type *controlplane.APIError): http.StatusConflict +// - "invalid_input" (type *controlplane.APIError): http.StatusBadRequest +// - "not_found" (type *controlplane.APIError): http.StatusNotFound +// - "server_error" (type *controlplane.APIError): http.StatusInternalServerError +// - error: internal error +func DecodeApplyMajorUpgradeResponse(decoder func(*http.Response) goahttp.Decoder, restoreBody bool) func(*http.Response) (any, error) { + return func(resp *http.Response) (any, error) { + if restoreBody { + b, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + resp.Body = io.NopCloser(bytes.NewBuffer(b)) + defer func() { + resp.Body = io.NopCloser(bytes.NewBuffer(b)) + }() + } else { + defer resp.Body.Close() + } + switch resp.StatusCode { + case http.StatusOK: + var ( + body ApplyMajorUpgradeResponseBody + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("control-plane", "apply-major-upgrade", err) + } + err = ValidateApplyMajorUpgradeResponseBody(&body) + if err != nil { + return nil, goahttp.ErrValidationError("control-plane", "apply-major-upgrade", err) + } + res := NewApplyMajorUpgradeResponseOK(&body) + return res, nil + case http.StatusConflict: + en := resp.Header.Get("goa-error") + switch en { + case "cluster_not_initialized": + var ( + body ApplyMajorUpgradeClusterNotInitializedResponseBody + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("control-plane", "apply-major-upgrade", err) + } + err = ValidateApplyMajorUpgradeClusterNotInitializedResponseBody(&body) + if err != nil { + return nil, goahttp.ErrValidationError("control-plane", "apply-major-upgrade", err) + } + return nil, NewApplyMajorUpgradeClusterNotInitialized(&body) + case "database_not_modifiable": + var ( + body ApplyMajorUpgradeDatabaseNotModifiableResponseBody + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("control-plane", "apply-major-upgrade", err) + } + err = ValidateApplyMajorUpgradeDatabaseNotModifiableResponseBody(&body) + if err != nil { + return nil, goahttp.ErrValidationError("control-plane", "apply-major-upgrade", err) + } + return nil, NewApplyMajorUpgradeDatabaseNotModifiable(&body) + case "operation_already_in_progress": + var ( + body ApplyMajorUpgradeOperationAlreadyInProgressResponseBody + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("control-plane", "apply-major-upgrade", err) + } + err = ValidateApplyMajorUpgradeOperationAlreadyInProgressResponseBody(&body) + if err != nil { + return nil, goahttp.ErrValidationError("control-plane", "apply-major-upgrade", err) + } + return nil, NewApplyMajorUpgradeOperationAlreadyInProgress(&body) + default: + body, _ := io.ReadAll(resp.Body) + return nil, goahttp.ErrInvalidResponse("control-plane", "apply-major-upgrade", resp.StatusCode, string(body)) + } + case http.StatusBadRequest: + var ( + body ApplyMajorUpgradeInvalidInputResponseBody + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("control-plane", "apply-major-upgrade", err) + } + err = ValidateApplyMajorUpgradeInvalidInputResponseBody(&body) + if err != nil { + return nil, goahttp.ErrValidationError("control-plane", "apply-major-upgrade", err) + } + return nil, NewApplyMajorUpgradeInvalidInput(&body) + case http.StatusNotFound: + var ( + body ApplyMajorUpgradeNotFoundResponseBody + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("control-plane", "apply-major-upgrade", err) + } + err = ValidateApplyMajorUpgradeNotFoundResponseBody(&body) + if err != nil { + return nil, goahttp.ErrValidationError("control-plane", "apply-major-upgrade", err) + } + return nil, NewApplyMajorUpgradeNotFound(&body) + case http.StatusInternalServerError: + var ( + body ApplyMajorUpgradeServerErrorResponseBody + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("control-plane", "apply-major-upgrade", err) + } + err = ValidateApplyMajorUpgradeServerErrorResponseBody(&body) + if err != nil { + return nil, goahttp.ErrValidationError("control-plane", "apply-major-upgrade", err) + } + return nil, NewApplyMajorUpgradeServerError(&body) + default: + body, _ := io.ReadAll(resp.Body) + return nil, goahttp.ErrInvalidResponse("control-plane", "apply-major-upgrade", resp.StatusCode, string(body)) + } + } +} + // BuildDeleteDatabaseRequest instantiates a HTTP request object with method // and path set to call the "control-plane" service "delete-database" endpoint func (c *Client) BuildDeleteDatabaseRequest(ctx context.Context, v any) (*http.Request, error) { @@ -4642,6 +4823,7 @@ func marshalControlplaneDatabaseNodeSpecToDatabaseNodeSpecRequestBody(v *control res := &DatabaseNodeSpecRequestBody{ Name: v.Name, PostgresVersion: v.PostgresVersion, + SpockVersion: v.SpockVersion, Port: v.Port, PatroniPort: v.PatroniPort, Cpus: v.Cpus, @@ -5140,6 +5322,7 @@ func marshalDatabaseNodeSpecRequestBodyToControlplaneDatabaseNodeSpec(v *Databas res := &controlplane.DatabaseNodeSpec{ Name: v.Name, PostgresVersion: v.PostgresVersion, + SpockVersion: v.SpockVersion, Port: v.Port, PatroniPort: v.PatroniPort, Cpus: v.Cpus, @@ -5778,6 +5961,7 @@ func unmarshalDatabaseNodeSpecResponseBodyToControlplaneDatabaseNodeSpec(v *Data res := &controlplane.DatabaseNodeSpec{ Name: *v.Name, PostgresVersion: v.PostgresVersion, + SpockVersion: v.SpockVersion, Port: v.Port, PatroniPort: v.PatroniPort, Cpus: v.Cpus, @@ -6262,6 +6446,7 @@ func marshalControlplaneDatabaseNodeSpecToDatabaseNodeSpecRequestBodyRequestBody res := &DatabaseNodeSpecRequestBodyRequestBody{ Name: v.Name, PostgresVersion: v.PostgresVersion, + SpockVersion: v.SpockVersion, Port: v.Port, PatroniPort: v.PatroniPort, Cpus: v.Cpus, @@ -6762,6 +6947,7 @@ func marshalDatabaseNodeSpecRequestBodyRequestBodyToControlplaneDatabaseNodeSpec res := &controlplane.DatabaseNodeSpec{ Name: v.Name, PostgresVersion: v.PostgresVersion, + SpockVersion: v.SpockVersion, Port: v.Port, PatroniPort: v.PatroniPort, Cpus: v.Cpus, diff --git a/api/apiv1/gen/http/control_plane/client/paths.go b/api/apiv1/gen/http/control_plane/client/paths.go index c7c78811..7320811e 100644 --- a/api/apiv1/gen/http/control_plane/client/paths.go +++ b/api/apiv1/gen/http/control_plane/client/paths.go @@ -76,6 +76,11 @@ func ApplyUpgradeControlPlanePath(databaseID string) string { return fmt.Sprintf("/v1/databases/%v/upgrade", databaseID) } +// ApplyMajorUpgradeControlPlanePath returns the URL path to the control-plane service apply-major-upgrade HTTP endpoint. +func ApplyMajorUpgradeControlPlanePath(databaseID string) string { + return fmt.Sprintf("/v1/databases/%v/upgrade-major", databaseID) +} + // DeleteDatabaseControlPlanePath returns the URL path to the control-plane service delete-database HTTP endpoint. func DeleteDatabaseControlPlanePath(databaseID string) string { return fmt.Sprintf("/v1/databases/%v", databaseID) diff --git a/api/apiv1/gen/http/control_plane/client/types.go b/api/apiv1/gen/http/control_plane/client/types.go index 4cb91a20..f3f44549 100644 --- a/api/apiv1/gen/http/control_plane/client/types.go +++ b/api/apiv1/gen/http/control_plane/client/types.go @@ -65,6 +65,24 @@ type ApplyUpgradeRequestBody struct { Image string `json:"image"` } +// ApplyMajorUpgradeRequestBody is the type of the "control-plane" service +// "apply-major-upgrade" endpoint HTTP request body. +type ApplyMajorUpgradeRequestBody struct { + // The Spock major version to upgrade to. + TargetSpockVersion string `json:"target_spock_version"` + // Full container image reference of the upgrade target. Must match the image + // field of a manifest entry whose spock_version is target_spock_version and + // whose postgres_version matches the database's current postgres_version. + // Unlike ApplyUpgradeRequest, the target entry is not required to have + // stability "stable" — a Spock major version is expected to still be in a + // "dev" stability window while this action is in use for it. + Image string `json:"image"` + // Explicit order (by node name) in which nodes are upgraded, one at a time. + // Defaults to the order nodes appear in the database spec if omitted. Every + // node in the database must appear exactly once. + NodeOrder []string `json:"node_order,omitempty"` +} + // BackupDatabaseNodeRequestBody is the type of the "control-plane" service // "backup-database-node" endpoint HTTP request body. type BackupDatabaseNodeRequestBody struct { @@ -247,6 +265,15 @@ type ApplyUpgradeResponseBody struct { Database *DatabaseResponseBody `json:"database"` } +// ApplyMajorUpgradeResponseBody is the type of the "control-plane" service +// "apply-major-upgrade" endpoint HTTP response body. +type ApplyMajorUpgradeResponseBody struct { + // The task tracking the major-version upgrade operation. + Task *TaskResponseBody `json:"task"` + // The database being upgraded. + Database *DatabaseResponseBody `json:"database"` +} + // DeleteDatabaseResponseBody is the type of the "control-plane" service // "delete-database" endpoint HTTP response body. type DeleteDatabaseResponseBody struct { @@ -943,6 +970,66 @@ type ApplyUpgradeServerErrorResponseBody struct { Message *string `json:"message"` } +// ApplyMajorUpgradeClusterNotInitializedResponseBody is the type of the +// "control-plane" service "apply-major-upgrade" endpoint HTTP response body +// for the "cluster_not_initialized" error. +type ApplyMajorUpgradeClusterNotInitializedResponseBody struct { + // The name of the error. + Name *string `json:"name"` + // The error message. + Message *string `json:"message"` +} + +// ApplyMajorUpgradeDatabaseNotModifiableResponseBody is the type of the +// "control-plane" service "apply-major-upgrade" endpoint HTTP response body +// for the "database_not_modifiable" error. +type ApplyMajorUpgradeDatabaseNotModifiableResponseBody struct { + // The name of the error. + Name *string `json:"name"` + // The error message. + Message *string `json:"message"` +} + +// ApplyMajorUpgradeOperationAlreadyInProgressResponseBody is the type of the +// "control-plane" service "apply-major-upgrade" endpoint HTTP response body +// for the "operation_already_in_progress" error. +type ApplyMajorUpgradeOperationAlreadyInProgressResponseBody struct { + // The name of the error. + Name *string `json:"name"` + // The error message. + Message *string `json:"message"` +} + +// ApplyMajorUpgradeInvalidInputResponseBody is the type of the "control-plane" +// service "apply-major-upgrade" endpoint HTTP response body for the +// "invalid_input" error. +type ApplyMajorUpgradeInvalidInputResponseBody struct { + // The name of the error. + Name *string `json:"name"` + // The error message. + Message *string `json:"message"` +} + +// ApplyMajorUpgradeNotFoundResponseBody is the type of the "control-plane" +// service "apply-major-upgrade" endpoint HTTP response body for the +// "not_found" error. +type ApplyMajorUpgradeNotFoundResponseBody struct { + // The name of the error. + Name *string `json:"name"` + // The error message. + Message *string `json:"message"` +} + +// ApplyMajorUpgradeServerErrorResponseBody is the type of the "control-plane" +// service "apply-major-upgrade" endpoint HTTP response body for the +// "server_error" error. +type ApplyMajorUpgradeServerErrorResponseBody struct { + // The name of the error. + Name *string `json:"name"` + // The error message. + Message *string `json:"message"` +} + // DeleteDatabaseClusterNotInitializedResponseBody is the type of the // "control-plane" service "delete-database" endpoint HTTP response body for // the "cluster_not_initialized" error. @@ -1962,6 +2049,13 @@ type DatabaseNodeSpecRequestBody struct { // The Postgres version for this node in 'major.minor' format. Overrides the // Postgres version set in the DatabaseSpec. PostgresVersion *string `json:"postgres_version,omitempty"` + // The major version of the Spock extension for this node. Overrides the Spock + // version set in the DatabaseSpec. Only settable through the dedicated + // major-version upgrade action — rejected on create-database and on the + // general update-database path, since a per-node major mismatch is only ever a + // deliberate, transient state during a rolling major-version upgrade, never a + // steady-state topology choice. + SpockVersion *string `json:"spock_version,omitempty"` // The port used by the Postgres database for this node. Overrides the Postgres // port set in the DatabaseSpec. Port *int `json:"port,omitempty"` @@ -2413,6 +2507,13 @@ type DatabaseNodeSpecResponseBody struct { // The Postgres version for this node in 'major.minor' format. Overrides the // Postgres version set in the DatabaseSpec. PostgresVersion *string `json:"postgres_version,omitempty"` + // The major version of the Spock extension for this node. Overrides the Spock + // version set in the DatabaseSpec. Only settable through the dedicated + // major-version upgrade action — rejected on create-database and on the + // general update-database path, since a per-node major mismatch is only ever a + // deliberate, transient state during a rolling major-version upgrade, never a + // steady-state topology choice. + SpockVersion *string `json:"spock_version,omitempty"` // The port used by the Postgres database for this node. Overrides the Postgres // port set in the DatabaseSpec. Port *int `json:"port,omitempty"` @@ -2784,6 +2885,13 @@ type DatabaseNodeSpecRequestBodyRequestBody struct { // The Postgres version for this node in 'major.minor' format. Overrides the // Postgres version set in the DatabaseSpec. PostgresVersion *string `json:"postgres_version,omitempty"` + // The major version of the Spock extension for this node. Overrides the Spock + // version set in the DatabaseSpec. Only settable through the dedicated + // major-version upgrade action — rejected on create-database and on the + // general update-database path, since a per-node major mismatch is only ever a + // deliberate, transient state during a rolling major-version upgrade, never a + // steady-state topology choice. + SpockVersion *string `json:"spock_version,omitempty"` // The port used by the Postgres database for this node. Overrides the Postgres // port set in the DatabaseSpec. Port *int `json:"port,omitempty"` @@ -3181,6 +3289,22 @@ func NewApplyUpgradeRequestBody(p *controlplane.ApplyUpgradePayload) *ApplyUpgra return body } +// NewApplyMajorUpgradeRequestBody builds the HTTP request body from the +// payload of the "apply-major-upgrade" endpoint of the "control-plane" service. +func NewApplyMajorUpgradeRequestBody(p *controlplane.ApplyMajorUpgradePayload) *ApplyMajorUpgradeRequestBody { + body := &ApplyMajorUpgradeRequestBody{ + TargetSpockVersion: p.Request.TargetSpockVersion, + Image: p.Request.Image, + } + if p.Request.NodeOrder != nil { + body.NodeOrder = make([]string, len(p.Request.NodeOrder)) + for i, val := range p.Request.NodeOrder { + body.NodeOrder[i] = val + } + } + return body +} + // NewBackupDatabaseNodeRequestBody builds the HTTP request body from the // payload of the "backup-database-node" endpoint of the "control-plane" // service. @@ -4005,6 +4129,82 @@ func NewApplyUpgradeServerError(body *ApplyUpgradeServerErrorResponseBody) *cont return v } +// NewApplyMajorUpgradeResponseOK builds a "control-plane" service +// "apply-major-upgrade" endpoint result from a HTTP "OK" response. +func NewApplyMajorUpgradeResponseOK(body *ApplyMajorUpgradeResponseBody) *controlplane.ApplyMajorUpgradeResponse { + v := &controlplane.ApplyMajorUpgradeResponse{} + v.Task = unmarshalTaskResponseBodyToControlplaneTask(body.Task) + v.Database = unmarshalDatabaseResponseBodyToControlplaneDatabase(body.Database) + + return v +} + +// NewApplyMajorUpgradeClusterNotInitialized builds a control-plane service +// apply-major-upgrade endpoint cluster_not_initialized error. +func NewApplyMajorUpgradeClusterNotInitialized(body *ApplyMajorUpgradeClusterNotInitializedResponseBody) *controlplane.APIError { + v := &controlplane.APIError{ + Name: *body.Name, + Message: *body.Message, + } + + return v +} + +// NewApplyMajorUpgradeDatabaseNotModifiable builds a control-plane service +// apply-major-upgrade endpoint database_not_modifiable error. +func NewApplyMajorUpgradeDatabaseNotModifiable(body *ApplyMajorUpgradeDatabaseNotModifiableResponseBody) *controlplane.APIError { + v := &controlplane.APIError{ + Name: *body.Name, + Message: *body.Message, + } + + return v +} + +// NewApplyMajorUpgradeOperationAlreadyInProgress builds a control-plane +// service apply-major-upgrade endpoint operation_already_in_progress error. +func NewApplyMajorUpgradeOperationAlreadyInProgress(body *ApplyMajorUpgradeOperationAlreadyInProgressResponseBody) *controlplane.APIError { + v := &controlplane.APIError{ + Name: *body.Name, + Message: *body.Message, + } + + return v +} + +// NewApplyMajorUpgradeInvalidInput builds a control-plane service +// apply-major-upgrade endpoint invalid_input error. +func NewApplyMajorUpgradeInvalidInput(body *ApplyMajorUpgradeInvalidInputResponseBody) *controlplane.APIError { + v := &controlplane.APIError{ + Name: *body.Name, + Message: *body.Message, + } + + return v +} + +// NewApplyMajorUpgradeNotFound builds a control-plane service +// apply-major-upgrade endpoint not_found error. +func NewApplyMajorUpgradeNotFound(body *ApplyMajorUpgradeNotFoundResponseBody) *controlplane.APIError { + v := &controlplane.APIError{ + Name: *body.Name, + Message: *body.Message, + } + + return v +} + +// NewApplyMajorUpgradeServerError builds a control-plane service +// apply-major-upgrade endpoint server_error error. +func NewApplyMajorUpgradeServerError(body *ApplyMajorUpgradeServerErrorResponseBody) *controlplane.APIError { + v := &controlplane.APIError{ + Name: *body.Name, + Message: *body.Message, + } + + return v +} + // NewDeleteDatabaseResponseOK builds a "control-plane" service // "delete-database" endpoint result from a HTTP "OK" response. func NewDeleteDatabaseResponseOK(body *DeleteDatabaseResponseBody) *controlplane.DeleteDatabaseResponse { @@ -5134,6 +5334,12 @@ func ValidateApplyUpgradeResponseBody(body *ApplyUpgradeResponseBody) (err error return } +// ValidateApplyMajorUpgradeResponseBody runs a no-op validation on +// Apply-Major-UpgradeResponseBody +func ValidateApplyMajorUpgradeResponseBody(body *ApplyMajorUpgradeResponseBody) (err error) { + return +} + // ValidateDeleteDatabaseResponseBody runs a no-op validation on // Delete-DatabaseResponseBody func ValidateDeleteDatabaseResponseBody(body *DeleteDatabaseResponseBody) (err error) { @@ -5524,6 +5730,42 @@ func ValidateApplyUpgradeServerErrorResponseBody(body *ApplyUpgradeServerErrorRe return } +// ValidateApplyMajorUpgradeClusterNotInitializedResponseBody runs a no-op +// validation on apply-major-upgrade_cluster_not_initialized_response_body +func ValidateApplyMajorUpgradeClusterNotInitializedResponseBody(body *ApplyMajorUpgradeClusterNotInitializedResponseBody) (err error) { + return +} + +// ValidateApplyMajorUpgradeDatabaseNotModifiableResponseBody runs a no-op +// validation on apply-major-upgrade_database_not_modifiable_response_body +func ValidateApplyMajorUpgradeDatabaseNotModifiableResponseBody(body *ApplyMajorUpgradeDatabaseNotModifiableResponseBody) (err error) { + return +} + +// ValidateApplyMajorUpgradeOperationAlreadyInProgressResponseBody runs a no-op +// validation on apply-major-upgrade_operation_already_in_progress_response_body +func ValidateApplyMajorUpgradeOperationAlreadyInProgressResponseBody(body *ApplyMajorUpgradeOperationAlreadyInProgressResponseBody) (err error) { + return +} + +// ValidateApplyMajorUpgradeInvalidInputResponseBody runs a no-op validation on +// apply-major-upgrade_invalid_input_response_body +func ValidateApplyMajorUpgradeInvalidInputResponseBody(body *ApplyMajorUpgradeInvalidInputResponseBody) (err error) { + return +} + +// ValidateApplyMajorUpgradeNotFoundResponseBody runs a no-op validation on +// apply-major-upgrade_not_found_response_body +func ValidateApplyMajorUpgradeNotFoundResponseBody(body *ApplyMajorUpgradeNotFoundResponseBody) (err error) { + return +} + +// ValidateApplyMajorUpgradeServerErrorResponseBody runs a no-op validation on +// apply-major-upgrade_server_error_response_body +func ValidateApplyMajorUpgradeServerErrorResponseBody(body *ApplyMajorUpgradeServerErrorResponseBody) (err error) { + return +} + // ValidateDeleteDatabaseClusterNotInitializedResponseBody runs a no-op // validation on delete-database_cluster_not_initialized_response_body func ValidateDeleteDatabaseClusterNotInitializedResponseBody(body *DeleteDatabaseClusterNotInitializedResponseBody) (err error) { @@ -6169,6 +6411,9 @@ func ValidateDatabaseNodeSpecRequestBody(body *DatabaseNodeSpecRequestBody) (err if body.PostgresVersion != nil { err = goa.MergeErrors(err, goa.ValidatePattern("body.postgres_version", *body.PostgresVersion, "^\\d{2}\\.\\d{1,2}$")) } + if body.SpockVersion != nil { + err = goa.MergeErrors(err, goa.ValidatePattern("body.spock_version", *body.SpockVersion, "^\\d{1}$")) + } if body.Port != nil { if *body.Port < 0 { err = goa.MergeErrors(err, goa.InvalidRangeError("body.port", *body.Port, 0, true)) @@ -6975,6 +7220,9 @@ func ValidateDatabaseNodeSpecRequestBodyRequestBody(body *DatabaseNodeSpecReques if body.PostgresVersion != nil { err = goa.MergeErrors(err, goa.ValidatePattern("body.postgres_version", *body.PostgresVersion, "^\\d{2}\\.\\d{1,2}$")) } + if body.SpockVersion != nil { + err = goa.MergeErrors(err, goa.ValidatePattern("body.spock_version", *body.SpockVersion, "^\\d{1}$")) + } if body.Port != nil { if *body.Port < 0 { err = goa.MergeErrors(err, goa.InvalidRangeError("body.port", *body.Port, 0, true)) diff --git a/api/apiv1/gen/http/control_plane/server/encode_decode.go b/api/apiv1/gen/http/control_plane/server/encode_decode.go index bd6c84d1..b8dd220b 100644 --- a/api/apiv1/gen/http/control_plane/server/encode_decode.go +++ b/api/apiv1/gen/http/control_plane/server/encode_decode.go @@ -1332,6 +1332,157 @@ func EncodeApplyUpgradeError(encoder func(context.Context, http.ResponseWriter) } } +// EncodeApplyMajorUpgradeResponse returns an encoder for responses returned by +// the control-plane apply-major-upgrade endpoint. +func EncodeApplyMajorUpgradeResponse(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder) func(context.Context, http.ResponseWriter, any) error { + return func(ctx context.Context, w http.ResponseWriter, v any) error { + res, _ := v.(*controlplane.ApplyMajorUpgradeResponse) + enc := encoder(ctx, w) + body := NewApplyMajorUpgradeResponseBody(res) + w.WriteHeader(http.StatusOK) + return enc.Encode(body) + } +} + +// DecodeApplyMajorUpgradeRequest returns a decoder for requests sent to the +// control-plane apply-major-upgrade endpoint. +func DecodeApplyMajorUpgradeRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.Decoder) func(*http.Request) (*controlplane.ApplyMajorUpgradePayload, error) { + return func(r *http.Request) (*controlplane.ApplyMajorUpgradePayload, error) { + var ( + body ApplyMajorUpgradeRequestBody + err error + ) + err = decoder(r).Decode(&body) + if err != nil { + if errors.Is(err, io.EOF) { + return nil, goa.MissingPayloadError() + } + var gerr *goa.ServiceError + if errors.As(err, &gerr) { + return nil, gerr + } + return nil, goa.DecodePayloadError(err.Error()) + } + err = ValidateApplyMajorUpgradeRequestBody(&body) + if err != nil { + return nil, err + } + + var ( + databaseID string + + params = mux.Vars(r) + ) + databaseID = params["database_id"] + if utf8.RuneCountInString(databaseID) < 1 { + err = goa.MergeErrors(err, goa.InvalidLengthError("database_id", databaseID, utf8.RuneCountInString(databaseID), 1, true)) + } + if utf8.RuneCountInString(databaseID) > 36 { + err = goa.MergeErrors(err, goa.InvalidLengthError("database_id", databaseID, utf8.RuneCountInString(databaseID), 36, false)) + } + if err != nil { + return nil, err + } + payload := NewApplyMajorUpgradePayload(&body, databaseID) + + return payload, nil + } +} + +// EncodeApplyMajorUpgradeError returns an encoder for errors returned by the +// apply-major-upgrade control-plane endpoint. +func EncodeApplyMajorUpgradeError(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, formatter func(ctx context.Context, err error) goahttp.Statuser) func(context.Context, http.ResponseWriter, error) error { + encodeError := goahttp.ErrorEncoder(encoder, formatter) + return func(ctx context.Context, w http.ResponseWriter, v error) error { + var en goa.GoaErrorNamer + if !errors.As(v, &en) { + return encodeError(ctx, w, v) + } + switch en.GoaErrorName() { + case "cluster_not_initialized": + var res *controlplane.APIError + errors.As(v, &res) + enc := encoder(ctx, w) + var body any + if formatter != nil { + body = formatter(ctx, res) + } else { + body = NewApplyMajorUpgradeClusterNotInitializedResponseBody(res) + } + w.Header().Set("goa-error", res.GoaErrorName()) + w.WriteHeader(http.StatusConflict) + return enc.Encode(body) + case "database_not_modifiable": + var res *controlplane.APIError + errors.As(v, &res) + enc := encoder(ctx, w) + var body any + if formatter != nil { + body = formatter(ctx, res) + } else { + body = NewApplyMajorUpgradeDatabaseNotModifiableResponseBody(res) + } + w.Header().Set("goa-error", res.GoaErrorName()) + w.WriteHeader(http.StatusConflict) + return enc.Encode(body) + case "operation_already_in_progress": + var res *controlplane.APIError + errors.As(v, &res) + enc := encoder(ctx, w) + var body any + if formatter != nil { + body = formatter(ctx, res) + } else { + body = NewApplyMajorUpgradeOperationAlreadyInProgressResponseBody(res) + } + w.Header().Set("goa-error", res.GoaErrorName()) + w.WriteHeader(http.StatusConflict) + return enc.Encode(body) + case "invalid_input": + var res *controlplane.APIError + errors.As(v, &res) + enc := encoder(ctx, w) + var body any + if formatter != nil { + body = formatter(ctx, res) + } else { + body = NewApplyMajorUpgradeInvalidInputResponseBody(res) + } + w.Header().Set("goa-error", res.GoaErrorName()) + w.WriteHeader(http.StatusBadRequest) + return enc.Encode(body) + case "not_found": + var res *controlplane.APIError + errors.As(v, &res) + enc := encoder(ctx, w) + var body any + if formatter != nil { + body = formatter(ctx, res) + } else { + body = NewApplyMajorUpgradeNotFoundResponseBody(res) + } + w.Header().Set("goa-error", res.GoaErrorName()) + w.WriteHeader(http.StatusNotFound) + return enc.Encode(body) + case "server_error": + var res *controlplane.APIError + errors.As(v, &res) + enc := encoder(ctx, w) + var body any + if formatter != nil { + body = formatter(ctx, res) + } else { + body = NewApplyMajorUpgradeServerErrorResponseBody(res) + } + w.Header().Set("goa-error", res.GoaErrorName()) + w.WriteHeader(http.StatusInternalServerError) + return enc.Encode(body) + default: + return encodeError(ctx, w, v) + } + } +} + // EncodeDeleteDatabaseResponse returns an encoder for responses returned by // the control-plane delete-database endpoint. func EncodeDeleteDatabaseResponse(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder) func(context.Context, http.ResponseWriter, any) error { @@ -3972,6 +4123,7 @@ func unmarshalDatabaseNodeSpecRequestBodyToControlplaneDatabaseNodeSpec(v *Datab res := &controlplane.DatabaseNodeSpec{ Name: *v.Name, PostgresVersion: v.PostgresVersion, + SpockVersion: v.SpockVersion, Port: v.Port, PatroniPort: v.PatroniPort, Cpus: v.Cpus, @@ -4600,6 +4752,7 @@ func marshalControlplaneDatabaseNodeSpecToDatabaseNodeSpecResponseBody(v *contro res := &DatabaseNodeSpecResponseBody{ Name: v.Name, PostgresVersion: v.PostgresVersion, + SpockVersion: v.SpockVersion, Port: v.Port, PatroniPort: v.PatroniPort, Cpus: v.Cpus, @@ -5094,6 +5247,7 @@ func unmarshalDatabaseNodeSpecRequestBodyRequestBodyToControlplaneDatabaseNodeSp res := &controlplane.DatabaseNodeSpec{ Name: *v.Name, PostgresVersion: v.PostgresVersion, + SpockVersion: v.SpockVersion, Port: v.Port, PatroniPort: v.PatroniPort, Cpus: v.Cpus, diff --git a/api/apiv1/gen/http/control_plane/server/paths.go b/api/apiv1/gen/http/control_plane/server/paths.go index 8e517da2..9453643e 100644 --- a/api/apiv1/gen/http/control_plane/server/paths.go +++ b/api/apiv1/gen/http/control_plane/server/paths.go @@ -76,6 +76,11 @@ func ApplyUpgradeControlPlanePath(databaseID string) string { return fmt.Sprintf("/v1/databases/%v/upgrade", databaseID) } +// ApplyMajorUpgradeControlPlanePath returns the URL path to the control-plane service apply-major-upgrade HTTP endpoint. +func ApplyMajorUpgradeControlPlanePath(databaseID string) string { + return fmt.Sprintf("/v1/databases/%v/upgrade-major", databaseID) +} + // DeleteDatabaseControlPlanePath returns the URL path to the control-plane service delete-database HTTP endpoint. func DeleteDatabaseControlPlanePath(databaseID string) string { return fmt.Sprintf("/v1/databases/%v", databaseID) diff --git a/api/apiv1/gen/http/control_plane/server/server.go b/api/apiv1/gen/http/control_plane/server/server.go index 49d74c2a..cdaab22b 100644 --- a/api/apiv1/gen/http/control_plane/server/server.go +++ b/api/apiv1/gen/http/control_plane/server/server.go @@ -33,6 +33,7 @@ type Server struct { GetDatabase http.Handler UpdateDatabase http.Handler ApplyUpgrade http.Handler + ApplyMajorUpgrade http.Handler DeleteDatabase http.Handler BackupDatabaseNode http.Handler SwitchoverDatabaseNode http.Handler @@ -98,6 +99,7 @@ func New( {"GetDatabase", "GET", "/v1/databases/{database_id}"}, {"UpdateDatabase", "POST", "/v1/databases/{database_id}"}, {"ApplyUpgrade", "POST", "/v1/databases/{database_id}/upgrade"}, + {"ApplyMajorUpgrade", "POST", "/v1/databases/{database_id}/upgrade-major"}, {"DeleteDatabase", "DELETE", "/v1/databases/{database_id}"}, {"BackupDatabaseNode", "POST", "/v1/databases/{database_id}/nodes/{node_name}/backups"}, {"SwitchoverDatabaseNode", "POST", "/v1/databases/{database_id}/nodes/{node_name}/switchover"}, @@ -130,6 +132,7 @@ func New( GetDatabase: NewGetDatabaseHandler(e.GetDatabase, mux, decoder, encoder, errhandler, formatter), UpdateDatabase: NewUpdateDatabaseHandler(e.UpdateDatabase, mux, decoder, encoder, errhandler, formatter), ApplyUpgrade: NewApplyUpgradeHandler(e.ApplyUpgrade, mux, decoder, encoder, errhandler, formatter), + ApplyMajorUpgrade: NewApplyMajorUpgradeHandler(e.ApplyMajorUpgrade, mux, decoder, encoder, errhandler, formatter), DeleteDatabase: NewDeleteDatabaseHandler(e.DeleteDatabase, mux, decoder, encoder, errhandler, formatter), BackupDatabaseNode: NewBackupDatabaseNodeHandler(e.BackupDatabaseNode, mux, decoder, encoder, errhandler, formatter), SwitchoverDatabaseNode: NewSwitchoverDatabaseNodeHandler(e.SwitchoverDatabaseNode, mux, decoder, encoder, errhandler, formatter), @@ -169,6 +172,7 @@ func (s *Server) Use(m func(http.Handler) http.Handler) { s.GetDatabase = m(s.GetDatabase) s.UpdateDatabase = m(s.UpdateDatabase) s.ApplyUpgrade = m(s.ApplyUpgrade) + s.ApplyMajorUpgrade = m(s.ApplyMajorUpgrade) s.DeleteDatabase = m(s.DeleteDatabase) s.BackupDatabaseNode = m(s.BackupDatabaseNode) s.SwitchoverDatabaseNode = m(s.SwitchoverDatabaseNode) @@ -206,6 +210,7 @@ func Mount(mux goahttp.Muxer, h *Server) { MountGetDatabaseHandler(mux, h.GetDatabase) MountUpdateDatabaseHandler(mux, h.UpdateDatabase) MountApplyUpgradeHandler(mux, h.ApplyUpgrade) + MountApplyMajorUpgradeHandler(mux, h.ApplyMajorUpgrade) MountDeleteDatabaseHandler(mux, h.DeleteDatabase) MountBackupDatabaseNodeHandler(mux, h.BackupDatabaseNode) MountSwitchoverDatabaseNodeHandler(mux, h.SwitchoverDatabaseNode) @@ -899,6 +904,59 @@ func NewApplyUpgradeHandler( }) } +// MountApplyMajorUpgradeHandler configures the mux to serve the +// "control-plane" service "apply-major-upgrade" endpoint. +func MountApplyMajorUpgradeHandler(mux goahttp.Muxer, h http.Handler) { + f, ok := h.(http.HandlerFunc) + if !ok { + f = func(w http.ResponseWriter, r *http.Request) { + h.ServeHTTP(w, r) + } + } + mux.Handle("POST", "/v1/databases/{database_id}/upgrade-major", f) +} + +// NewApplyMajorUpgradeHandler creates a HTTP handler which loads the HTTP +// request and calls the "control-plane" service "apply-major-upgrade" endpoint. +func NewApplyMajorUpgradeHandler( + endpoint goa.Endpoint, + mux goahttp.Muxer, + decoder func(*http.Request) goahttp.Decoder, + encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, + errhandler func(context.Context, http.ResponseWriter, error), + formatter func(ctx context.Context, err error) goahttp.Statuser, +) http.Handler { + var ( + decodeRequest = DecodeApplyMajorUpgradeRequest(mux, decoder) + encodeResponse = EncodeApplyMajorUpgradeResponse(encoder) + encodeError = EncodeApplyMajorUpgradeError(encoder, formatter) + ) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := context.WithValue(r.Context(), goahttp.AcceptTypeKey, r.Header.Get("Accept")) + ctx = context.WithValue(ctx, goa.MethodKey, "apply-major-upgrade") + ctx = context.WithValue(ctx, goa.ServiceKey, "control-plane") + payload, err := decodeRequest(r) + if err != nil { + if err := encodeError(ctx, w, err); err != nil && errhandler != nil { + errhandler(ctx, w, err) + } + return + } + res, err := endpoint(ctx, payload) + if err != nil { + if err := encodeError(ctx, w, err); err != nil && errhandler != nil { + errhandler(ctx, w, err) + } + return + } + if err := encodeResponse(ctx, w, res); err != nil { + if errhandler != nil { + errhandler(ctx, w, err) + } + } + }) +} + // MountDeleteDatabaseHandler configures the mux to serve the "control-plane" // service "delete-database" endpoint. func MountDeleteDatabaseHandler(mux goahttp.Muxer, h http.Handler) { diff --git a/api/apiv1/gen/http/control_plane/server/types.go b/api/apiv1/gen/http/control_plane/server/types.go index a2ae600e..46c53e29 100644 --- a/api/apiv1/gen/http/control_plane/server/types.go +++ b/api/apiv1/gen/http/control_plane/server/types.go @@ -65,6 +65,24 @@ type ApplyUpgradeRequestBody struct { Image *string `json:"image"` } +// ApplyMajorUpgradeRequestBody is the type of the "control-plane" service +// "apply-major-upgrade" endpoint HTTP request body. +type ApplyMajorUpgradeRequestBody struct { + // The Spock major version to upgrade to. + TargetSpockVersion *string `json:"target_spock_version"` + // Full container image reference of the upgrade target. Must match the image + // field of a manifest entry whose spock_version is target_spock_version and + // whose postgres_version matches the database's current postgres_version. + // Unlike ApplyUpgradeRequest, the target entry is not required to have + // stability "stable" — a Spock major version is expected to still be in a + // "dev" stability window while this action is in use for it. + Image *string `json:"image"` + // Explicit order (by node name) in which nodes are upgraded, one at a time. + // Defaults to the order nodes appear in the database spec if omitted. Every + // node in the database must appear exactly once. + NodeOrder []string `json:"node_order,omitempty"` +} + // BackupDatabaseNodeRequestBody is the type of the "control-plane" service // "backup-database-node" endpoint HTTP request body. type BackupDatabaseNodeRequestBody struct { @@ -247,6 +265,15 @@ type ApplyUpgradeResponseBody struct { Database *DatabaseResponseBody `json:"database"` } +// ApplyMajorUpgradeResponseBody is the type of the "control-plane" service +// "apply-major-upgrade" endpoint HTTP response body. +type ApplyMajorUpgradeResponseBody struct { + // The task tracking the major-version upgrade operation. + Task *TaskResponseBody `json:"task"` + // The database being upgraded. + Database *DatabaseResponseBody `json:"database"` +} + // DeleteDatabaseResponseBody is the type of the "control-plane" service // "delete-database" endpoint HTTP response body. type DeleteDatabaseResponseBody struct { @@ -943,6 +970,66 @@ type ApplyUpgradeServerErrorResponseBody struct { Message string `json:"message"` } +// ApplyMajorUpgradeClusterNotInitializedResponseBody is the type of the +// "control-plane" service "apply-major-upgrade" endpoint HTTP response body +// for the "cluster_not_initialized" error. +type ApplyMajorUpgradeClusterNotInitializedResponseBody struct { + // The name of the error. + Name string `json:"name"` + // The error message. + Message string `json:"message"` +} + +// ApplyMajorUpgradeDatabaseNotModifiableResponseBody is the type of the +// "control-plane" service "apply-major-upgrade" endpoint HTTP response body +// for the "database_not_modifiable" error. +type ApplyMajorUpgradeDatabaseNotModifiableResponseBody struct { + // The name of the error. + Name string `json:"name"` + // The error message. + Message string `json:"message"` +} + +// ApplyMajorUpgradeOperationAlreadyInProgressResponseBody is the type of the +// "control-plane" service "apply-major-upgrade" endpoint HTTP response body +// for the "operation_already_in_progress" error. +type ApplyMajorUpgradeOperationAlreadyInProgressResponseBody struct { + // The name of the error. + Name string `json:"name"` + // The error message. + Message string `json:"message"` +} + +// ApplyMajorUpgradeInvalidInputResponseBody is the type of the "control-plane" +// service "apply-major-upgrade" endpoint HTTP response body for the +// "invalid_input" error. +type ApplyMajorUpgradeInvalidInputResponseBody struct { + // The name of the error. + Name string `json:"name"` + // The error message. + Message string `json:"message"` +} + +// ApplyMajorUpgradeNotFoundResponseBody is the type of the "control-plane" +// service "apply-major-upgrade" endpoint HTTP response body for the +// "not_found" error. +type ApplyMajorUpgradeNotFoundResponseBody struct { + // The name of the error. + Name string `json:"name"` + // The error message. + Message string `json:"message"` +} + +// ApplyMajorUpgradeServerErrorResponseBody is the type of the "control-plane" +// service "apply-major-upgrade" endpoint HTTP response body for the +// "server_error" error. +type ApplyMajorUpgradeServerErrorResponseBody struct { + // The name of the error. + Name string `json:"name"` + // The error message. + Message string `json:"message"` +} + // DeleteDatabaseClusterNotInitializedResponseBody is the type of the // "control-plane" service "delete-database" endpoint HTTP response body for // the "cluster_not_initialized" error. @@ -2047,6 +2134,13 @@ type DatabaseNodeSpecResponseBody struct { // The Postgres version for this node in 'major.minor' format. Overrides the // Postgres version set in the DatabaseSpec. PostgresVersion *string `json:"postgres_version,omitempty"` + // The major version of the Spock extension for this node. Overrides the Spock + // version set in the DatabaseSpec. Only settable through the dedicated + // major-version upgrade action — rejected on create-database and on the + // general update-database path, since a per-node major mismatch is only ever a + // deliberate, transient state during a rolling major-version upgrade, never a + // steady-state topology choice. + SpockVersion *string `json:"spock_version,omitempty"` // The port used by the Postgres database for this node. Overrides the Postgres // port set in the DatabaseSpec. Port *int `json:"port,omitempty"` @@ -2426,6 +2520,13 @@ type DatabaseNodeSpecRequestBody struct { // The Postgres version for this node in 'major.minor' format. Overrides the // Postgres version set in the DatabaseSpec. PostgresVersion *string `json:"postgres_version,omitempty"` + // The major version of the Spock extension for this node. Overrides the Spock + // version set in the DatabaseSpec. Only settable through the dedicated + // major-version upgrade action — rejected on create-database and on the + // general update-database path, since a per-node major mismatch is only ever a + // deliberate, transient state during a rolling major-version upgrade, never a + // steady-state topology choice. + SpockVersion *string `json:"spock_version,omitempty"` // The port used by the Postgres database for this node. Overrides the Postgres // port set in the DatabaseSpec. Port *int `json:"port,omitempty"` @@ -2794,6 +2895,13 @@ type DatabaseNodeSpecRequestBodyRequestBody struct { // The Postgres version for this node in 'major.minor' format. Overrides the // Postgres version set in the DatabaseSpec. PostgresVersion *string `json:"postgres_version,omitempty"` + // The major version of the Spock extension for this node. Overrides the Spock + // version set in the DatabaseSpec. Only settable through the dedicated + // major-version upgrade action — rejected on create-database and on the + // general update-database path, since a per-node major mismatch is only ever a + // deliberate, transient state during a rolling major-version upgrade, never a + // steady-state topology choice. + SpockVersion *string `json:"spock_version,omitempty"` // The port used by the Postgres database for this node. Overrides the Postgres // port set in the DatabaseSpec. Port *int `json:"port,omitempty"` @@ -3372,6 +3480,19 @@ func NewApplyUpgradeResponseBody(res *controlplane.ApplyUpgradeResponse) *ApplyU return body } +// NewApplyMajorUpgradeResponseBody builds the HTTP response body from the +// result of the "apply-major-upgrade" endpoint of the "control-plane" service. +func NewApplyMajorUpgradeResponseBody(res *controlplane.ApplyMajorUpgradeResponse) *ApplyMajorUpgradeResponseBody { + body := &ApplyMajorUpgradeResponseBody{} + if res.Task != nil { + body.Task = marshalControlplaneTaskToTaskResponseBody(res.Task) + } + if res.Database != nil { + body.Database = marshalControlplaneDatabaseToDatabaseResponseBody(res.Database) + } + return body +} + // NewDeleteDatabaseResponseBody builds the HTTP response body from the result // of the "delete-database" endpoint of the "control-plane" service. func NewDeleteDatabaseResponseBody(res *controlplane.DeleteDatabaseResponse) *DeleteDatabaseResponseBody { @@ -4152,6 +4273,72 @@ func NewApplyUpgradeServerErrorResponseBody(res *controlplane.APIError) *ApplyUp return body } +// NewApplyMajorUpgradeClusterNotInitializedResponseBody builds the HTTP +// response body from the result of the "apply-major-upgrade" endpoint of the +// "control-plane" service. +func NewApplyMajorUpgradeClusterNotInitializedResponseBody(res *controlplane.APIError) *ApplyMajorUpgradeClusterNotInitializedResponseBody { + body := &ApplyMajorUpgradeClusterNotInitializedResponseBody{ + Name: res.Name, + Message: res.Message, + } + return body +} + +// NewApplyMajorUpgradeDatabaseNotModifiableResponseBody builds the HTTP +// response body from the result of the "apply-major-upgrade" endpoint of the +// "control-plane" service. +func NewApplyMajorUpgradeDatabaseNotModifiableResponseBody(res *controlplane.APIError) *ApplyMajorUpgradeDatabaseNotModifiableResponseBody { + body := &ApplyMajorUpgradeDatabaseNotModifiableResponseBody{ + Name: res.Name, + Message: res.Message, + } + return body +} + +// NewApplyMajorUpgradeOperationAlreadyInProgressResponseBody builds the HTTP +// response body from the result of the "apply-major-upgrade" endpoint of the +// "control-plane" service. +func NewApplyMajorUpgradeOperationAlreadyInProgressResponseBody(res *controlplane.APIError) *ApplyMajorUpgradeOperationAlreadyInProgressResponseBody { + body := &ApplyMajorUpgradeOperationAlreadyInProgressResponseBody{ + Name: res.Name, + Message: res.Message, + } + return body +} + +// NewApplyMajorUpgradeInvalidInputResponseBody builds the HTTP response body +// from the result of the "apply-major-upgrade" endpoint of the "control-plane" +// service. +func NewApplyMajorUpgradeInvalidInputResponseBody(res *controlplane.APIError) *ApplyMajorUpgradeInvalidInputResponseBody { + body := &ApplyMajorUpgradeInvalidInputResponseBody{ + Name: res.Name, + Message: res.Message, + } + return body +} + +// NewApplyMajorUpgradeNotFoundResponseBody builds the HTTP response body from +// the result of the "apply-major-upgrade" endpoint of the "control-plane" +// service. +func NewApplyMajorUpgradeNotFoundResponseBody(res *controlplane.APIError) *ApplyMajorUpgradeNotFoundResponseBody { + body := &ApplyMajorUpgradeNotFoundResponseBody{ + Name: res.Name, + Message: res.Message, + } + return body +} + +// NewApplyMajorUpgradeServerErrorResponseBody builds the HTTP response body +// from the result of the "apply-major-upgrade" endpoint of the "control-plane" +// service. +func NewApplyMajorUpgradeServerErrorResponseBody(res *controlplane.APIError) *ApplyMajorUpgradeServerErrorResponseBody { + body := &ApplyMajorUpgradeServerErrorResponseBody{ + Name: res.Name, + Message: res.Message, + } + return body +} + // NewDeleteDatabaseClusterNotInitializedResponseBody builds the HTTP response // body from the result of the "delete-database" endpoint of the // "control-plane" service. @@ -5060,6 +5247,27 @@ func NewApplyUpgradePayload(body *ApplyUpgradeRequestBody, databaseID string) *c return res } +// NewApplyMajorUpgradePayload builds a control-plane service +// apply-major-upgrade endpoint payload. +func NewApplyMajorUpgradePayload(body *ApplyMajorUpgradeRequestBody, databaseID string) *controlplane.ApplyMajorUpgradePayload { + v := &controlplane.ApplyMajorUpgradeRequest{ + TargetSpockVersion: *body.TargetSpockVersion, + Image: *body.Image, + } + if body.NodeOrder != nil { + v.NodeOrder = make([]string, len(body.NodeOrder)) + for i, val := range body.NodeOrder { + v.NodeOrder[i] = val + } + } + res := &controlplane.ApplyMajorUpgradePayload{ + Request: v, + } + res.DatabaseID = controlplane.Identifier(databaseID) + + return res +} + // NewDeleteDatabasePayload builds a control-plane service delete-database // endpoint payload. func NewDeleteDatabasePayload(databaseID string, force bool) *controlplane.DeleteDatabasePayload { @@ -5407,6 +5615,26 @@ func ValidateApplyUpgradeRequestBody(body *ApplyUpgradeRequestBody) (err error) return } +// ValidateApplyMajorUpgradeRequestBody runs the validations defined on +// Apply-Major-UpgradeRequestBody +func ValidateApplyMajorUpgradeRequestBody(body *ApplyMajorUpgradeRequestBody) (err error) { + if body.TargetSpockVersion == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("target_spock_version", "body")) + } + if body.Image == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("image", "body")) + } + if body.TargetSpockVersion != nil { + err = goa.MergeErrors(err, goa.ValidatePattern("body.target_spock_version", *body.TargetSpockVersion, "^\\d{1}$")) + } + if body.Image != nil { + if utf8.RuneCountInString(*body.Image) < 1 { + err = goa.MergeErrors(err, goa.InvalidLengthError("body.image", *body.Image, utf8.RuneCountInString(*body.Image), 1, true)) + } + } + return +} + // ValidateBackupDatabaseNodeRequestBody runs the validations defined on // Backup-Database-NodeRequestBody func ValidateBackupDatabaseNodeRequestBody(body *BackupDatabaseNodeRequestBody) (err error) { @@ -5592,6 +5820,9 @@ func ValidateDatabaseNodeSpecRequestBody(body *DatabaseNodeSpecRequestBody) (err if body.PostgresVersion != nil { err = goa.MergeErrors(err, goa.ValidatePattern("body.postgres_version", *body.PostgresVersion, "^\\d{2}\\.\\d{1,2}$")) } + if body.SpockVersion != nil { + err = goa.MergeErrors(err, goa.ValidatePattern("body.spock_version", *body.SpockVersion, "^\\d{1}$")) + } if body.Port != nil { if *body.Port < 0 { err = goa.MergeErrors(err, goa.InvalidRangeError("body.port", *body.Port, 0, true)) @@ -6373,6 +6604,9 @@ func ValidateDatabaseNodeSpecRequestBodyRequestBody(body *DatabaseNodeSpecReques if body.PostgresVersion != nil { err = goa.MergeErrors(err, goa.ValidatePattern("body.postgres_version", *body.PostgresVersion, "^\\d{2}\\.\\d{1,2}$")) } + if body.SpockVersion != nil { + err = goa.MergeErrors(err, goa.ValidatePattern("body.spock_version", *body.SpockVersion, "^\\d{1}$")) + } if body.Port != nil { if *body.Port < 0 { err = goa.MergeErrors(err, goa.InvalidRangeError("body.port", *body.Port, 0, true)) diff --git a/api/apiv1/gen/http/openapi.json b/api/apiv1/gen/http/openapi.json index 954bfbae..da64afc7 100644 --- a/api/apiv1/gen/http/openapi.json +++ b/api/apiv1/gen/http/openapi.json @@ -1848,6 +1848,94 @@ ] } }, + "/v1/databases/{database_id}/upgrade-major": { + "post": { + "tags": [ + "Database" + ], + "summary": "Apply Spock major-version upgrade", + "description": "Applies a dedicated Spock major-version upgrade (e.g. 5.x to 6.x) to a database, rolling through each node one at a time rather than redeploying uniformly. Independent of apply-upgrade, which is restricted to same-major minor/patch bumps and cannot reach a different Spock major.", + "operationId": "control-plane#apply-major-upgrade", + "parameters": [ + { + "name": "database_id", + "in": "path", + "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", + "required": true, + "type": "string" + }, + { + "name": "Apply-Major-UpgradeRequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ApplyMajorUpgradeRequest" + } + } + ], + "responses": { + "200": { + "description": "OK response.", + "schema": { + "$ref": "#/definitions/ApplyMajorUpgradeResponse", + "required": [ + "task", + "database" + ] + } + }, + "400": { + "description": "Bad Request response.", + "schema": { + "$ref": "#/definitions/APIError", + "required": [ + "name", + "message" + ] + } + }, + "404": { + "description": "Not Found response.", + "schema": { + "$ref": "#/definitions/APIError", + "required": [ + "name", + "message" + ] + } + }, + "409": { + "description": "Conflict response.", + "schema": { + "$ref": "#/definitions/APIError", + "required": [ + "name", + "message" + ] + } + }, + "500": { + "description": "Internal Server Error response.", + "schema": { + "$ref": "#/definitions/APIError", + "required": [ + "name", + "message" + ] + } + }, + "default": { + "description": "Unexpected error response", + "schema": { + "$ref": "#/definitions/APIError" + } + } + }, + "schemes": [ + "http" + ] + } + }, "/v1/hosts": { "get": { "tags": [ @@ -2554,6 +2642,234 @@ "message" ] }, + "ApplyMajorUpgradeRequest": { + "title": "ApplyMajorUpgradeRequest", + "type": "object", + "properties": { + "image": { + "type": "string", + "description": "Full container image reference of the upgrade target. Must match the image field of a manifest entry whose spock_version is target_spock_version and whose postgres_version matches the database's current postgres_version. Unlike ApplyUpgradeRequest, the target entry is not required to have stability \"stable\" — a Spock major version is expected to still be in a \"dev\" stability window while this action is in use for it.", + "example": "ghcr.io/pgedge/pgedge-postgres:18.4-spock6.0.0-standard-1", + "minLength": 1 + }, + "node_order": { + "type": "array", + "items": { + "type": "string", + "example": "Explicabo culpa eos natus aperiam excepturi consectetur." + }, + "description": "Explicit order (by node name) in which nodes are upgraded, one at a time. Defaults to the order nodes appear in the database spec if omitted. Every node in the database must appear exactly once.", + "example": [ + "n2", + "n1", + "n3" + ] + }, + "target_spock_version": { + "type": "string", + "description": "The Spock major version to upgrade to.", + "example": "6", + "pattern": "^\\d{1}$" + } + }, + "description": "Request to upgrade a database across a Spock major version boundary (e.g. 5.x to 6.x). Deliberately separate from ApplyUpgradeRequest: a major-version bump changes replication protocol behavior and is executed one node at a time (rolling), not redeployed uniformly like a minor/patch bump.", + "example": { + "image": "ghcr.io/pgedge/pgedge-postgres:18.4-spock6.0.0-standard-1", + "node_order": [ + "n2", + "n1", + "n3" + ], + "target_spock_version": "6" + }, + "required": [ + "target_spock_version", + "image" + ] + }, + "ApplyMajorUpgradeResponse": { + "title": "ApplyMajorUpgradeResponse", + "type": "object", + "properties": { + "database": { + "$ref": "#/definitions/Database" + }, + "task": { + "$ref": "#/definitions/Task" + } + }, + "example": { + "database": { + "created_at": "2025-06-18T16:52:05Z", + "id": "storefront", + "instances": [ + { + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2025-06-18T16:52:22Z", + "host_id": "us-east-1", + "id": "storefront-n1-689qacsi", + "node_name": "n1", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n1n3", + "provider_node": "n3", + "status": "replicating" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "replicating" + } + ], + "version": "4.0.10" + }, + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:36Z" + }, + { + "connection_info": { + "addresses": [ + "10.24.35.2", + "i-058731542fee493f.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2025-06-18T16:52:22Z", + "host_id": "ap-south-1", + "id": "storefront-n2-9ptayhma", + "node_name": "n2", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n2n1", + "provider_node": "n1", + "status": "replicating" + }, + { + "name": "sub_n2n3", + "provider_node": "n3", + "status": "replicating" + } + ], + "version": "4.0.10" + }, + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:01Z" + }, + { + "connection_info": { + "addresses": [ + "10.24.36.2", + "i-494027b7b53f6a23.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2025-06-18T16:52:22Z", + "host_id": "eu-central-1", + "id": "storefront-n3-ant97dj4", + "node_name": "n3", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n3n1", + "provider_node": "n1", + "status": "replicating" + }, + { + "name": "sub_n3n2", + "provider_node": "n2", + "status": "replicating" + } + ], + "version": "4.0.10" + }, + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:01Z" + } + ], + "spec": { + "database_name": "storefront", + "database_users": [ + { + "attributes": [ + "SUPERUSER", + "LOGIN" + ], + "db_owner": true, + "username": "admin" + } + ], + "nodes": [ + { + "host_ids": [ + "us-east-1" + ], + "name": "n1" + }, + { + "host_ids": [ + "ap-south-1" + ], + "name": "n2" + }, + { + "host_ids": [ + "eu-central-1" + ], + "name": "n3" + } + ], + "port": 5432, + "postgres_version": "17.6", + "spock_version": "5" + }, + "state": "restoring", + "updated_at": "2025-06-18T17:58:59Z" + }, + "task": { + "completed_at": "2025-06-18T16:52:35Z", + "created_at": "2025-06-18T16:52:05Z", + "database_id": "storefront", + "entity_id": "storefront", + "scope": "database", + "status": "completed", + "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", + "type": "create" + } + }, + "required": [ + "task", + "database" + ] + }, "ApplyUpgradeRequest": { "title": "ApplyUpgradeRequest", "type": "object", @@ -2871,7 +3187,7 @@ }, "additionalProperties": { "type": "string", - "example": "Explicabo culpa eos natus aperiam excepturi consectetur." + "example": "Ut aperiam." } }, "backup_options": { @@ -2882,7 +3198,7 @@ }, "additionalProperties": { "type": "string", - "example": "Ut aperiam." + "example": "Sed quis architecto magnam temporibus ipsa et." } }, "type": { @@ -4283,6 +4599,12 @@ "type": "string", "description": "The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node.", "example": "n1" + }, + "spock_version": { + "type": "string", + "description": "The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice.", + "example": "6", + "pattern": "^\\d{1}$" } }, "example": { @@ -4456,7 +4778,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, "required": [ "name", @@ -4770,7 +5093,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, { "backup_config": { @@ -4945,7 +5269,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, { "backup_config": { @@ -5120,7 +5445,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" } ], "minItems": 1, @@ -5651,7 +5977,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, { "backup_config": { @@ -5826,7 +6153,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" } ], "orchestrator_opts": { @@ -8627,7 +8955,7 @@ "type": "array", "items": { "type": "string", - "example": "Et reprehenderit et nam quo qui." + "example": "Qui veniam exercitationem." }, "description": "The nodes to restore. Defaults to all nodes if empty or unspecified.", "example": [ @@ -9750,22 +10078,6 @@ }, "description": "Entries in the task log.", "example": [ - { - "fields": { - "option.enabled": true, - "status": "creating" - }, - "message": "task started", - "timestamp": "2025-05-29T15:43:13Z" - }, - { - "fields": { - "option.enabled": true, - "status": "creating" - }, - "message": "task started", - "timestamp": "2025-05-29T15:43:13Z" - }, { "fields": { "option.enabled": true, diff --git a/api/apiv1/gen/http/openapi.yaml b/api/apiv1/gen/http/openapi.yaml index 099fe3a6..5c310cf1 100644 --- a/api/apiv1/gen/http/openapi.yaml +++ b/api/apiv1/gen/http/openapi.yaml @@ -1282,6 +1282,66 @@ paths: $ref: '#/definitions/APIError' schemes: - http + /v1/databases/{database_id}/upgrade-major: + post: + tags: + - Database + summary: Apply Spock major-version upgrade + description: Applies a dedicated Spock major-version upgrade (e.g. 5.x to 6.x) to a database, rolling through each node one at a time rather than redeploying uniformly. Independent of apply-upgrade, which is restricted to same-major minor/patch bumps and cannot reach a different Spock major. + operationId: control-plane#apply-major-upgrade + parameters: + - name: database_id + in: path + description: A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens. + required: true + type: string + - name: Apply-Major-UpgradeRequestBody + in: body + required: true + schema: + $ref: '#/definitions/ApplyMajorUpgradeRequest' + responses: + "200": + description: OK response. + schema: + $ref: '#/definitions/ApplyMajorUpgradeResponse' + required: + - task + - database + "400": + description: Bad Request response. + schema: + $ref: '#/definitions/APIError' + required: + - name + - message + "404": + description: Not Found response. + schema: + $ref: '#/definitions/APIError' + required: + - name + - message + "409": + description: Conflict response. + schema: + $ref: '#/definitions/APIError' + required: + - name + - message + "500": + description: Internal Server Error response. + schema: + $ref: '#/definitions/APIError' + required: + - name + - message + default: + description: Unexpected error response + schema: + $ref: '#/definitions/APIError' + schemes: + - http /v1/hosts: get: tags: @@ -1779,6 +1839,167 @@ definitions: required: - name - message + ApplyMajorUpgradeRequest: + title: ApplyMajorUpgradeRequest + type: object + properties: + image: + type: string + description: Full container image reference of the upgrade target. Must match the image field of a manifest entry whose spock_version is target_spock_version and whose postgres_version matches the database's current postgres_version. Unlike ApplyUpgradeRequest, the target entry is not required to have stability "stable" — a Spock major version is expected to still be in a "dev" stability window while this action is in use for it. + example: ghcr.io/pgedge/pgedge-postgres:18.4-spock6.0.0-standard-1 + minLength: 1 + node_order: + type: array + items: + type: string + example: Explicabo culpa eos natus aperiam excepturi consectetur. + description: Explicit order (by node name) in which nodes are upgraded, one at a time. Defaults to the order nodes appear in the database spec if omitted. Every node in the database must appear exactly once. + example: + - n2 + - n1 + - n3 + target_spock_version: + type: string + description: The Spock major version to upgrade to. + example: "6" + pattern: ^\d{1}$ + description: 'Request to upgrade a database across a Spock major version boundary (e.g. 5.x to 6.x). Deliberately separate from ApplyUpgradeRequest: a major-version bump changes replication protocol behavior and is executed one node at a time (rolling), not redeployed uniformly like a minor/patch bump.' + example: + image: ghcr.io/pgedge/pgedge-postgres:18.4-spock6.0.0-standard-1 + node_order: + - n2 + - n1 + - n3 + target_spock_version: "6" + required: + - target_spock_version + - image + ApplyMajorUpgradeResponse: + title: ApplyMajorUpgradeResponse + type: object + properties: + database: + $ref: '#/definitions/Database' + task: + $ref: '#/definitions/Task' + example: + database: + created_at: "2025-06-18T16:52:05Z" + id: storefront + instances: + - connection_info: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + port: 5432 + created_at: "2025-06-18T16:52:22Z" + host_id: us-east-1 + id: storefront-n1-689qacsi + node_name: n1 + postgres: + patroni_state: running + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n1n3 + provider_node: n3 + status: replicating + - name: sub_n1n2 + provider_node: n2 + status: replicating + version: 4.0.10 + state: available + status_updated_at: "2025-06-18T17:58:56Z" + updated_at: "2025-06-18T17:54:36Z" + - connection_info: + addresses: + - 10.24.35.2 + - i-058731542fee493f.ec2.internal + port: 5432 + created_at: "2025-06-18T16:52:22Z" + host_id: ap-south-1 + id: storefront-n2-9ptayhma + node_name: n2 + postgres: + patroni_state: running + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n2n1 + provider_node: n1 + status: replicating + - name: sub_n2n3 + provider_node: n3 + status: replicating + version: 4.0.10 + state: available + status_updated_at: "2025-06-18T17:58:56Z" + updated_at: "2025-06-18T17:54:01Z" + - connection_info: + addresses: + - 10.24.36.2 + - i-494027b7b53f6a23.ec2.internal + port: 5432 + created_at: "2025-06-18T16:52:22Z" + host_id: eu-central-1 + id: storefront-n3-ant97dj4 + node_name: n3 + postgres: + patroni_state: running + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n3n1 + provider_node: n1 + status: replicating + - name: sub_n3n2 + provider_node: n2 + status: replicating + version: 4.0.10 + state: available + status_updated_at: "2025-06-18T17:58:56Z" + updated_at: "2025-06-18T17:54:01Z" + spec: + database_name: storefront + database_users: + - attributes: + - SUPERUSER + - LOGIN + db_owner: true + username: admin + nodes: + - host_ids: + - us-east-1 + name: n1 + - host_ids: + - ap-south-1 + name: n2 + - host_ids: + - eu-central-1 + name: n3 + port: 5432 + postgres_version: "17.6" + spock_version: "5" + state: restoring + updated_at: "2025-06-18T17:58:59Z" + task: + completed_at: "2025-06-18T16:52:35Z" + created_at: "2025-06-18T16:52:05Z" + database_id: storefront + entity_id: storefront + scope: database + status: completed + task_id: 019783f4-75f4-71e7-85a3-c9b96b345d77 + type: create + required: + - task + - database ApplyUpgradeRequest: title: ApplyUpgradeRequest type: object @@ -2027,7 +2248,7 @@ definitions: key: value additionalProperties: type: string - example: Explicabo culpa eos natus aperiam excepturi consectetur. + example: Ut aperiam. backup_options: type: object description: Options for the backup. @@ -2035,7 +2256,7 @@ definitions: archive-check: "n" additionalProperties: type: string - example: Ut aperiam. + example: Sed quis architecto magnam temporibus ipsa et. type: type: string description: The type of backup. @@ -3051,6 +3272,11 @@ definitions: type: string description: The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node. example: n1 + spock_version: + type: string + description: The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice. + example: "6" + pattern: ^\d{1}$ example: backup_config: repositories: @@ -3177,6 +3403,7 @@ definitions: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" required: - name - host_ids @@ -3410,6 +3637,7 @@ definitions: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" - backup_config: repositories: - azure_account: pgedge-backups @@ -3537,6 +3765,7 @@ definitions: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" - backup_config: repositories: - azure_account: pgedge-backups @@ -3664,6 +3893,7 @@ definitions: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" minItems: 1 maxItems: 9 orchestrator_opts: @@ -4040,6 +4270,7 @@ definitions: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" - backup_config: repositories: - azure_account: pgedge-backups @@ -4167,6 +4398,7 @@ definitions: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" orchestrator_opts: swarm: extra_labels: @@ -6165,7 +6397,7 @@ definitions: type: array items: type: string - example: Et reprehenderit et nam quo qui. + example: Qui veniam exercitationem. description: The nodes to restore. Defaults to all nodes if empty or unspecified. example: - n1 @@ -7004,16 +7236,6 @@ definitions: status: creating message: task started timestamp: "2025-05-29T15:43:13Z" - - fields: - option.enabled: true - status: creating - message: task started - timestamp: "2025-05-29T15:43:13Z" - - fields: - option.enabled: true - status: creating - message: task started - timestamp: "2025-05-29T15:43:13Z" last_entry_id: type: string description: The ID of the last entry in the task log. diff --git a/api/apiv1/gen/http/openapi3.json b/api/apiv1/gen/http/openapi3.json index b5f30f49..3f4b7c84 100644 --- a/api/apiv1/gen/http/openapi3.json +++ b/api/apiv1/gen/http/openapi3.json @@ -518,7 +518,7 @@ "type": "array", "items": { "type": "string", - "example": "Tempora laboriosam aut." + "example": "Qui dolores quibusdam." }, "description": "Optional fields to include in each database response. Supported values: available_upgrades.", "example": [ @@ -1498,7 +1498,7 @@ "type": "array", "items": { "type": "string", - "example": "Est dolor consequatur." + "example": "Repellat recusandae sequi." }, "description": "Optional fields to include in the response. Supported values: available_upgrades.", "example": [ @@ -1792,20 +1792,19 @@ "type": "array", "items": { "type": "string", - "example": "Illo delectus dolorum." + "example": "Aspernatur libero nihil sunt ut dicta." }, "description": "Host IDs to treat as removed during this update. Events targeting these hosts will be skipped.", "example": [ - "Aut aut veritatis ut nulla.", - "Earum distinctio qui qui dolores quibusdam officiis.", - "Recusandae sequi vel aspernatur libero nihil sunt." + "Maiores minima.", + "Qui sit.", + "Autem explicabo nemo et architecto qui." ] }, "example": [ - "Quasi quo maiores minima velit.", - "Sit rerum autem explicabo nemo et architecto.", - "In cum enim est.", - "Repudiandae in quis eum." + "Enim est enim repudiandae in.", + "Eum quasi aspernatur cum quod sed id.", + "Rerum quo autem facere incidunt asperiores." ] }, { @@ -4340,260 +4339,213 @@ } } }, - "/v1/hosts": { - "get": { + "/v1/databases/{database_id}/upgrade-major": { + "post": { "tags": [ - "Host" + "Database" ], - "summary": "List hosts", - "description": "Lists all hosts within the cluster.", - "operationId": "list-hosts", + "summary": "Apply Spock major-version upgrade", + "description": "Applies a dedicated Spock major-version upgrade (e.g. 5.x to 6.x) to a database, rolling through each node one at a time rather than redeploying uniformly. Independent of apply-upgrade, which is restricted to same-major minor/patch bumps and cannot reach a different Spock major.", + "operationId": "apply-major-upgrade", + "parameters": [ + { + "name": "database_id", + "in": "path", + "description": "ID of the database to upgrade.", + "required": true, + "schema": { + "type": "string", + "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 + }, + "example": "my-app" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplyMajorUpgradeRequest" + }, + "example": { + "image": "ghcr.io/pgedge/pgedge-postgres:18.4-spock6.0.0-standard-1", + "node_order": [ + "n2", + "n1", + "n3" + ], + "target_spock_version": "6" + } + } + } + }, "responses": { "200": { "description": "OK response.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ListHostsResponse" + "$ref": "#/components/schemas/ApplyMajorUpgradeResponse2" }, - "examples": { - "default": { - "summary": "default", - "value": { - "hosts": [ - { - "client_addresses": [ - "10.24.34.2", - "i-0123456789abcdef.ec2.internal" - ], - "cohort": { - "cohort_id": "zdjfu3tfxg1cihv3146ro3hy2", - "control_available": true, - "member_id": "lah4bsznw6kc0hp7biylmmmll", - "type": "swarm" - }, - "cpus": 16, - "data_dir": "/data", - "default_pgedge_version": { - "postgres_version": "17.6", - "spock_version": "5" - }, - "etcd_mode": "server", - "id": "us-east-1", - "memory": "16GB", - "orchestrator": "swarm", - "peer_addresses": [ + "example": { + "database": { + "created_at": "2025-06-18T16:52:05Z", + "id": "storefront", + "instances": [ + { + "connection_info": { + "addresses": [ "10.24.34.2", "i-0123456789abcdef.ec2.internal" ], - "status": { - "components": {}, - "state": "healthy", - "updated_at": "2025-06-17T00:00:00Z" - }, - "supported_pgedge_versions": [ - { - "postgres_version": "17.6", - "spock_version": "5" - }, + "port": 5432 + }, + "created_at": "2025-06-18T16:52:22Z", + "host_id": "us-east-1", + "id": "storefront-n1-689qacsi", + "node_name": "n1", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ { - "postgres_version": "18.1", - "spock_version": "5" + "name": "sub_n1n3", + "provider_node": "n3", + "status": "replicating" }, { - "postgres_version": "16.10", - "spock_version": "5" + "name": "sub_n1n2", + "provider_node": "n2", + "status": "replicating" } - ] - }, - { - "client_addresses": [ - "10.24.35.2", - "i-058731542fee493f.ec2.internal" ], - "cohort": { - "cohort_id": "zdjfu3tfxg1cihv3146ro3hy2", - "control_available": true, - "member_id": "cb88u9jael2psnepep5iuzb4r", - "type": "swarm" - }, - "cpus": 16, - "data_dir": "/data", - "default_pgedge_version": { - "postgres_version": "17.6", - "spock_version": "5" - }, - "etcd_mode": "server", - "id": "ap-south-1", - "memory": "16GB", - "orchestrator": "swarm", - "peer_addresses": [ + "version": "4.0.10" + }, + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:36Z" + }, + { + "connection_info": { + "addresses": [ "10.24.35.2", "i-058731542fee493f.ec2.internal" ], - "status": { - "components": {}, - "state": "healthy", - "updated_at": "2025-06-17T00:00:00Z" - }, - "supported_pgedge_versions": [ - { - "postgres_version": "17.6", - "spock_version": "5" - }, + "port": 5432 + }, + "created_at": "2025-06-18T16:52:22Z", + "host_id": "ap-south-1", + "id": "storefront-n2-9ptayhma", + "node_name": "n2", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ { - "postgres_version": "18.1", - "spock_version": "5" + "name": "sub_n2n1", + "provider_node": "n1", + "status": "replicating" }, { - "postgres_version": "16.10", - "spock_version": "5" + "name": "sub_n2n3", + "provider_node": "n3", + "status": "replicating" } - ] - }, - { - "client_addresses": [ - "10.24.36.2", - "i-494027b7b53f6a23.ec2.internal" ], - "cohort": { - "cohort_id": "zdjfu3tfxg1cihv3146ro3hy2", - "control_available": true, - "member_id": "u7u9i3nhqunxc4wj577l6ecb0", - "type": "swarm" - }, - "cpus": 16, - "data_dir": "/data", - "default_pgedge_version": { - "postgres_version": "17.6", - "spock_version": "5" - }, - "etcd_mode": "client", - "id": "eu-central-1", - "memory": "16GB", - "orchestrator": "swarm", - "peer_addresses": [ + "version": "4.0.10" + }, + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:01Z" + }, + { + "connection_info": { + "addresses": [ "10.24.36.2", "i-494027b7b53f6a23.ec2.internal" ], - "status": { - "components": {}, - "state": "healthy", - "updated_at": "2025-06-17T00:00:00Z" - }, - "supported_pgedge_versions": [ - { - "postgres_version": "17.6", - "spock_version": "5" - }, + "port": 5432 + }, + "created_at": "2025-06-18T16:52:22Z", + "host_id": "eu-central-1", + "id": "storefront-n3-ant97dj4", + "node_name": "n3", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ { - "postgres_version": "18.1", - "spock_version": "5" + "name": "sub_n3n1", + "provider_node": "n1", + "status": "replicating" }, { - "postgres_version": "16.10", - "spock_version": "5" + "name": "sub_n3n2", + "provider_node": "n2", + "status": "replicating" } - ] - } - ] - } - } - } - } - } - }, - "409": { - "description": "cluster_not_initialized: Conflict response.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIError" - }, - "example": { - "message": "A longer description of the error.", - "name": "error_name" - } - } - } - }, - "500": { - "description": "server_error: Internal Server Error response.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIError" - }, - "example": { - "message": "A longer description of the error.", - "name": "error_name" - } - } - } - }, - "default": { - "description": "Unexpected error response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIError" - }, - "example": { - "message": "A longer description of the error.", - "name": "error_name" - } - } - } - } - } - } - }, - "/v1/hosts/{host_id}": { - "delete": { - "tags": [ - "Host" - ], - "summary": "Remove host", - "description": "Removes a host from the cluster.", - "operationId": "remove-host", - "parameters": [ - { - "name": "force", - "in": "query", - "description": "Force removal even if instances exist or quorum would be violated. Use only for disaster recovery when a host is permanently lost. ", - "allowEmptyValue": true, - "schema": { - "type": "boolean", - "description": "Force removal even if instances exist or quorum would be violated. Use only for disaster recovery when a host is permanently lost. ", - "default": false, - "example": true - }, - "example": true - }, - { - "name": "host_id", - "in": "path", - "description": "ID of the host to remove.", - "required": true, - "schema": { - "type": "string", - "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", - "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "minLength": 1, - "maxLength": 36 - }, - "example": "host-1" - } - ], - "responses": { - "200": { - "description": "OK response.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RemoveHostResponse" - }, - "example": { + ], + "version": "4.0.10" + }, + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:01Z" + } + ], + "spec": { + "database_name": "storefront", + "database_users": [ + { + "attributes": [ + "SUPERUSER", + "LOGIN" + ], + "db_owner": true, + "username": "admin" + } + ], + "nodes": [ + { + "host_ids": [ + "us-east-1" + ], + "name": "n1" + }, + { + "host_ids": [ + "ap-south-1" + ], + "name": "n2" + }, + { + "host_ids": [ + "eu-central-1" + ], + "name": "n3" + } + ], + "port": 5432, + "postgres_version": "17.6", + "spock_version": "5" + }, + "state": "restoring", + "updated_at": "2025-06-18T17:58:59Z" + }, "task": { "completed_at": "2025-06-18T16:52:35Z", "created_at": "2025-06-18T16:52:05Z", @@ -4603,49 +4555,7 @@ "status": "completed", "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", "type": "create" - }, - "update_database_tasks": [ - { - "completed_at": "2025-06-18T16:52:35Z", - "created_at": "2025-06-18T16:52:05Z", - "database_id": "storefront", - "entity_id": "storefront", - "scope": "database", - "status": "completed", - "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", - "type": "create" - }, - { - "completed_at": "2025-06-18T16:52:35Z", - "created_at": "2025-06-18T16:52:05Z", - "database_id": "storefront", - "entity_id": "storefront", - "scope": "database", - "status": "completed", - "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", - "type": "create" - }, - { - "completed_at": "2025-06-18T16:52:35Z", - "created_at": "2025-06-18T16:52:05Z", - "database_id": "storefront", - "entity_id": "storefront", - "scope": "database", - "status": "completed", - "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", - "type": "create" - }, - { - "completed_at": "2025-06-18T16:52:35Z", - "created_at": "2025-06-18T16:52:05Z", - "database_id": "storefront", - "entity_id": "storefront", - "scope": "database", - "status": "completed", - "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", - "type": "create" - } - ] + } } } } @@ -4679,7 +4589,7 @@ } }, "409": { - "description": "cluster_not_initialized: Conflict response.", + "description": "operation_already_in_progress: Conflict response.", "content": { "application/json": { "schema": { @@ -4721,115 +4631,167 @@ } } } - }, + } + }, + "/v1/hosts": { "get": { "tags": [ "Host" ], - "summary": "Get host", - "description": "Returns information about a particular host in the cluster.", - "operationId": "get-host", - "parameters": [ - { - "name": "host_id", - "in": "path", - "description": "ID of the host to get.", - "required": true, - "schema": { - "type": "string", - "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", - "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "minLength": 1, - "maxLength": 36 - }, - "example": "host-1" - } - ], + "summary": "List hosts", + "description": "Lists all hosts within the cluster.", + "operationId": "list-hosts", "responses": { "200": { "description": "OK response.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Host" + "$ref": "#/components/schemas/ListHostsResponse" }, - "example": { - "client_addresses": [ - "10.24.34.2", - "i-0123456789abcdef.ec2.internal" - ], - "cohort": { - "control_available": true, - "member_id": "lah4bsznw6kc0hp7biylmmmll", - "type": "swarm" - }, - "cpus": 4, - "data_dir": "/data", - "default_pgedge_version": { - "postgres_version": "17.6", - "spock_version": "5" - }, - "etcd_mode": "server", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "memory": "16GiB", - "orchestrator": "swarm", - "peer_addresses": [ - "10.24.34.2", - "i-0123456789abcdef.ec2.internal" - ], - "status": { - "components": { - "Id dolorem rerum labore commodi.": { - "details": { - "alarms": [ - "3: NOSPACE" - ] - }, - "error": "failed to connect to etcd", - "healthy": false - } - }, - "state": "available", - "updated_at": "2021-07-01T12:34:56Z" - }, - "supported_pgedge_versions": [ - { - "postgres_version": "17.6", - "spock_version": "5" - }, - { - "postgres_version": "17.6", - "spock_version": "5" - } - ] - } - } - } - }, - "400": { - "description": "invalid_input: Bad Request response.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIError" - }, - "example": { - "message": "A longer description of the error.", - "name": "error_name" - } - } - } - }, - "404": { - "description": "not_found: Not Found response.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIError" - }, - "example": { - "message": "A longer description of the error.", - "name": "error_name" + "examples": { + "default": { + "summary": "default", + "value": { + "hosts": [ + { + "client_addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "cohort": { + "cohort_id": "zdjfu3tfxg1cihv3146ro3hy2", + "control_available": true, + "member_id": "lah4bsznw6kc0hp7biylmmmll", + "type": "swarm" + }, + "cpus": 16, + "data_dir": "/data", + "default_pgedge_version": { + "postgres_version": "17.6", + "spock_version": "5" + }, + "etcd_mode": "server", + "id": "us-east-1", + "memory": "16GB", + "orchestrator": "swarm", + "peer_addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "status": { + "components": {}, + "state": "healthy", + "updated_at": "2025-06-17T00:00:00Z" + }, + "supported_pgedge_versions": [ + { + "postgres_version": "17.6", + "spock_version": "5" + }, + { + "postgres_version": "18.1", + "spock_version": "5" + }, + { + "postgres_version": "16.10", + "spock_version": "5" + } + ] + }, + { + "client_addresses": [ + "10.24.35.2", + "i-058731542fee493f.ec2.internal" + ], + "cohort": { + "cohort_id": "zdjfu3tfxg1cihv3146ro3hy2", + "control_available": true, + "member_id": "cb88u9jael2psnepep5iuzb4r", + "type": "swarm" + }, + "cpus": 16, + "data_dir": "/data", + "default_pgedge_version": { + "postgres_version": "17.6", + "spock_version": "5" + }, + "etcd_mode": "server", + "id": "ap-south-1", + "memory": "16GB", + "orchestrator": "swarm", + "peer_addresses": [ + "10.24.35.2", + "i-058731542fee493f.ec2.internal" + ], + "status": { + "components": {}, + "state": "healthy", + "updated_at": "2025-06-17T00:00:00Z" + }, + "supported_pgedge_versions": [ + { + "postgres_version": "17.6", + "spock_version": "5" + }, + { + "postgres_version": "18.1", + "spock_version": "5" + }, + { + "postgres_version": "16.10", + "spock_version": "5" + } + ] + }, + { + "client_addresses": [ + "10.24.36.2", + "i-494027b7b53f6a23.ec2.internal" + ], + "cohort": { + "cohort_id": "zdjfu3tfxg1cihv3146ro3hy2", + "control_available": true, + "member_id": "u7u9i3nhqunxc4wj577l6ecb0", + "type": "swarm" + }, + "cpus": 16, + "data_dir": "/data", + "default_pgedge_version": { + "postgres_version": "17.6", + "spock_version": "5" + }, + "etcd_mode": "client", + "id": "eu-central-1", + "memory": "16GB", + "orchestrator": "swarm", + "peer_addresses": [ + "10.24.36.2", + "i-494027b7b53f6a23.ec2.internal" + ], + "status": { + "components": {}, + "state": "healthy", + "updated_at": "2025-06-17T00:00:00Z" + }, + "supported_pgedge_versions": [ + { + "postgres_version": "17.6", + "spock_version": "5" + }, + { + "postgres_version": "18.1", + "spock_version": "5" + }, + { + "postgres_version": "16.10", + "spock_version": "5" + } + ] + } + ] + } + } } } } @@ -4879,65 +4841,32 @@ } } }, - "/v1/hosts/{host_id}/tasks": { - "get": { + "/v1/hosts/{host_id}": { + "delete": { "tags": [ "Host" ], - "summary": "List host tasks", - "description": "Lists all tasks for a host.", - "operationId": "list-host-tasks", + "summary": "Remove host", + "description": "Removes a host from the cluster.", + "operationId": "remove-host", "parameters": [ { - "name": "after_task_id", - "in": "query", - "description": "ID of the task to start from.", - "allowEmptyValue": true, - "schema": { - "type": "string", - "description": "ID of the task to start from.", - "example": "3c875a27-f6a6-4c1c-ba5f-6972fb1fc348", - "format": "uuid" - }, - "example": "3c875a27-f6a6-4c1c-ba5f-6972fb1fc348" - }, - { - "name": "limit", - "in": "query", - "description": "Maximum number of tasks to return.", - "allowEmptyValue": true, - "schema": { - "type": "integer", - "description": "Maximum number of tasks to return.", - "example": 100, - "format": "int64" - }, - "example": 100 - }, - { - "name": "sort_order", + "name": "force", "in": "query", - "description": "Sort order for the tasks.", + "description": "Force removal even if instances exist or quorum would be violated. Use only for disaster recovery when a host is permanently lost. ", "allowEmptyValue": true, "schema": { - "type": "string", - "description": "Sort order for the tasks.", - "example": "ascend", - "enum": [ - "asc", - "ascend", - "ascending", - "desc", - "descend", - "descending" - ] + "type": "boolean", + "description": "Force removal even if instances exist or quorum would be violated. Use only for disaster recovery when a host is permanently lost. ", + "default": false, + "example": true }, - "example": "ascend" + "example": true }, { "name": "host_id", "in": "path", - "description": "ID of the host to list tasks for.", + "description": "ID of the host to remove.", "required": true, "schema": { "type": "string", @@ -4955,22 +4884,62 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ListHostTasksResponse" + "$ref": "#/components/schemas/RemoveHostResponse" }, "example": { - "tasks": [ + "task": { + "completed_at": "2025-06-18T16:52:35Z", + "created_at": "2025-06-18T16:52:05Z", + "database_id": "storefront", + "entity_id": "storefront", + "scope": "database", + "status": "completed", + "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", + "type": "create" + }, + "update_database_tasks": [ { - "completed_at": "2025-06-18T17:54:36Z", - "created_at": "2025-06-18T17:54:28Z", - "entity_id": "host-1", - "host_id": "host-1", - "scope": "host", + "completed_at": "2025-06-18T16:52:35Z", + "created_at": "2025-06-18T16:52:05Z", + "database_id": "storefront", + "entity_id": "storefront", + "scope": "database", "status": "completed", - "task_id": "0197842d-9082-7496-b787-77bd2e11809f", - "type": "remove_host" - } - ] - } + "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", + "type": "create" + }, + { + "completed_at": "2025-06-18T16:52:35Z", + "created_at": "2025-06-18T16:52:05Z", + "database_id": "storefront", + "entity_id": "storefront", + "scope": "database", + "status": "completed", + "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", + "type": "create" + }, + { + "completed_at": "2025-06-18T16:52:35Z", + "created_at": "2025-06-18T16:52:05Z", + "database_id": "storefront", + "entity_id": "storefront", + "scope": "database", + "status": "completed", + "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", + "type": "create" + }, + { + "completed_at": "2025-06-18T16:52:35Z", + "created_at": "2025-06-18T16:52:05Z", + "database_id": "storefront", + "entity_id": "storefront", + "scope": "database", + "status": "completed", + "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", + "type": "create" + } + ] + } } } }, @@ -5045,21 +5014,19 @@ } } } - } - }, - "/v1/hosts/{host_id}/tasks/{task_id}": { + }, "get": { "tags": [ "Host" ], - "summary": "Get host task", - "description": "Returns information about a particular task for a host.", - "operationId": "get-host-task", + "summary": "Get host", + "description": "Returns information about a particular host in the cluster.", + "operationId": "get-host", "parameters": [ { "name": "host_id", "in": "path", - "description": "ID of the host the task belongs to.", + "description": "ID of the host to get.", "required": true, "schema": { "type": "string", @@ -5069,19 +5036,6 @@ "maxLength": 36 }, "example": "host-1" - }, - { - "name": "task_id", - "in": "path", - "description": "ID of the task to get.", - "required": true, - "schema": { - "type": "string", - "description": "ID of the task to get.", - "example": "3c875a27-f6a6-4c1c-ba5f-6972fb1fc348", - "format": "uuid" - }, - "example": "3c875a27-f6a6-4c1c-ba5f-6972fb1fc348" } ], "responses": { @@ -5090,17 +5044,57 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/Task" + "$ref": "#/components/schemas/Host" }, "example": { - "completed_at": "2025-06-18T16:52:35Z", - "created_at": "2025-06-18T16:52:05Z", - "database_id": "storefront", - "entity_id": "storefront", - "scope": "database", - "status": "completed", - "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", - "type": "create" + "client_addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "cohort": { + "control_available": true, + "member_id": "lah4bsznw6kc0hp7biylmmmll", + "type": "swarm" + }, + "cpus": 4, + "data_dir": "/data", + "default_pgedge_version": { + "postgres_version": "17.6", + "spock_version": "5" + }, + "etcd_mode": "server", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "memory": "16GiB", + "orchestrator": "swarm", + "peer_addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "status": { + "components": { + "Id dolorem rerum labore commodi.": { + "details": { + "alarms": [ + "3: NOSPACE" + ] + }, + "error": "failed to connect to etcd", + "healthy": false + } + }, + "state": "available", + "updated_at": "2021-07-01T12:34:56Z" + }, + "supported_pgedge_versions": [ + { + "postgres_version": "17.6", + "spock_version": "5" + }, + { + "postgres_version": "17.6", + "spock_version": "5" + } + ] } } } @@ -5178,23 +5172,23 @@ } } }, - "/v1/hosts/{host_id}/tasks/{task_id}/logs": { + "/v1/hosts/{host_id}/tasks": { "get": { "tags": [ "Host" ], - "summary": "Get host task logs", - "description": "Returns the log of a particular task for a host.", - "operationId": "get-host-task-log", + "summary": "List host tasks", + "description": "Lists all tasks for a host.", + "operationId": "list-host-tasks", "parameters": [ { - "name": "after_entry_id", + "name": "after_task_id", "in": "query", - "description": "ID of the entry to start from.", + "description": "ID of the task to start from.", "allowEmptyValue": true, "schema": { "type": "string", - "description": "ID of the entry to start from.", + "description": "ID of the task to start from.", "example": "3c875a27-f6a6-4c1c-ba5f-6972fb1fc348", "format": "uuid" }, @@ -5203,20 +5197,40 @@ { "name": "limit", "in": "query", - "description": "Maximum number of entries to return.", + "description": "Maximum number of tasks to return.", "allowEmptyValue": true, "schema": { "type": "integer", - "description": "Maximum number of entries to return.", + "description": "Maximum number of tasks to return.", "example": 100, "format": "int64" }, "example": 100 }, + { + "name": "sort_order", + "in": "query", + "description": "Sort order for the tasks.", + "allowEmptyValue": true, + "schema": { + "type": "string", + "description": "Sort order for the tasks.", + "example": "ascend", + "enum": [ + "asc", + "ascend", + "ascending", + "desc", + "descend", + "descending" + ] + }, + "example": "ascend" + }, { "name": "host_id", "in": "path", - "description": "ID of the host to get the task logs for.", + "description": "ID of the host to list tasks for.", "required": true, "schema": { "type": "string", @@ -5226,19 +5240,6 @@ "maxLength": 36 }, "example": "host-1" - }, - { - "name": "task_id", - "in": "path", - "description": "ID of the task to get the logs for.", - "required": true, - "schema": { - "type": "string", - "description": "ID of the task to get the logs for.", - "example": "3c875a27-f6a6-4c1c-ba5f-6972fb1fc348", - "format": "uuid" - }, - "example": "3c875a27-f6a6-4c1c-ba5f-6972fb1fc348" } ], "responses": { @@ -5247,138 +5248,21 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/TaskLog" + "$ref": "#/components/schemas/ListHostTasksResponse" }, - "examples": { - "node_backup task log": { - "summary": "node_backup task log", - "description": "The task log from a 'node_backup' task. These messages are produced by pgbackrest.", - "value": { - "entity_id": "storefront", - "entries": [ - { - "message": "P00 INFO: backup command begin 2.55.1: --config=/opt/pgedge/configs/pgbackrest.backup.conf --exec-id=198-b17fae6e --log-level-console=info --no-log-timestamp --pg1-path=/opt/pgedge/data/pgdata --pg1-user=pgedge --repo1-cipher-type=none --repo1-path=/backups/databases/storefront/n1 --repo1-retention-full=7 --repo1-retention-full-type=time --repo1-type=posix --stanza=db --start-fast --type=full", - "timestamp": "2025-06-18T17:54:34Z" - }, - { - "message": "P00 INFO: execute non-exclusive backup start: backup begins after the requested immediate checkpoint completes", - "timestamp": "2025-06-18T17:54:34Z" - }, - { - "message": "P00 INFO: backup start archive = 000000020000000000000004, lsn = 0/4000028", - "timestamp": "2025-06-18T17:54:34Z" - }, - { - "message": "P00 INFO: check archive for prior segment 000000020000000000000003", - "timestamp": "2025-06-18T17:54:34Z" - }, - { - "message": "P00 INFO: execute non-exclusive backup stop and wait for all WAL segments to archive", - "timestamp": "2025-06-18T17:54:36Z" - }, - { - "message": "P00 INFO: backup stop archive = 000000020000000000000004, lsn = 0/4000120", - "timestamp": "2025-06-18T17:54:36Z" - }, - { - "message": "P00 INFO: check archive for segment(s) 000000020000000000000004:000000020000000000000004", - "timestamp": "2025-06-18T17:54:36Z" - }, - { - "message": "P00 INFO: new backup label = 20250618-175434F", - "timestamp": "2025-06-18T17:54:36Z" - }, - { - "message": "P00 INFO: full backup size = 30.6MB, file total = 1342", - "timestamp": "2025-06-18T17:54:36Z" - }, - { - "message": "P00 INFO: backup command end: completed successfully", - "timestamp": "2025-06-18T17:54:36Z" - }, - { - "message": "P00 INFO: expire command begin 2.55.1: --config=/opt/pgedge/configs/pgbackrest.backup.conf --exec-id=198-b17fae6e --log-level-console=info --no-log-timestamp --repo1-cipher-type=none --repo1-path=/backups/databases/storefront/n1 --repo1-retention-full=7 --repo1-retention-full-type=time --repo1-type=posix --stanza=db", - "timestamp": "2025-06-18T17:54:36Z" - }, - { - "message": "P00 INFO: repo1: time-based archive retention not met - archive logs will not be expired", - "timestamp": "2025-06-18T17:54:36Z" - }, - { - "message": "P00 INFO: expire command end: completed successfully", - "timestamp": "2025-06-18T17:54:36Z" - } - ], - "last_entry_id": "0197842d-b14d-7c69-86c1-c006a7c65318", - "scope": "database", + "example": { + "tasks": [ + { + "completed_at": "2025-06-18T17:54:36Z", + "created_at": "2025-06-18T17:54:28Z", + "entity_id": "host-1", + "host_id": "host-1", + "scope": "host", + "status": "completed", "task_id": "0197842d-9082-7496-b787-77bd2e11809f", - "task_status": "completed" + "type": "remove_host" } - }, - "update task log": { - "summary": "update task log", - "description": "This is the task log of an update task. This example excludes many entries for brevity.", - "value": { - "entity_id": "storefront", - "entries": [ - { - "message": "refreshing current state", - "timestamp": "2025-06-18T17:53:19Z" - }, - { - "fields": { - "duration_ms": 8972 - }, - "message": "finished refreshing current state (took 8.972080116s)", - "timestamp": "2025-06-18T17:53:28Z" - }, - { - "fields": { - "host_id": "host-1", - "resource_id": "storefront-n1-689qacsi-backup", - "resource_type": "swarm.pgbackrest_config" - }, - "message": "creating resource swarm.pgbackrest_config::storefront-n1-689qacsi-backup", - "timestamp": "2025-06-18T17:53:29Z" - }, - { - "fields": { - "host_id": "host-2", - "resource_id": "storefront-n2-9ptayhma-backup", - "resource_type": "swarm.pgbackrest_config" - }, - "message": "creating resource swarm.pgbackrest_config::storefront-n2-9ptayhma-backup", - "timestamp": "2025-06-18T17:53:29Z" - }, - { - "fields": { - "duration_ms": 383, - "host_id": "host-3", - "resource_id": "n3", - "resource_type": "swarm.pgbackrest_stanza", - "success": true - }, - "message": "finished creating resource swarm.pgbackrest_stanza::n3 (took 383.568613ms)", - "timestamp": "2025-06-18T17:54:02Z" - }, - { - "fields": { - "duration_ms": 1181, - "host_id": "host-1", - "resource_id": "n1", - "resource_type": "swarm.pgbackrest_stanza", - "success": true - }, - "message": "finished creating resource swarm.pgbackrest_stanza::n1 (took 1.181454868s)", - "timestamp": "2025-06-18T17:54:03Z" - } - ], - "last_entry_id": "0197842d-303b-7251-b814-6d12c98e7d25", - "scope": "database", - "task_id": "0197842c-7c4f-7a8c-829e-7405c2a41c8c", - "task_status": "completed" - } - } + ] } } } @@ -5456,36 +5340,20 @@ } } }, - "/v1/tasks": { + "/v1/hosts/{host_id}/tasks/{task_id}": { "get": { "tags": [ - "System" + "Host" ], - "summary": "List tasks", - "description": "Lists tasks across all scopes with optional filtering by scope and entity ID.", - "operationId": "list-tasks", + "summary": "Get host task", + "description": "Returns information about a particular task for a host.", + "operationId": "get-host-task", "parameters": [ { - "name": "scope", - "in": "query", - "description": "Optional scope to filter tasks (database or host).", - "allowEmptyValue": true, - "schema": { - "type": "string", - "description": "Optional scope to filter tasks (database or host).", - "example": "database", - "enum": [ - "database", - "host" - ] - }, - "example": "database" - }, - { - "name": "entity_id", - "in": "query", - "description": "Optional entity ID to filter tasks. Requires scope to be set.", - "allowEmptyValue": true, + "name": "host_id", + "in": "path", + "description": "ID of the host the task belongs to.", + "required": true, "schema": { "type": "string", "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", @@ -5493,53 +5361,20 @@ "minLength": 1, "maxLength": 36 }, - "example": "my-app" + "example": "host-1" }, { - "name": "after_task_id", - "in": "query", - "description": "ID of the task to start from.", - "allowEmptyValue": true, + "name": "task_id", + "in": "path", + "description": "ID of the task to get.", + "required": true, "schema": { "type": "string", - "description": "ID of the task to start from.", + "description": "ID of the task to get.", "example": "3c875a27-f6a6-4c1c-ba5f-6972fb1fc348", "format": "uuid" }, "example": "3c875a27-f6a6-4c1c-ba5f-6972fb1fc348" - }, - { - "name": "limit", - "in": "query", - "description": "Maximum number of tasks to return.", - "allowEmptyValue": true, - "schema": { - "type": "integer", - "description": "Maximum number of tasks to return.", - "example": 100, - "format": "int64" - }, - "example": 100 - }, - { - "name": "sort_order", - "in": "query", - "description": "Sort order for the tasks.", - "allowEmptyValue": true, - "schema": { - "type": "string", - "description": "Sort order for the tasks.", - "example": "ascend", - "enum": [ - "asc", - "ascend", - "ascending", - "desc", - "descend", - "descending" - ] - }, - "example": "ascend" } ], "responses": { @@ -5548,32 +5383,17 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ListTasksResponse" + "$ref": "#/components/schemas/Task" }, "example": { - "tasks": [ - { - "completed_at": "2025-06-18T17:54:36Z", - "created_at": "2025-06-18T17:54:28Z", - "database_id": "storefront", - "entity_id": "storefront", - "instance_id": "storefront-n1-689qacsi", - "scope": "database", - "status": "completed", - "task_id": "0197842d-9082-7496-b787-77bd2e11809f", - "type": "node_backup" - }, - { - "completed_at": "2025-06-18T17:54:36Z", - "created_at": "2025-06-18T17:54:28Z", - "entity_id": "host-1", - "host_id": "host-1", - "scope": "host", - "status": "completed", - "task_id": "0197842d-9082-7496-b787-77bd2e11809f", - "type": "remove_host" - } - ] + "completed_at": "2025-06-18T16:52:35Z", + "created_at": "2025-06-18T16:52:05Z", + "database_id": "storefront", + "entity_id": "storefront", + "scope": "database", + "status": "completed", + "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", + "type": "create" } } } @@ -5592,22 +5412,8 @@ } } }, - "409": { - "description": "cluster_not_initialized: Conflict response.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/APIError" - }, - "example": { - "message": "A longer description of the error.", - "name": "error_name" - } - } - } - }, - "500": { - "description": "server_error: Internal Server Error response.", + "404": { + "description": "not_found: Not Found response.", "content": { "application/json": { "schema": { @@ -5620,8 +5426,8 @@ } } }, - "default": { - "description": "Unexpected error response", + "409": { + "description": "cluster_not_initialized: Conflict response.", "content": { "application/json": { "schema": { @@ -5633,34 +5439,6 @@ } } } - } - } - } - }, - "/v1/version": { - "get": { - "tags": [ - "System" - ], - "summary": "Get version", - "description": "Returns version information for this Control Plane server.", - "operationId": "get-version", - "responses": { - "200": { - "description": "OK response.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VersionInfo" - }, - "example": { - "arch": "amd64", - "revision": "e89ae93b", - "revision_time": "2025-01-01T01:30:00Z", - "version": "1.0.0" - } - } - } }, "500": { "description": "server_error: Internal Server Error response.", @@ -5692,1211 +5470,3943 @@ } } } - } - }, - "components": { - "schemas": { - "APIError": { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "The error message.", - "example": "A longer description of the error." + }, + "/v1/hosts/{host_id}/tasks/{task_id}/logs": { + "get": { + "tags": [ + "Host" + ], + "summary": "Get host task logs", + "description": "Returns the log of a particular task for a host.", + "operationId": "get-host-task-log", + "parameters": [ + { + "name": "after_entry_id", + "in": "query", + "description": "ID of the entry to start from.", + "allowEmptyValue": true, + "schema": { + "type": "string", + "description": "ID of the entry to start from.", + "example": "3c875a27-f6a6-4c1c-ba5f-6972fb1fc348", + "format": "uuid" + }, + "example": "3c875a27-f6a6-4c1c-ba5f-6972fb1fc348" }, - "name": { - "type": "string", - "description": "The name of the error.", - "example": "error_name" - } + { + "name": "limit", + "in": "query", + "description": "Maximum number of entries to return.", + "allowEmptyValue": true, + "schema": { + "type": "integer", + "description": "Maximum number of entries to return.", + "example": 100, + "format": "int64" + }, + "example": 100 + }, + { + "name": "host_id", + "in": "path", + "description": "ID of the host to get the task logs for.", + "required": true, + "schema": { + "type": "string", + "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 + }, + "example": "host-1" + }, + { + "name": "task_id", + "in": "path", + "description": "ID of the task to get the logs for.", + "required": true, + "schema": { + "type": "string", + "description": "ID of the task to get the logs for.", + "example": "3c875a27-f6a6-4c1c-ba5f-6972fb1fc348", + "format": "uuid" + }, + "example": "3c875a27-f6a6-4c1c-ba5f-6972fb1fc348" + } + ], + "responses": { + "200": { + "description": "OK response.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskLog" + }, + "examples": { + "node_backup task log": { + "summary": "node_backup task log", + "description": "The task log from a 'node_backup' task. These messages are produced by pgbackrest.", + "value": { + "entity_id": "storefront", + "entries": [ + { + "message": "P00 INFO: backup command begin 2.55.1: --config=/opt/pgedge/configs/pgbackrest.backup.conf --exec-id=198-b17fae6e --log-level-console=info --no-log-timestamp --pg1-path=/opt/pgedge/data/pgdata --pg1-user=pgedge --repo1-cipher-type=none --repo1-path=/backups/databases/storefront/n1 --repo1-retention-full=7 --repo1-retention-full-type=time --repo1-type=posix --stanza=db --start-fast --type=full", + "timestamp": "2025-06-18T17:54:34Z" + }, + { + "message": "P00 INFO: execute non-exclusive backup start: backup begins after the requested immediate checkpoint completes", + "timestamp": "2025-06-18T17:54:34Z" + }, + { + "message": "P00 INFO: backup start archive = 000000020000000000000004, lsn = 0/4000028", + "timestamp": "2025-06-18T17:54:34Z" + }, + { + "message": "P00 INFO: check archive for prior segment 000000020000000000000003", + "timestamp": "2025-06-18T17:54:34Z" + }, + { + "message": "P00 INFO: execute non-exclusive backup stop and wait for all WAL segments to archive", + "timestamp": "2025-06-18T17:54:36Z" + }, + { + "message": "P00 INFO: backup stop archive = 000000020000000000000004, lsn = 0/4000120", + "timestamp": "2025-06-18T17:54:36Z" + }, + { + "message": "P00 INFO: check archive for segment(s) 000000020000000000000004:000000020000000000000004", + "timestamp": "2025-06-18T17:54:36Z" + }, + { + "message": "P00 INFO: new backup label = 20250618-175434F", + "timestamp": "2025-06-18T17:54:36Z" + }, + { + "message": "P00 INFO: full backup size = 30.6MB, file total = 1342", + "timestamp": "2025-06-18T17:54:36Z" + }, + { + "message": "P00 INFO: backup command end: completed successfully", + "timestamp": "2025-06-18T17:54:36Z" + }, + { + "message": "P00 INFO: expire command begin 2.55.1: --config=/opt/pgedge/configs/pgbackrest.backup.conf --exec-id=198-b17fae6e --log-level-console=info --no-log-timestamp --repo1-cipher-type=none --repo1-path=/backups/databases/storefront/n1 --repo1-retention-full=7 --repo1-retention-full-type=time --repo1-type=posix --stanza=db", + "timestamp": "2025-06-18T17:54:36Z" + }, + { + "message": "P00 INFO: repo1: time-based archive retention not met - archive logs will not be expired", + "timestamp": "2025-06-18T17:54:36Z" + }, + { + "message": "P00 INFO: expire command end: completed successfully", + "timestamp": "2025-06-18T17:54:36Z" + } + ], + "last_entry_id": "0197842d-b14d-7c69-86c1-c006a7c65318", + "scope": "database", + "task_id": "0197842d-9082-7496-b787-77bd2e11809f", + "task_status": "completed" + } + }, + "update task log": { + "summary": "update task log", + "description": "This is the task log of an update task. This example excludes many entries for brevity.", + "value": { + "entity_id": "storefront", + "entries": [ + { + "message": "refreshing current state", + "timestamp": "2025-06-18T17:53:19Z" + }, + { + "fields": { + "duration_ms": 8972 + }, + "message": "finished refreshing current state (took 8.972080116s)", + "timestamp": "2025-06-18T17:53:28Z" + }, + { + "fields": { + "host_id": "host-1", + "resource_id": "storefront-n1-689qacsi-backup", + "resource_type": "swarm.pgbackrest_config" + }, + "message": "creating resource swarm.pgbackrest_config::storefront-n1-689qacsi-backup", + "timestamp": "2025-06-18T17:53:29Z" + }, + { + "fields": { + "host_id": "host-2", + "resource_id": "storefront-n2-9ptayhma-backup", + "resource_type": "swarm.pgbackrest_config" + }, + "message": "creating resource swarm.pgbackrest_config::storefront-n2-9ptayhma-backup", + "timestamp": "2025-06-18T17:53:29Z" + }, + { + "fields": { + "duration_ms": 383, + "host_id": "host-3", + "resource_id": "n3", + "resource_type": "swarm.pgbackrest_stanza", + "success": true + }, + "message": "finished creating resource swarm.pgbackrest_stanza::n3 (took 383.568613ms)", + "timestamp": "2025-06-18T17:54:02Z" + }, + { + "fields": { + "duration_ms": 1181, + "host_id": "host-1", + "resource_id": "n1", + "resource_type": "swarm.pgbackrest_stanza", + "success": true + }, + "message": "finished creating resource swarm.pgbackrest_stanza::n1 (took 1.181454868s)", + "timestamp": "2025-06-18T17:54:03Z" + } + ], + "last_entry_id": "0197842d-303b-7251-b814-6d12c98e7d25", + "scope": "database", + "task_id": "0197842c-7c4f-7a8c-829e-7405c2a41c8c", + "task_status": "completed" + } + } + } + } + } + }, + "400": { + "description": "invalid_input: Bad Request response.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIError" + }, + "example": { + "message": "A longer description of the error.", + "name": "error_name" + } + } + } + }, + "404": { + "description": "not_found: Not Found response.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIError" + }, + "example": { + "message": "A longer description of the error.", + "name": "error_name" + } + } + } + }, + "409": { + "description": "cluster_not_initialized: Conflict response.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIError" + }, + "example": { + "message": "A longer description of the error.", + "name": "error_name" + } + } + } + }, + "500": { + "description": "server_error: Internal Server Error response.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIError" + }, + "example": { + "message": "A longer description of the error.", + "name": "error_name" + } + } + } + }, + "default": { + "description": "Unexpected error response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIError" + }, + "example": { + "message": "A longer description of the error.", + "name": "error_name" + } + } + } + } + } + } + }, + "/v1/tasks": { + "get": { + "tags": [ + "System" + ], + "summary": "List tasks", + "description": "Lists tasks across all scopes with optional filtering by scope and entity ID.", + "operationId": "list-tasks", + "parameters": [ + { + "name": "scope", + "in": "query", + "description": "Optional scope to filter tasks (database or host).", + "allowEmptyValue": true, + "schema": { + "type": "string", + "description": "Optional scope to filter tasks (database or host).", + "example": "database", + "enum": [ + "database", + "host" + ] + }, + "example": "database" + }, + { + "name": "entity_id", + "in": "query", + "description": "Optional entity ID to filter tasks. Requires scope to be set.", + "allowEmptyValue": true, + "schema": { + "type": "string", + "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 + }, + "example": "my-app" + }, + { + "name": "after_task_id", + "in": "query", + "description": "ID of the task to start from.", + "allowEmptyValue": true, + "schema": { + "type": "string", + "description": "ID of the task to start from.", + "example": "3c875a27-f6a6-4c1c-ba5f-6972fb1fc348", + "format": "uuid" + }, + "example": "3c875a27-f6a6-4c1c-ba5f-6972fb1fc348" + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of tasks to return.", + "allowEmptyValue": true, + "schema": { + "type": "integer", + "description": "Maximum number of tasks to return.", + "example": 100, + "format": "int64" + }, + "example": 100 + }, + { + "name": "sort_order", + "in": "query", + "description": "Sort order for the tasks.", + "allowEmptyValue": true, + "schema": { + "type": "string", + "description": "Sort order for the tasks.", + "example": "ascend", + "enum": [ + "asc", + "ascend", + "ascending", + "desc", + "descend", + "descending" + ] + }, + "example": "ascend" + } + ], + "responses": { + "200": { + "description": "OK response.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListTasksResponse" + }, + "example": { + "tasks": [ + { + "completed_at": "2025-06-18T17:54:36Z", + "created_at": "2025-06-18T17:54:28Z", + "database_id": "storefront", + "entity_id": "storefront", + "instance_id": "storefront-n1-689qacsi", + "scope": "database", + "status": "completed", + "task_id": "0197842d-9082-7496-b787-77bd2e11809f", + "type": "node_backup" + }, + { + "completed_at": "2025-06-18T17:54:36Z", + "created_at": "2025-06-18T17:54:28Z", + "entity_id": "host-1", + "host_id": "host-1", + "scope": "host", + "status": "completed", + "task_id": "0197842d-9082-7496-b787-77bd2e11809f", + "type": "remove_host" + } + ] + } + } + } + }, + "400": { + "description": "invalid_input: Bad Request response.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIError" + }, + "example": { + "message": "A longer description of the error.", + "name": "error_name" + } + } + } + }, + "409": { + "description": "cluster_not_initialized: Conflict response.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIError" + }, + "example": { + "message": "A longer description of the error.", + "name": "error_name" + } + } + } + }, + "500": { + "description": "server_error: Internal Server Error response.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIError" + }, + "example": { + "message": "A longer description of the error.", + "name": "error_name" + } + } + } + }, + "default": { + "description": "Unexpected error response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIError" + }, + "example": { + "message": "A longer description of the error.", + "name": "error_name" + } + } + } + } + } + } + }, + "/v1/version": { + "get": { + "tags": [ + "System" + ], + "summary": "Get version", + "description": "Returns version information for this Control Plane server.", + "operationId": "get-version", + "responses": { + "200": { + "description": "OK response.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VersionInfo" + }, + "example": { + "arch": "amd64", + "revision": "e89ae93b", + "revision_time": "2025-01-01T01:30:00Z", + "version": "1.0.0" + } + } + } + }, + "500": { + "description": "server_error: Internal Server Error response.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIError" + }, + "example": { + "message": "A longer description of the error.", + "name": "error_name" + } + } + } + }, + "default": { + "description": "Unexpected error response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/APIError" + }, + "example": { + "message": "A longer description of the error.", + "name": "error_name" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "APIError": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "The error message.", + "example": "A longer description of the error." + }, + "name": { + "type": "string", + "description": "The name of the error.", + "example": "error_name" + } + }, + "description": "A Control Plane API error.", + "example": { + "message": "A longer description of the error.", + "name": "error_name" + }, + "required": [ + "name", + "message" + ] + }, + "ApplyMajorUpgradeRequest": { + "type": "object", + "properties": { + "image": { + "type": "string", + "description": "Full container image reference of the upgrade target. Must match the image field of a manifest entry whose spock_version is target_spock_version and whose postgres_version matches the database's current postgres_version. Unlike ApplyUpgradeRequest, the target entry is not required to have stability \"stable\" — a Spock major version is expected to still be in a \"dev\" stability window while this action is in use for it.", + "example": "ghcr.io/pgedge/pgedge-postgres:18.4-spock6.0.0-standard-1", + "minLength": 1 + }, + "node_order": { + "type": "array", + "items": { + "type": "string", + "example": "Sapiente eos aut." + }, + "description": "Explicit order (by node name) in which nodes are upgraded, one at a time. Defaults to the order nodes appear in the database spec if omitted. Every node in the database must appear exactly once.", + "example": [ + "n2", + "n1", + "n3" + ] + }, + "target_spock_version": { + "type": "string", + "description": "The Spock major version to upgrade to.", + "example": "6", + "pattern": "^\\d{1}$" + } + }, + "description": "Request to upgrade a database across a Spock major version boundary (e.g. 5.x to 6.x). Deliberately separate from ApplyUpgradeRequest: a major-version bump changes replication protocol behavior and is executed one node at a time (rolling), not redeployed uniformly like a minor/patch bump.", + "example": { + "image": "ghcr.io/pgedge/pgedge-postgres:18.4-spock6.0.0-standard-1", + "node_order": [ + "n2", + "n1", + "n3" + ], + "target_spock_version": "6" + }, + "required": [ + "target_spock_version", + "image" + ] + }, + "ApplyMajorUpgradeResponse": { + "type": "object", + "properties": { + "database": { + "$ref": "#/components/schemas/Database" + }, + "task": { + "$ref": "#/components/schemas/Task" + } + }, + "example": { + "database": { + "created_at": "2025-06-18T16:52:05Z", + "id": "storefront", + "instances": [ + { + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2025-06-18T16:52:22Z", + "host_id": "us-east-1", + "id": "storefront-n1-689qacsi", + "node_name": "n1", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n1n3", + "provider_node": "n3", + "status": "replicating" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "replicating" + } + ], + "version": "4.0.10" + }, + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:36Z" + }, + { + "connection_info": { + "addresses": [ + "10.24.35.2", + "i-058731542fee493f.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2025-06-18T16:52:22Z", + "host_id": "ap-south-1", + "id": "storefront-n2-9ptayhma", + "node_name": "n2", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n2n1", + "provider_node": "n1", + "status": "replicating" + }, + { + "name": "sub_n2n3", + "provider_node": "n3", + "status": "replicating" + } + ], + "version": "4.0.10" + }, + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:01Z" + }, + { + "connection_info": { + "addresses": [ + "10.24.36.2", + "i-494027b7b53f6a23.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2025-06-18T16:52:22Z", + "host_id": "eu-central-1", + "id": "storefront-n3-ant97dj4", + "node_name": "n3", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n3n1", + "provider_node": "n1", + "status": "replicating" + }, + { + "name": "sub_n3n2", + "provider_node": "n2", + "status": "replicating" + } + ], + "version": "4.0.10" + }, + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:01Z" + } + ], + "spec": { + "database_name": "storefront", + "database_users": [ + { + "attributes": [ + "SUPERUSER", + "LOGIN" + ], + "db_owner": true, + "username": "admin" + } + ], + "nodes": [ + { + "host_ids": [ + "us-east-1" + ], + "name": "n1" + }, + { + "host_ids": [ + "ap-south-1" + ], + "name": "n2" + }, + { + "host_ids": [ + "eu-central-1" + ], + "name": "n3" + } + ], + "port": 5432, + "postgres_version": "17.6", + "spock_version": "5" + }, + "state": "restoring", + "updated_at": "2025-06-18T17:58:59Z" + }, + "task": { + "completed_at": "2025-06-18T16:52:35Z", + "created_at": "2025-06-18T16:52:05Z", + "database_id": "storefront", + "entity_id": "storefront", + "scope": "database", + "status": "completed", + "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", + "type": "create" + } + }, + "required": [ + "task", + "database" + ] + }, + "ApplyMajorUpgradeResponse2": { + "type": "object", + "properties": { + "database": { + "$ref": "#/components/schemas/Database6" + }, + "task": { + "$ref": "#/components/schemas/Task" + } + }, + "example": { + "database": { + "created_at": "2025-06-18T16:52:05Z", + "id": "storefront", + "instances": [ + { + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2025-06-18T16:52:22Z", + "host_id": "us-east-1", + "id": "storefront-n1-689qacsi", + "node_name": "n1", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n1n3", + "provider_node": "n3", + "status": "replicating" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "replicating" + } + ], + "version": "4.0.10" + }, + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:36Z" + }, + { + "connection_info": { + "addresses": [ + "10.24.35.2", + "i-058731542fee493f.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2025-06-18T16:52:22Z", + "host_id": "ap-south-1", + "id": "storefront-n2-9ptayhma", + "node_name": "n2", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n2n1", + "provider_node": "n1", + "status": "replicating" + }, + { + "name": "sub_n2n3", + "provider_node": "n3", + "status": "replicating" + } + ], + "version": "4.0.10" + }, + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:01Z" + }, + { + "connection_info": { + "addresses": [ + "10.24.36.2", + "i-494027b7b53f6a23.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2025-06-18T16:52:22Z", + "host_id": "eu-central-1", + "id": "storefront-n3-ant97dj4", + "node_name": "n3", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n3n1", + "provider_node": "n1", + "status": "replicating" + }, + { + "name": "sub_n3n2", + "provider_node": "n2", + "status": "replicating" + } + ], + "version": "4.0.10" + }, + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:01Z" + } + ], + "spec": { + "database_name": "storefront", + "database_users": [ + { + "attributes": [ + "SUPERUSER", + "LOGIN" + ], + "db_owner": true, + "username": "admin" + } + ], + "nodes": [ + { + "host_ids": [ + "us-east-1" + ], + "name": "n1" + }, + { + "host_ids": [ + "ap-south-1" + ], + "name": "n2" + }, + { + "host_ids": [ + "eu-central-1" + ], + "name": "n3" + } + ], + "port": 5432, + "postgres_version": "17.6", + "spock_version": "5" + }, + "state": "restoring", + "updated_at": "2025-06-18T17:58:59Z" + }, + "task": { + "completed_at": "2025-06-18T16:52:35Z", + "created_at": "2025-06-18T16:52:05Z", + "database_id": "storefront", + "entity_id": "storefront", + "scope": "database", + "status": "completed", + "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", + "type": "create" + } + }, + "required": [ + "task", + "database" + ] + }, + "ApplyUpgradeRequest": { + "type": "object", + "properties": { + "image": { + "type": "string", + "description": "Full container image reference of the upgrade target. Must match the image field of a stable manifest entry in the same Postgres major / Spock major bucket as the current version and be strictly newer.", + "example": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.8-standard-1", + "minLength": 1 + } + }, + "example": { + "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.8-standard-1" + }, + "required": [ + "image" + ] + }, + "ApplyUpgradeResponse": { + "type": "object", + "properties": { + "database": { + "$ref": "#/components/schemas/Database" + }, + "task": { + "$ref": "#/components/schemas/Task" + } + }, + "example": { + "database": { + "created_at": "2025-06-18T16:52:05Z", + "id": "storefront", + "state": "modifying", + "updated_at": "2025-06-18T17:58:59Z" + }, + "task": { + "created_at": "2025-06-18T17:58:59Z", + "database_id": "storefront", + "status": "pending", + "task_id": "01978431-b628-758a-aec6-03b331fa1a17", + "type": "upgrade" + } + }, + "required": [ + "task", + "database" + ] + }, + "ApplyUpgradeResponse2": { + "type": "object", + "properties": { + "database": { + "$ref": "#/components/schemas/Database5" + }, + "task": { + "$ref": "#/components/schemas/Task" + } + }, + "example": { + "database": { + "created_at": "2025-06-18T16:52:05Z", + "id": "storefront", + "state": "modifying", + "updated_at": "2025-06-18T17:58:59Z" + }, + "task": { + "created_at": "2025-06-18T17:58:59Z", + "database_id": "storefront", + "status": "pending", + "task_id": "01978431-b628-758a-aec6-03b331fa1a17", + "type": "upgrade" + } + }, + "required": [ + "task", + "database" + ] + }, + "AvailableUpgrade": { + "type": "object", + "properties": { + "image": { + "type": "string", + "description": "Full container image reference for the upgrade candidate.", + "example": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1" + }, + "postgres_version": { + "type": "string", + "description": "Postgres version of the upgrade candidate.", + "example": "17.10" + }, + "spock_version": { + "type": "string", + "description": "Spock major version of the upgrade candidate.", + "example": "5" + } + }, + "description": "A newer stable image available for the database in the same Postgres major / Spock major bucket.", + "example": { + "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", + "postgres_version": "17.10", + "spock_version": "5" + }, + "required": [ + "postgres_version", + "spock_version", + "image" + ] + }, + "BackupConfigSpec": { + "type": "object", + "properties": { + "repositories": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BackupRepositorySpec" + }, + "description": "The repositories for this backup configuration.", + "example": [ + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + } + ], + "minItems": 1 + }, + "schedules": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BackupScheduleSpec" + }, + "description": "The schedules for this backup configuration.", + "example": [ + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + } + ], + "maxItems": 32 + } + }, + "example": { + "repositories": [ + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + } + ], + "schedules": [ + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + } + ] + }, + "required": [ + "repositories" + ] + }, + "BackupDatabaseNodeResponse": { + "type": "object", + "properties": { + "task": { + "$ref": "#/components/schemas/Task" + } + }, + "example": { + "task": { + "created_at": "2025-06-18T17:54:28Z", + "database_id": "storefront", + "status": "pending", + "task_id": "0197842d-9082-7496-b787-77bd2e11809f", + "type": "node_backup" + } + }, + "required": [ + "task" + ] + }, + "BackupOptions": { + "type": "object", + "properties": { + "annotations": { + "type": "object", + "description": "Annotations for the backup.", + "example": { + "key": "value" + }, + "additionalProperties": { + "type": "string", + "example": "Temporibus aut." + } + }, + "backup_options": { + "type": "object", + "description": "Options for the backup.", + "example": { + "archive-check": "n" + }, + "additionalProperties": { + "type": "string", + "example": "Repudiandae ab sed." + } + }, + "type": { + "type": "string", + "description": "The type of backup.", + "example": "full", + "enum": [ + "full", + "diff", + "incr" + ] + } + }, + "example": { + "annotations": { + "initiated-by": "backup-cron-job" + }, + "backup_options": { + "archive-check": "n" + }, + "type": "full" + }, + "required": [ + "type" + ] + }, + "BackupRepositorySpec": { + "type": "object", + "properties": { + "azure_account": { + "type": "string", + "description": "The Azure account name for this repository. Only applies when type = 'azure'.", + "example": "pgedge-backups", + "minLength": 3, + "maxLength": 24 + }, + "azure_container": { + "type": "string", + "description": "The Azure container name for this repository. Only applies when type = 'azure'.", + "example": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "minLength": 3, + "maxLength": 63 + }, + "azure_endpoint": { + "type": "string", + "description": "The optional Azure endpoint for this repository. Only applies when type = 'azure'.", + "example": "blob.core.usgovcloudapi.net", + "minLength": 3, + "maxLength": 128 + }, + "azure_key": { + "type": "string", + "description": "The Azure storage account access key to use for this repository. This field will be excluded from the response of all endpoints. It can also be omitted from update requests to keep the current value.", + "example": "YXpLZXk=", + "maxLength": 128 + }, + "base_path": { + "type": "string", + "description": "The base path within the repository to store backups. Required for type = 'posix' and 'cifs'.", + "example": "/backups", + "maxLength": 256 + }, + "custom_options": { + "type": "object", + "description": "Additional options to apply to this repository.", + "example": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "additionalProperties": { + "type": "string", + "example": "Accusamus alias ipsa qui." + } + }, + "gcs_bucket": { + "type": "string", + "description": "The GCS bucket name for this repository. Only applies when type = 'gcs'.", + "example": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "minLength": 3, + "maxLength": 63 + }, + "gcs_endpoint": { + "type": "string", + "description": "The optional GCS endpoint for this repository. Only applies when type = 'gcs'.", + "example": "localhost", + "minLength": 3, + "maxLength": 128 + }, + "gcs_key": { + "type": "string", + "description": "Optional base64-encoded private key data. If omitted, pgbackrest will use the service account attached to the instance profile. This field will be excluded from the response of all endpoints. It can also be omitted from update requests to keep the current value.", + "example": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "maxLength": 1024 + }, + "id": { + "type": "string", + "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 + }, + "retention_full": { + "type": "integer", + "description": "The count of full backups to retain or the time to retain full backups.", + "example": 2, + "format": "int64", + "minimum": 1, + "maximum": 9999999 + }, + "retention_full_type": { + "type": "string", + "description": "The type of measure used for retention_full.", + "example": "count", + "enum": [ + "time", + "count" + ] + }, + "s3_bucket": { + "type": "string", + "description": "The S3 bucket name for this repository. Only applies when type = 's3'.", + "example": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "minLength": 3, + "maxLength": 63 + }, + "s3_endpoint": { + "type": "string", + "description": "The optional S3 endpoint for this repository. Only applies when type = 's3'.", + "example": "s3.us-east-1.amazonaws.com", + "minLength": 3, + "maxLength": 128 + }, + "s3_key": { + "type": "string", + "description": "An optional AWS access key ID to use for this repository. If not provided, pgbackrest will use the default credential provider chain. This field will be excluded from the response of all endpoints. It can also be omitted from update requests to keep the current value.", + "example": "AKIAIOSFODNN7EXAMPLE", + "maxLength": 128 + }, + "s3_key_secret": { + "type": "string", + "description": "The corresponding secret for the AWS access key ID in s3_key. This field will be excluded from the response of all endpoints. It can also be omitted from update requests to keep the current value.", + "example": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "maxLength": 128 + }, + "s3_region": { + "type": "string", + "description": "The region of the S3 bucket for this repository. Only applies when type = 's3'.", + "example": "us-east-1", + "minLength": 1, + "maxLength": 32 + }, + "type": { + "type": "string", + "description": "The type of this repository.", + "example": "s3", + "enum": [ + "s3", + "gcs", + "azure", + "posix", + "cifs" + ] + } + }, + "example": { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + "required": [ + "type" + ] + }, + "BackupScheduleSpec": { + "type": "object", + "properties": { + "cron_expression": { + "type": "string", + "description": "The cron expression for this schedule.", + "example": "0 6 * * ?", + "maxLength": 32 + }, + "id": { + "type": "string", + "description": "The unique identifier for this backup schedule.", + "example": "daily-full-backup", + "maxLength": 64 + }, + "type": { + "type": "string", + "description": "The type of backup to take on this schedule.", + "example": "full", + "enum": [ + "full", + "incr" + ] + } + }, + "example": { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + "required": [ + "id", + "type", + "cron_expression" + ] + }, + "CancelDatabaseTaskPayload": { + "type": "object", + "properties": { + "database_id": { + "type": "string", + "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 + }, + "task_id": { + "type": "string", + "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 + } + }, + "example": { + "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "task_id": "76f9b8c0-4958-11f0-a489-3bb29577c696" + }, + "required": [ + "database_id", + "task_id" + ] + }, + "Cluster": { + "type": "object", + "properties": { + "hosts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Host" + }, + "description": "All of the hosts in the cluster.", + "example": [ + { + "client_addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "cohort": { + "cohort_id": "zdjfu3tfxg1cihv3146ro3hy2", + "control_available": true, + "member_id": "lah4bsznw6kc0hp7biylmmmll", + "type": "swarm" + }, + "cpus": 16, + "data_dir": "/data", + "default_pgedge_version": { + "postgres_version": "17.6", + "spock_version": "5" + }, + "etcd_mode": "server", + "id": "us-east-1", + "memory": "16GB", + "orchestrator": "swarm", + "peer_addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "status": { + "components": {}, + "state": "healthy", + "updated_at": "2025-06-17T00:00:00Z" + }, + "supported_pgedge_versions": [ + { + "postgres_version": "17.6", + "spock_version": "5" + }, + { + "postgres_version": "18.1", + "spock_version": "5" + }, + { + "postgres_version": "16.10", + "spock_version": "5" + } + ] + }, + { + "client_addresses": [ + "10.24.35.2", + "i-058731542fee493f.ec2.internal" + ], + "cohort": { + "cohort_id": "zdjfu3tfxg1cihv3146ro3hy2", + "control_available": true, + "member_id": "cb88u9jael2psnepep5iuzb4r", + "type": "swarm" + }, + "cpus": 16, + "data_dir": "/data", + "default_pgedge_version": { + "postgres_version": "17.6", + "spock_version": "5" + }, + "etcd_mode": "server", + "id": "ap-south-1", + "memory": "16GB", + "orchestrator": "swarm", + "peer_addresses": [ + "10.24.35.2", + "i-058731542fee493f.ec2.internal" + ], + "status": { + "components": {}, + "state": "healthy", + "updated_at": "2025-06-17T00:00:00Z" + }, + "supported_pgedge_versions": [ + { + "postgres_version": "17.6", + "spock_version": "5" + }, + { + "postgres_version": "18.1", + "spock_version": "5" + }, + { + "postgres_version": "16.10", + "spock_version": "5" + } + ] + }, + { + "client_addresses": [ + "10.24.36.2", + "i-494027b7b53f6a23.ec2.internal" + ], + "cohort": { + "cohort_id": "zdjfu3tfxg1cihv3146ro3hy2", + "control_available": true, + "member_id": "u7u9i3nhqunxc4wj577l6ecb0", + "type": "swarm" + }, + "cpus": 16, + "data_dir": "/data", + "default_pgedge_version": { + "postgres_version": "17.6", + "spock_version": "5" + }, + "etcd_mode": "client", + "id": "eu-central-1", + "memory": "16GB", + "orchestrator": "swarm", + "peer_addresses": [ + "10.24.36.2", + "i-494027b7b53f6a23.ec2.internal" + ], + "status": { + "components": {}, + "state": "healthy", + "updated_at": "2025-06-17T00:00:00Z" + }, + "supported_pgedge_versions": [ + { + "postgres_version": "17.6", + "spock_version": "5" + }, + { + "postgres_version": "18.1", + "spock_version": "5" + }, + { + "postgres_version": "16.10", + "spock_version": "5" + } + ] + } + ] + }, + "id": { + "type": "string", + "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 + }, + "status": { + "$ref": "#/components/schemas/ClusterStatus" + } + }, + "example": { + "hosts": [ + { + "client_addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "cohort": { + "cohort_id": "zdjfu3tfxg1cihv3146ro3hy2", + "control_available": true, + "member_id": "lah4bsznw6kc0hp7biylmmmll", + "type": "swarm" + }, + "cpus": 16, + "data_dir": "/data", + "default_pgedge_version": { + "postgres_version": "17.6", + "spock_version": "5" + }, + "etcd_mode": "server", + "id": "us-east-1", + "memory": "16GB", + "orchestrator": "swarm", + "peer_addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "status": { + "components": {}, + "state": "healthy", + "updated_at": "2025-06-17T00:00:00Z" + }, + "supported_pgedge_versions": [ + { + "postgres_version": "17.6", + "spock_version": "5" + }, + { + "postgres_version": "18.1", + "spock_version": "5" + }, + { + "postgres_version": "16.10", + "spock_version": "5" + } + ] + }, + { + "client_addresses": [ + "10.24.35.2", + "i-058731542fee493f.ec2.internal" + ], + "cohort": { + "cohort_id": "zdjfu3tfxg1cihv3146ro3hy2", + "control_available": true, + "member_id": "cb88u9jael2psnepep5iuzb4r", + "type": "swarm" + }, + "cpus": 16, + "data_dir": "/data", + "default_pgedge_version": { + "postgres_version": "17.6", + "spock_version": "5" + }, + "etcd_mode": "server", + "id": "ap-south-1", + "memory": "16GB", + "orchestrator": "swarm", + "peer_addresses": [ + "10.24.35.2", + "i-058731542fee493f.ec2.internal" + ], + "status": { + "components": {}, + "state": "healthy", + "updated_at": "2025-06-17T00:00:00Z" + }, + "supported_pgedge_versions": [ + { + "postgres_version": "17.6", + "spock_version": "5" + }, + { + "postgres_version": "18.1", + "spock_version": "5" + }, + { + "postgres_version": "16.10", + "spock_version": "5" + } + ] + }, + { + "client_addresses": [ + "10.24.36.2", + "i-494027b7b53f6a23.ec2.internal" + ], + "cohort": { + "cohort_id": "zdjfu3tfxg1cihv3146ro3hy2", + "control_available": true, + "member_id": "u7u9i3nhqunxc4wj577l6ecb0", + "type": "swarm" + }, + "cpus": 16, + "data_dir": "/data", + "default_pgedge_version": { + "postgres_version": "17.6", + "spock_version": "5" + }, + "etcd_mode": "client", + "id": "eu-central-1", + "memory": "16GB", + "orchestrator": "swarm", + "peer_addresses": [ + "10.24.36.2", + "i-494027b7b53f6a23.ec2.internal" + ], + "status": { + "components": {}, + "state": "healthy", + "updated_at": "2025-06-17T00:00:00Z" + }, + "supported_pgedge_versions": [ + { + "postgres_version": "17.6", + "spock_version": "5" + }, + { + "postgres_version": "18.1", + "spock_version": "5" + }, + { + "postgres_version": "16.10", + "spock_version": "5" + } + ] + } + ], + "id": "production", + "status": { + "state": "available" + } + }, + "required": [ + "id", + "status", + "hosts" + ] + }, + "ClusterCredentials": { + "type": "object", + "properties": { + "ca_cert": { + "type": "string", + "description": "The base64-encoded CA certificate for the cluster.", + "example": "ZGE4NDdkMzMtM2FiYi00YzE2LTkzOGQtNDRkODU2ZDFlZWZlCg==" + }, + "client_cert": { + "type": "string", + "description": "The base64-encoded etcd client certificate for the new cluster member.", + "example": "NWM0MGMyZTAtYjAyYS00NzkxLTk0YjAtMjMyN2EyZGQ4ZDc3Cg==" + }, + "client_key": { + "type": "string", + "description": "The base64-encoded etcd client key for the new cluster member.", + "example": "Y2FlNjhmODQtYjE1Ni00YWYyLWFhMWEtM2FhNzI2MmVhYTM0Cg==" + }, + "password": { + "type": "string", + "description": "The Etcd password for the new host.", + "example": "a78v2x866zirk4o737gjdssfi" + }, + "server_cert": { + "type": "string", + "description": "The base64-encoded etcd server certificate for the new cluster member.", + "example": "Nzc1OGQyY2UtZjdjOC00YmE4LTk2ZmQtOWE3MjVmYmY3NDdiCg==" + }, + "server_key": { + "type": "string", + "description": "The base64-encoded etcd server key for the new cluster member.", + "example": "NWRhNzY1ZGUtNzJkMi00OTU3LTk4ODUtOWRiZThjOGE5MGQ3Cg==" + }, + "username": { + "type": "string", + "description": "The Etcd username for the new host.", + "example": "host-2" + } }, - "description": "A Control Plane API error.", "example": { - "message": "A longer description of the error.", - "name": "error_name" + "ca_cert": "ZGE4NDdkMzMtM2FiYi00YzE2LTkzOGQtNDRkODU2ZDFlZWZlCg==", + "client_cert": "NWM0MGMyZTAtYjAyYS00NzkxLTk0YjAtMjMyN2EyZGQ4ZDc3Cg==", + "client_key": "Y2FlNjhmODQtYjE1Ni00YWYyLWFhMWEtM2FhNzI2MmVhYTM0Cg==", + "password": "a78v2x866zirk4o737gjdssfi", + "server_cert": "Nzc1OGQyY2UtZjdjOC00YmE4LTk2ZmQtOWE3MjVmYmY3NDdiCg==", + "server_key": "NWRhNzY1ZGUtNzJkMi00OTU3LTk4ODUtOWRiZThjOGE5MGQ3Cg==", + "username": "host-2" }, "required": [ - "name", - "message" + "username", + "password", + "ca_cert", + "client_cert", + "client_key", + "server_cert", + "server_key" ] }, - "ApplyUpgradeRequest": { + "ClusterJoinOptions": { "type": "object", "properties": { - "image": { - "type": "string", - "description": "Full container image reference of the upgrade target. Must match the image field of a stable manifest entry in the same Postgres major / Spock major bucket as the current version and be strictly newer.", - "example": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.8-standard-1", - "minLength": 1 + "credentials": { + "$ref": "#/components/schemas/ClusterCredentials" + }, + "leader": { + "$ref": "#/components/schemas/EtcdClusterMember" } }, "example": { - "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.8-standard-1" + "credentials": { + "ca_cert": "ZGE4NDdkMzMtM2FiYi00YzE2LTkzOGQtNDRkODU2ZDFlZWZlCg==", + "client_cert": "NWM0MGMyZTAtYjAyYS00NzkxLTk0YjAtMjMyN2EyZGQ4ZDc3Cg==", + "client_key": "Y2FlNjhmODQtYjE1Ni00YWYyLWFhMWEtM2FhNzI2MmVhYTM0Cg==", + "password": "a78v2x866zirk4o737gjdssfi", + "server_cert": "Nzc1OGQyY2UtZjdjOC00YmE4LTk2ZmQtOWE3MjVmYmY3NDdiCg==", + "server_key": "NWRhNzY1ZGUtNzJkMi00OTU3LTk4ODUtOWRiZThjOGE5MGQ3Cg==", + "username": "host-2" + }, + "leader": { + "client_urls": [ + "http://192.168.1.1:2379" + ], + "name": "host-1", + "peer_urls": [ + "http://192.168.1.1:2380" + ] + } }, "required": [ - "image" + "leader", + "credentials" ] }, - "ApplyUpgradeResponse": { + "ClusterJoinRequest": { "type": "object", "properties": { - "database": { - "$ref": "#/components/schemas/Database" + "addresses": { + "type": "array", + "items": { + "type": "string", + "example": "477", + "minLength": 3, + "maxLength": 128 + }, + "description": "The peer addresses of the host that's joining the cluster.", + "example": [ + "10.1.0.113", + "ip-10-1-0-113.ec2.internal" + ] }, - "task": { - "$ref": "#/components/schemas/Task" + "embedded_etcd_enabled": { + "type": "boolean", + "description": "True if the joining member is configured to run an embedded an etcd server.", + "example": true + }, + "host_id": { + "type": "string", + "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 + }, + "token": { + "type": "string", + "description": "Token to join the cluster.", + "example": "PGEDGE-dd440afcf5de20ef8e8cf54f6cb9f125fd55f90e64faa94b906130b31235e730-41e975f41d7ea61058f2fe2572cb52dd", + "pattern": "^PGEDGE-[\\w]{64}-[\\w]{32}$" } }, "example": { - "database": { - "created_at": "2025-06-18T16:52:05Z", - "id": "storefront", - "state": "modifying", - "updated_at": "2025-06-18T17:58:59Z" + "addresses": [ + "10.1.0.113", + "ip-10-1-0-113.ec2.internal" + ], + "embedded_etcd_enabled": true, + "host_id": "host-1", + "token": "PGEDGE-dd440afcf5de20ef8e8cf54f6cb9f125fd55f90e64faa94b906130b31235e730-41e975f41d7ea61058f2fe2572cb52dd" + }, + "required": [ + "embedded_etcd_enabled", + "token", + "host_id", + "addresses" + ] + }, + "ClusterJoinToken": { + "type": "object", + "properties": { + "server_urls": { + "type": "array", + "items": { + "type": "string", + "example": "Et itaque placeat placeat a enim sit." + }, + "description": "Existing server to join", + "example": [ + "http://192.168.1.1:3000" + ] }, - "task": { - "created_at": "2025-06-18T17:58:59Z", - "database_id": "storefront", - "status": "pending", - "task_id": "01978431-b628-758a-aec6-03b331fa1a17", - "type": "upgrade" + "token": { + "type": "string", + "description": "Token to join an existing cluster.", + "example": "PGEDGE-dd440afcf5de20ef8e8cf54f6cb9f125fd55f90e64faa94b906130b31235e730-41e975f41d7ea61058f2fe2572cb52dd" } }, + "example": { + "server_urls": [ + "http://192.168.1.1:3000" + ], + "token": "PGEDGE-dd440afcf5de20ef8e8cf54f6cb9f125fd55f90e64faa94b906130b31235e730-41e975f41d7ea61058f2fe2572cb52dd" + }, "required": [ - "task", - "database" + "token", + "server_urls" ] }, - "ApplyUpgradeResponse2": { + "ClusterStatus": { "type": "object", "properties": { - "database": { - "$ref": "#/components/schemas/Database5" + "state": { + "type": "string", + "description": "The current state of the cluster.", + "example": "error", + "enum": [ + "available", + "error" + ] + } + }, + "example": { + "state": "error" + }, + "required": [ + "state" + ] + }, + "ComponentStatus": { + "type": "object", + "properties": { + "details": { + "type": "object", + "description": "Additional details about the component.", + "example": { + "alarms": [ + "3: NOSPACE" + ] + }, + "additionalProperties": true }, - "task": { - "$ref": "#/components/schemas/Task" + "error": { + "type": "string", + "description": "Error message from any errors that occurred during the health check.", + "example": "failed to connect to etcd" + }, + "healthy": { + "type": "boolean", + "description": "Indicates if the component is healthy.", + "example": false } }, "example": { - "database": { - "created_at": "2025-06-18T16:52:05Z", - "id": "storefront", - "state": "modifying", - "updated_at": "2025-06-18T17:58:59Z" + "details": { + "alarms": [ + "3: NOSPACE" + ] }, - "task": { - "created_at": "2025-06-18T17:58:59Z", - "database_id": "storefront", - "status": "pending", - "task_id": "01978431-b628-758a-aec6-03b331fa1a17", - "type": "upgrade" + "error": "failed to connect to etcd", + "healthy": false + }, + "required": [ + "healthy" + ] + }, + "CreateDatabaseRequest": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 + }, + "spec": { + "$ref": "#/components/schemas/DatabaseSpec" + }, + "tenant_id": { + "type": "string", + "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 + } + }, + "example": { + "id": "storefront", + "spec": { + "database_name": "storefront", + "database_users": [ + { + "attributes": [ + "LOGIN", + "SUPERUSER" + ], + "db_owner": true, + "password": "password", + "username": "admin" + } + ], + "nodes": [ + { + "host_ids": [ + "us-east-1" + ], + "name": "n1" + }, + { + "host_ids": [ + "ap-south-1" + ], + "name": "n2" + }, + { + "host_ids": [ + "eu-central-1" + ], + "name": "n3" + } + ], + "port": 5432, + "postgresql_conf": { + "max_connections": 5000 + } } }, "required": [ - "task", - "database" + "spec" ] }, - "AvailableUpgrade": { + "CreateDatabaseRequest2": { "type": "object", "properties": { - "image": { + "id": { "type": "string", - "description": "Full container image reference for the upgrade candidate.", - "example": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1" + "description": "Unique identifier for the database.", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 }, - "postgres_version": { - "type": "string", - "description": "Postgres version of the upgrade candidate.", - "example": "17.10" + "spec": { + "$ref": "#/components/schemas/DatabaseSpec2" }, - "spock_version": { + "tenant_id": { "type": "string", - "description": "Spock major version of the upgrade candidate.", - "example": "5" + "description": "Unique identifier for the database's owner.", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 } }, - "description": "A newer stable image available for the database in the same Postgres major / Spock major bucket.", "example": { - "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", - "postgres_version": "17.10", - "spock_version": "5" - }, - "required": [ - "postgres_version", - "spock_version", - "image" - ] - }, - "BackupConfigSpec": { - "type": "object", - "properties": { - "repositories": { - "type": "array", - "items": { - "$ref": "#/components/schemas/BackupRepositorySpec" - }, - "description": "The repositories for this backup configuration.", - "example": [ + "id": "storefront", + "spec": { + "database_name": "storefront", + "database_users": [ { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" + "attributes": [ + "LOGIN", + "SUPERUSER" + ], + "db_owner": true, + "password": "password", + "username": "admin" } ], - "minItems": 1 - }, - "schedules": { - "type": "array", - "items": { - "$ref": "#/components/schemas/BackupScheduleSpec" - }, - "description": "The schedules for this backup configuration.", - "example": [ + "nodes": [ { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "host_ids": [ + "us-east-1" + ], + "name": "n1" }, { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "host_ids": [ + "ap-south-1" + ], + "name": "n2" }, { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "host_ids": [ + "eu-central-1" + ], + "name": "n3" } ], - "maxItems": 32 - } - }, - "example": { - "repositories": [ - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - } - ], - "schedules": [ - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "port": 5432, + "postgresql_conf": { + "max_connections": 5000 } - ] + } }, "required": [ - "repositories" + "spec" ] }, - "BackupDatabaseNodeResponse": { + "CreateDatabaseResponse": { "type": "object", "properties": { + "database": { + "$ref": "#/components/schemas/Database" + }, "task": { "$ref": "#/components/schemas/Task" } }, "example": { + "database": { + "created_at": "2025-06-18T16:52:05Z", + "id": "storefront", + "spec": { + "database_name": "storefront", + "database_users": [ + { + "attributes": [ + "SUPERUSER", + "LOGIN" + ], + "db_owner": true, + "username": "admin" + } + ], + "nodes": [ + { + "host_ids": [ + "us-east-1" + ], + "name": "n1" + }, + { + "host_ids": [ + "ap-south-1" + ], + "name": "n2" + }, + { + "host_ids": [ + "eu-central-1" + ], + "name": "n3" + } + ], + "port": 5432, + "postgres_version": "17.6", + "spock_version": "5" + }, + "state": "creating", + "updated_at": "2025-06-18T16:52:05Z" + }, "task": { - "created_at": "2025-06-18T17:54:28Z", + "created_at": "2025-06-18T16:52:05Z", "database_id": "storefront", "status": "pending", - "task_id": "0197842d-9082-7496-b787-77bd2e11809f", - "type": "node_backup" + "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", + "type": "create" } }, "required": [ - "task" + "task", + "database" ] }, - "BackupOptions": { + "CreateDatabaseResponse2": { "type": "object", "properties": { - "annotations": { - "type": "object", - "description": "Annotations for the backup.", - "example": { - "key": "value" - }, - "additionalProperties": { - "type": "string", - "example": "Natus qui veniam exercitationem placeat temporibus." - } - }, - "backup_options": { - "type": "object", - "description": "Options for the backup.", - "example": { - "archive-check": "n" - }, - "additionalProperties": { - "type": "string", - "example": "Facilis repudiandae ab sed exercitationem." - } + "database": { + "$ref": "#/components/schemas/Database2" }, - "type": { - "type": "string", - "description": "The type of backup.", - "example": "full", - "enum": [ - "full", - "diff", - "incr" - ] + "task": { + "$ref": "#/components/schemas/Task" } }, "example": { - "annotations": { - "initiated-by": "backup-cron-job" - }, - "backup_options": { - "archive-check": "n" - }, - "type": "full" - }, - "required": [ - "type" - ] - }, - "BackupRepositorySpec": { - "type": "object", - "properties": { - "azure_account": { - "type": "string", - "description": "The Azure account name for this repository. Only applies when type = 'azure'.", - "example": "pgedge-backups", - "minLength": 3, - "maxLength": 24 - }, - "azure_container": { - "type": "string", - "description": "The Azure container name for this repository. Only applies when type = 'azure'.", - "example": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "minLength": 3, - "maxLength": 63 - }, - "azure_endpoint": { - "type": "string", - "description": "The optional Azure endpoint for this repository. Only applies when type = 'azure'.", - "example": "blob.core.usgovcloudapi.net", - "minLength": 3, - "maxLength": 128 - }, - "azure_key": { - "type": "string", - "description": "The Azure storage account access key to use for this repository. This field will be excluded from the response of all endpoints. It can also be omitted from update requests to keep the current value.", - "example": "YXpLZXk=", - "maxLength": 128 - }, - "base_path": { - "type": "string", - "description": "The base path within the repository to store backups. Required for type = 'posix' and 'cifs'.", - "example": "/backups", - "maxLength": 256 - }, - "custom_options": { - "type": "object", - "description": "Additional options to apply to this repository.", - "example": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" + "database": { + "created_at": "2025-06-18T16:52:05Z", + "id": "storefront", + "spec": { + "database_name": "storefront", + "database_users": [ + { + "attributes": [ + "SUPERUSER", + "LOGIN" + ], + "db_owner": true, + "username": "admin" + } + ], + "nodes": [ + { + "host_ids": [ + "us-east-1" + ], + "name": "n1" + }, + { + "host_ids": [ + "ap-south-1" + ], + "name": "n2" + }, + { + "host_ids": [ + "eu-central-1" + ], + "name": "n3" + } + ], + "port": 5432, + "postgres_version": "17.6", + "spock_version": "5" }, - "additionalProperties": { - "type": "string", - "example": "Aut doloribus rem culpa ullam minus dolore." - } - }, - "gcs_bucket": { - "type": "string", - "description": "The GCS bucket name for this repository. Only applies when type = 'gcs'.", - "example": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "minLength": 3, - "maxLength": 63 - }, - "gcs_endpoint": { - "type": "string", - "description": "The optional GCS endpoint for this repository. Only applies when type = 'gcs'.", - "example": "localhost", - "minLength": 3, - "maxLength": 128 - }, - "gcs_key": { - "type": "string", - "description": "Optional base64-encoded private key data. If omitted, pgbackrest will use the service account attached to the instance profile. This field will be excluded from the response of all endpoints. It can also be omitted from update requests to keep the current value.", - "example": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "maxLength": 1024 - }, - "id": { - "type": "string", - "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", - "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "minLength": 1, - "maxLength": 36 - }, - "retention_full": { - "type": "integer", - "description": "The count of full backups to retain or the time to retain full backups.", - "example": 2, - "format": "int64", - "minimum": 1, - "maximum": 9999999 - }, - "retention_full_type": { - "type": "string", - "description": "The type of measure used for retention_full.", - "example": "count", - "enum": [ - "time", - "count" - ] - }, - "s3_bucket": { - "type": "string", - "description": "The S3 bucket name for this repository. Only applies when type = 's3'.", - "example": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "minLength": 3, - "maxLength": 63 - }, - "s3_endpoint": { - "type": "string", - "description": "The optional S3 endpoint for this repository. Only applies when type = 's3'.", - "example": "s3.us-east-1.amazonaws.com", - "minLength": 3, - "maxLength": 128 - }, - "s3_key": { - "type": "string", - "description": "An optional AWS access key ID to use for this repository. If not provided, pgbackrest will use the default credential provider chain. This field will be excluded from the response of all endpoints. It can also be omitted from update requests to keep the current value.", - "example": "AKIAIOSFODNN7EXAMPLE", - "maxLength": 128 - }, - "s3_key_secret": { - "type": "string", - "description": "The corresponding secret for the AWS access key ID in s3_key. This field will be excluded from the response of all endpoints. It can also be omitted from update requests to keep the current value.", - "example": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "maxLength": 128 - }, - "s3_region": { - "type": "string", - "description": "The region of the S3 bucket for this repository. Only applies when type = 's3'.", - "example": "us-east-1", - "minLength": 1, - "maxLength": 32 - }, - "type": { - "type": "string", - "description": "The type of this repository.", - "example": "s3", - "enum": [ - "s3", - "gcs", - "azure", - "posix", - "cifs" - ] - } - }, - "example": { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" + "state": "creating", + "updated_at": "2025-06-18T16:52:05Z" }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" + "task": { + "created_at": "2025-06-18T16:52:05Z", + "database_id": "storefront", + "status": "pending", + "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", + "type": "create" + } }, "required": [ - "type" + "task", + "database" ] }, - "BackupScheduleSpec": { + "Database": { "type": "object", "properties": { - "cron_expression": { - "type": "string", - "description": "The cron expression for this schedule.", - "example": "0 6 * * ?", - "maxLength": 32 + "available_upgrades": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AvailableUpgrade" + }, + "description": "Newer stable image versions available in the same Postgres major / Spock major bucket. Present only when ?include=available_upgrades is set.", + "example": [ + { + "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", + "postgres_version": "17.10", + "spock_version": "5" + }, + { + "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", + "postgres_version": "17.10", + "spock_version": "5" + } + ] }, - "id": { + "created_at": { "type": "string", - "description": "The unique identifier for this backup schedule.", - "example": "daily-full-backup", - "maxLength": 64 + "description": "The time that the database was created.", + "example": "2025-01-01T01:30:00Z", + "format": "date-time" }, - "type": { - "type": "string", - "description": "The type of backup to take on this schedule.", - "example": "full", - "enum": [ - "full", - "incr" - ] - } - }, - "example": { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - }, - "required": [ - "id", - "type", - "cron_expression" - ] - }, - "CancelDatabaseTaskPayload": { - "type": "object", - "properties": { - "database_id": { + "id": { "type": "string", "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", "minLength": 1, "maxLength": 36 }, - "task_id": { - "type": "string", - "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", - "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "minLength": 1, - "maxLength": 36 - } - }, - "example": { - "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "task_id": "76f9b8c0-4958-11f0-a489-3bb29577c696" - }, - "required": [ - "database_id", - "task_id" - ] - }, - "Cluster": { - "type": "object", - "properties": { - "hosts": { + "instances": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Instance" + }, + "description": "All of the instances in the database.", + "example": [ + { + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2011-12-03T04:20:14Z", + "error": "failed to get patroni status: connection refused", + "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", + "node_name": "n1", + "postgres": { + "patroni_paused": false, + "patroni_state": "unknown", + "pending_restart": false, + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + } + ], + "version": "4.10.0" + }, + "state": "stopped", + "status_updated_at": "1998-03-14T08:14:25Z", + "updated_at": "1978-12-17T01:14:06Z" + }, + { + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2011-12-03T04:20:14Z", + "error": "failed to get patroni status: connection refused", + "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", + "node_name": "n1", + "postgres": { + "patroni_paused": false, + "patroni_state": "unknown", + "pending_restart": false, + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + } + ], + "version": "4.10.0" + }, + "state": "stopped", + "status_updated_at": "1998-03-14T08:14:25Z", + "updated_at": "1978-12-17T01:14:06Z" + }, + { + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2011-12-03T04:20:14Z", + "error": "failed to get patroni status: connection refused", + "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", + "node_name": "n1", + "postgres": { + "patroni_paused": false, + "patroni_state": "unknown", + "pending_restart": false, + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + } + ], + "version": "4.10.0" + }, + "state": "stopped", + "status_updated_at": "1998-03-14T08:14:25Z", + "updated_at": "1978-12-17T01:14:06Z" + }, + { + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2011-12-03T04:20:14Z", + "error": "failed to get patroni status: connection refused", + "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", + "node_name": "n1", + "postgres": { + "patroni_paused": false, + "patroni_state": "unknown", + "pending_restart": false, + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + } + ], + "version": "4.10.0" + }, + "state": "stopped", + "status_updated_at": "1998-03-14T08:14:25Z", + "updated_at": "1978-12-17T01:14:06Z" + } + ] + }, + "service_instances": { "type": "array", "items": { - "$ref": "#/components/schemas/Host" + "$ref": "#/components/schemas/ServiceInstance" }, - "description": "All of the hosts in the cluster.", + "description": "Service instances running alongside this database.", "example": [ { - "client_addresses": [ - "10.24.34.2", - "i-0123456789abcdef.ec2.internal" - ], - "cohort": { - "cohort_id": "zdjfu3tfxg1cihv3146ro3hy2", - "control_available": true, - "member_id": "lah4bsznw6kc0hp7biylmmmll", - "type": "swarm" - }, - "cpus": 16, - "data_dir": "/data", - "default_pgedge_version": { - "postgres_version": "17.6", - "spock_version": "5" - }, - "etcd_mode": "server", - "id": "us-east-1", - "memory": "16GB", - "orchestrator": "swarm", - "peer_addresses": [ - "10.24.34.2", - "i-0123456789abcdef.ec2.internal" - ], + "created_at": "2025-01-28T10:00:00Z", + "database_id": "production", + "error": "failed to start container: image not found", + "host_id": "host-1", + "service_id": "mcp-server", + "service_instance_id": "mcp-server-host-1", + "state": "running", "status": { - "components": {}, - "state": "healthy", - "updated_at": "2025-06-17T00:00:00Z" - }, - "supported_pgedge_versions": [ - { - "postgres_version": "17.6", - "spock_version": "5" - }, - { - "postgres_version": "18.1", - "spock_version": "5" + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "container_id": "a1b2c3d4e5f6", + "health_check": { + "checked_at": "2025-01-28T10:00:00Z", + "message": "Connection refused", + "status": "healthy" }, - { - "postgres_version": "16.10", - "spock_version": "5" - } - ] + "image_version": "1.0.0", + "last_health_at": "2025-01-28T10:00:00Z", + "ports": [ + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + } + ], + "service_ready": true + }, + "updated_at": "2025-01-28T10:05:00Z" }, { - "client_addresses": [ - "10.24.35.2", - "i-058731542fee493f.ec2.internal" - ], - "cohort": { - "cohort_id": "zdjfu3tfxg1cihv3146ro3hy2", - "control_available": true, - "member_id": "cb88u9jael2psnepep5iuzb4r", - "type": "swarm" - }, - "cpus": 16, - "data_dir": "/data", - "default_pgedge_version": { - "postgres_version": "17.6", - "spock_version": "5" - }, - "etcd_mode": "server", - "id": "ap-south-1", - "memory": "16GB", - "orchestrator": "swarm", - "peer_addresses": [ - "10.24.35.2", - "i-058731542fee493f.ec2.internal" - ], + "created_at": "2025-01-28T10:00:00Z", + "database_id": "production", + "error": "failed to start container: image not found", + "host_id": "host-1", + "service_id": "mcp-server", + "service_instance_id": "mcp-server-host-1", + "state": "running", "status": { - "components": {}, - "state": "healthy", - "updated_at": "2025-06-17T00:00:00Z" - }, - "supported_pgedge_versions": [ - { - "postgres_version": "17.6", - "spock_version": "5" - }, - { - "postgres_version": "18.1", - "spock_version": "5" + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "container_id": "a1b2c3d4e5f6", + "health_check": { + "checked_at": "2025-01-28T10:00:00Z", + "message": "Connection refused", + "status": "healthy" }, - { - "postgres_version": "16.10", - "spock_version": "5" - } - ] + "image_version": "1.0.0", + "last_health_at": "2025-01-28T10:00:00Z", + "ports": [ + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + } + ], + "service_ready": true + }, + "updated_at": "2025-01-28T10:05:00Z" }, { - "client_addresses": [ - "10.24.36.2", - "i-494027b7b53f6a23.ec2.internal" - ], - "cohort": { - "cohort_id": "zdjfu3tfxg1cihv3146ro3hy2", - "control_available": true, - "member_id": "u7u9i3nhqunxc4wj577l6ecb0", - "type": "swarm" - }, - "cpus": 16, - "data_dir": "/data", - "default_pgedge_version": { - "postgres_version": "17.6", - "spock_version": "5" - }, - "etcd_mode": "client", - "id": "eu-central-1", - "memory": "16GB", - "orchestrator": "swarm", - "peer_addresses": [ - "10.24.36.2", - "i-494027b7b53f6a23.ec2.internal" - ], + "created_at": "2025-01-28T10:00:00Z", + "database_id": "production", + "error": "failed to start container: image not found", + "host_id": "host-1", + "service_id": "mcp-server", + "service_instance_id": "mcp-server-host-1", + "state": "running", "status": { - "components": {}, - "state": "healthy", - "updated_at": "2025-06-17T00:00:00Z" - }, - "supported_pgedge_versions": [ - { - "postgres_version": "17.6", - "spock_version": "5" + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "container_id": "a1b2c3d4e5f6", + "health_check": { + "checked_at": "2025-01-28T10:00:00Z", + "message": "Connection refused", + "status": "healthy" }, - { - "postgres_version": "18.1", - "spock_version": "5" + "image_version": "1.0.0", + "last_health_at": "2025-01-28T10:00:00Z", + "ports": [ + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + } + ], + "service_ready": true + }, + "updated_at": "2025-01-28T10:05:00Z" + }, + { + "created_at": "2025-01-28T10:00:00Z", + "database_id": "production", + "error": "failed to start container: image not found", + "host_id": "host-1", + "service_id": "mcp-server", + "service_instance_id": "mcp-server-host-1", + "state": "running", + "status": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "container_id": "a1b2c3d4e5f6", + "health_check": { + "checked_at": "2025-01-28T10:00:00Z", + "message": "Connection refused", + "status": "healthy" }, - { - "postgres_version": "16.10", - "spock_version": "5" - } - ] + "image_version": "1.0.0", + "last_health_at": "2025-01-28T10:00:00Z", + "ports": [ + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + } + ], + "service_ready": true + }, + "updated_at": "2025-01-28T10:05:00Z" } ] }, - "id": { + "spec": { + "$ref": "#/components/schemas/DatabaseSpec" + }, + "state": { + "type": "string", + "description": "Current state of the database.", + "example": "available", + "enum": [ + "creating", + "modifying", + "available", + "deleting", + "degraded", + "failed", + "restoring", + "unknown" + ] + }, + "tenant_id": { "type": "string", "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", "minLength": 1, "maxLength": 36 }, - "status": { - "$ref": "#/components/schemas/ClusterStatus" + "updated_at": { + "type": "string", + "description": "The time that the database was last updated.", + "example": "2025-01-01T02:30:00Z", + "format": "date-time" } }, "example": { - "hosts": [ + "created_at": "2025-06-18T16:52:05Z", + "id": "storefront", + "instances": [ { - "client_addresses": [ - "10.24.34.2", - "i-0123456789abcdef.ec2.internal" - ], - "cohort": { - "cohort_id": "zdjfu3tfxg1cihv3146ro3hy2", - "control_available": true, - "member_id": "lah4bsznw6kc0hp7biylmmmll", - "type": "swarm" + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 }, - "cpus": 16, - "data_dir": "/data", - "default_pgedge_version": { - "postgres_version": "17.6", - "spock_version": "5" + "created_at": "2025-06-18T16:52:22Z", + "host_id": "us-east-1", + "id": "storefront-n1-689qacsi", + "node_name": "n1", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" }, - "etcd_mode": "server", - "id": "us-east-1", - "memory": "16GB", - "orchestrator": "swarm", - "peer_addresses": [ - "10.24.34.2", - "i-0123456789abcdef.ec2.internal" - ], - "status": { - "components": {}, - "state": "healthy", - "updated_at": "2025-06-17T00:00:00Z" + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n1n3", + "provider_node": "n3", + "status": "replicating" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "replicating" + } + ], + "version": "4.0.10" }, - "supported_pgedge_versions": [ - { - "postgres_version": "17.6", - "spock_version": "5" - }, - { - "postgres_version": "18.1", - "spock_version": "5" - }, - { - "postgres_version": "16.10", - "spock_version": "5" - } - ] + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:36Z" }, { - "client_addresses": [ - "10.24.35.2", - "i-058731542fee493f.ec2.internal" - ], - "cohort": { - "cohort_id": "zdjfu3tfxg1cihv3146ro3hy2", - "control_available": true, - "member_id": "cb88u9jael2psnepep5iuzb4r", - "type": "swarm" + "connection_info": { + "addresses": [ + "10.24.35.2", + "i-058731542fee493f.ec2.internal" + ], + "port": 5432 }, - "cpus": 16, - "data_dir": "/data", - "default_pgedge_version": { - "postgres_version": "17.6", - "spock_version": "5" + "created_at": "2025-06-18T16:52:22Z", + "host_id": "ap-south-1", + "id": "storefront-n2-9ptayhma", + "node_name": "n2", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" }, - "etcd_mode": "server", - "id": "ap-south-1", - "memory": "16GB", - "orchestrator": "swarm", - "peer_addresses": [ - "10.24.35.2", - "i-058731542fee493f.ec2.internal" - ], - "status": { - "components": {}, - "state": "healthy", - "updated_at": "2025-06-17T00:00:00Z" + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n2n1", + "provider_node": "n1", + "status": "replicating" + }, + { + "name": "sub_n2n3", + "provider_node": "n3", + "status": "replicating" + } + ], + "version": "4.0.10" }, - "supported_pgedge_versions": [ - { - "postgres_version": "17.6", - "spock_version": "5" - }, - { - "postgres_version": "18.1", - "spock_version": "5" - }, - { - "postgres_version": "16.10", - "spock_version": "5" - } - ] + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:01Z" }, { - "client_addresses": [ - "10.24.36.2", - "i-494027b7b53f6a23.ec2.internal" - ], - "cohort": { - "cohort_id": "zdjfu3tfxg1cihv3146ro3hy2", - "control_available": true, - "member_id": "u7u9i3nhqunxc4wj577l6ecb0", - "type": "swarm" + "connection_info": { + "addresses": [ + "10.24.36.2", + "i-494027b7b53f6a23.ec2.internal" + ], + "port": 5432 }, - "cpus": 16, - "data_dir": "/data", - "default_pgedge_version": { - "postgres_version": "17.6", - "spock_version": "5" + "created_at": "2025-06-18T16:52:22Z", + "host_id": "eu-central-1", + "id": "storefront-n3-ant97dj4", + "node_name": "n3", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" }, - "etcd_mode": "client", - "id": "eu-central-1", - "memory": "16GB", - "orchestrator": "swarm", - "peer_addresses": [ - "10.24.36.2", - "i-494027b7b53f6a23.ec2.internal" - ], - "status": { - "components": {}, - "state": "healthy", - "updated_at": "2025-06-17T00:00:00Z" + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n3n1", + "provider_node": "n1", + "status": "replicating" + }, + { + "name": "sub_n3n2", + "provider_node": "n2", + "status": "replicating" + } + ], + "version": "4.0.10" }, - "supported_pgedge_versions": [ - { - "postgres_version": "17.6", - "spock_version": "5" - }, - { - "postgres_version": "18.1", - "spock_version": "5" - }, - { - "postgres_version": "16.10", - "spock_version": "5" - } - ] + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:01Z" } ], - "id": "production", - "status": { - "state": "available" - } + "spec": { + "database_name": "storefront", + "database_users": [ + { + "attributes": [ + "SUPERUSER", + "LOGIN" + ], + "db_owner": true, + "username": "admin" + } + ], + "nodes": [ + { + "host_ids": [ + "us-east-1" + ], + "name": "n1" + }, + { + "host_ids": [ + "ap-south-1" + ], + "name": "n2" + }, + { + "host_ids": [ + "eu-central-1" + ], + "name": "n3" + } + ], + "port": 5432, + "postgres_version": "17.6", + "spock_version": "5" + }, + "state": "restoring", + "updated_at": "2025-06-18T17:58:59Z" }, "required": [ "id", - "status", - "hosts" + "created_at", + "updated_at", + "state" ] }, - "ClusterCredentials": { + "Database2": { "type": "object", "properties": { - "ca_cert": { - "type": "string", - "description": "The base64-encoded CA certificate for the cluster.", - "example": "ZGE4NDdkMzMtM2FiYi00YzE2LTkzOGQtNDRkODU2ZDFlZWZlCg==" - }, - "client_cert": { - "type": "string", - "description": "The base64-encoded etcd client certificate for the new cluster member.", - "example": "NWM0MGMyZTAtYjAyYS00NzkxLTk0YjAtMjMyN2EyZGQ4ZDc3Cg==" - }, - "client_key": { - "type": "string", - "description": "The base64-encoded etcd client key for the new cluster member.", - "example": "Y2FlNjhmODQtYjE1Ni00YWYyLWFhMWEtM2FhNzI2MmVhYTM0Cg==" - }, - "password": { - "type": "string", - "description": "The Etcd password for the new host.", - "example": "a78v2x866zirk4o737gjdssfi" - }, - "server_cert": { - "type": "string", - "description": "The base64-encoded etcd server certificate for the new cluster member.", - "example": "Nzc1OGQyY2UtZjdjOC00YmE4LTk2ZmQtOWE3MjVmYmY3NDdiCg==" + "available_upgrades": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AvailableUpgrade" + }, + "description": "Newer stable image versions available in the same Postgres major / Spock major bucket. Present only when ?include=available_upgrades is set.", + "example": [ + { + "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", + "postgres_version": "17.10", + "spock_version": "5" + }, + { + "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", + "postgres_version": "17.10", + "spock_version": "5" + } + ] }, - "server_key": { + "created_at": { "type": "string", - "description": "The base64-encoded etcd server key for the new cluster member.", - "example": "NWRhNzY1ZGUtNzJkMi00OTU3LTk4ODUtOWRiZThjOGE5MGQ3Cg==" + "description": "The time that the database was created.", + "example": "2025-01-01T01:30:00Z", + "format": "date-time" }, - "username": { + "id": { "type": "string", - "description": "The Etcd username for the new host.", - "example": "host-2" - } - }, - "example": { - "ca_cert": "ZGE4NDdkMzMtM2FiYi00YzE2LTkzOGQtNDRkODU2ZDFlZWZlCg==", - "client_cert": "NWM0MGMyZTAtYjAyYS00NzkxLTk0YjAtMjMyN2EyZGQ4ZDc3Cg==", - "client_key": "Y2FlNjhmODQtYjE1Ni00YWYyLWFhMWEtM2FhNzI2MmVhYTM0Cg==", - "password": "a78v2x866zirk4o737gjdssfi", - "server_cert": "Nzc1OGQyY2UtZjdjOC00YmE4LTk2ZmQtOWE3MjVmYmY3NDdiCg==", - "server_key": "NWRhNzY1ZGUtNzJkMi00OTU3LTk4ODUtOWRiZThjOGE5MGQ3Cg==", - "username": "host-2" - }, - "required": [ - "username", - "password", - "ca_cert", - "client_cert", - "client_key", - "server_cert", - "server_key" - ] - }, - "ClusterJoinOptions": { - "type": "object", - "properties": { - "credentials": { - "$ref": "#/components/schemas/ClusterCredentials" - }, - "leader": { - "$ref": "#/components/schemas/EtcdClusterMember" - } - }, - "example": { - "credentials": { - "ca_cert": "ZGE4NDdkMzMtM2FiYi00YzE2LTkzOGQtNDRkODU2ZDFlZWZlCg==", - "client_cert": "NWM0MGMyZTAtYjAyYS00NzkxLTk0YjAtMjMyN2EyZGQ4ZDc3Cg==", - "client_key": "Y2FlNjhmODQtYjE1Ni00YWYyLWFhMWEtM2FhNzI2MmVhYTM0Cg==", - "password": "a78v2x866zirk4o737gjdssfi", - "server_cert": "Nzc1OGQyY2UtZjdjOC00YmE4LTk2ZmQtOWE3MjVmYmY3NDdiCg==", - "server_key": "NWRhNzY1ZGUtNzJkMi00OTU3LTk4ODUtOWRiZThjOGE5MGQ3Cg==", - "username": "host-2" + "description": "Unique identifier for the database.", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 }, - "leader": { - "client_urls": [ - "http://192.168.1.1:2379" - ], - "name": "host-1", - "peer_urls": [ - "http://192.168.1.1:2380" + "instances": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Instance" + }, + "description": "All of the instances in the database.", + "example": [ + { + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2011-03-15T17:48:48Z", + "error": "failed to get patroni status: connection refused", + "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", + "node_name": "n1", + "postgres": { + "patroni_paused": false, + "patroni_state": "unknown", + "pending_restart": true, + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + } + ], + "version": "4.10.0" + }, + "state": "available", + "status_updated_at": "1993-04-25T23:06:28Z", + "updated_at": "1981-08-22T23:20:01Z" + }, + { + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2011-03-15T17:48:48Z", + "error": "failed to get patroni status: connection refused", + "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", + "node_name": "n1", + "postgres": { + "patroni_paused": false, + "patroni_state": "unknown", + "pending_restart": true, + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + } + ], + "version": "4.10.0" + }, + "state": "available", + "status_updated_at": "1993-04-25T23:06:28Z", + "updated_at": "1981-08-22T23:20:01Z" + }, + { + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2011-03-15T17:48:48Z", + "error": "failed to get patroni status: connection refused", + "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", + "node_name": "n1", + "postgres": { + "patroni_paused": false, + "patroni_state": "unknown", + "pending_restart": true, + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + } + ], + "version": "4.10.0" + }, + "state": "available", + "status_updated_at": "1993-04-25T23:06:28Z", + "updated_at": "1981-08-22T23:20:01Z" + }, + { + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2011-03-15T17:48:48Z", + "error": "failed to get patroni status: connection refused", + "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", + "node_name": "n1", + "postgres": { + "patroni_paused": false, + "patroni_state": "unknown", + "pending_restart": true, + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + } + ], + "version": "4.10.0" + }, + "state": "available", + "status_updated_at": "1993-04-25T23:06:28Z", + "updated_at": "1981-08-22T23:20:01Z" + } ] - } - }, - "required": [ - "leader", - "credentials" - ] - }, - "ClusterJoinRequest": { - "type": "object", - "properties": { - "addresses": { + }, + "service_instances": { "type": "array", "items": { - "type": "string", - "example": "o47", - "minLength": 3, - "maxLength": 128 + "$ref": "#/components/schemas/ServiceInstance" }, - "description": "The peer addresses of the host that's joining the cluster.", + "description": "Service instances running alongside this database.", "example": [ - "10.1.0.113", - "ip-10-1-0-113.ec2.internal" + { + "created_at": "2025-01-28T10:00:00Z", + "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "error": "failed to start container: image not found", + "host_id": "host-1", + "service_id": "mcp-server", + "service_instance_id": "mcp-server-host-1", + "state": "running", + "status": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "container_id": "a1b2c3d4e5f6", + "health_check": { + "checked_at": "2025-01-28T10:00:00Z", + "message": "Connection refused", + "status": "healthy" + }, + "image_version": "1.0.0", + "last_health_at": "2025-01-28T10:00:00Z", + "ports": [ + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + } + ], + "service_ready": true + }, + "updated_at": "2025-01-28T10:05:00Z" + }, + { + "created_at": "2025-01-28T10:00:00Z", + "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "error": "failed to start container: image not found", + "host_id": "host-1", + "service_id": "mcp-server", + "service_instance_id": "mcp-server-host-1", + "state": "running", + "status": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "container_id": "a1b2c3d4e5f6", + "health_check": { + "checked_at": "2025-01-28T10:00:00Z", + "message": "Connection refused", + "status": "healthy" + }, + "image_version": "1.0.0", + "last_health_at": "2025-01-28T10:00:00Z", + "ports": [ + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + } + ], + "service_ready": true + }, + "updated_at": "2025-01-28T10:05:00Z" + }, + { + "created_at": "2025-01-28T10:00:00Z", + "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "error": "failed to start container: image not found", + "host_id": "host-1", + "service_id": "mcp-server", + "service_instance_id": "mcp-server-host-1", + "state": "running", + "status": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "container_id": "a1b2c3d4e5f6", + "health_check": { + "checked_at": "2025-01-28T10:00:00Z", + "message": "Connection refused", + "status": "healthy" + }, + "image_version": "1.0.0", + "last_health_at": "2025-01-28T10:00:00Z", + "ports": [ + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + } + ], + "service_ready": true + }, + "updated_at": "2025-01-28T10:05:00Z" + }, + { + "created_at": "2025-01-28T10:00:00Z", + "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "error": "failed to start container: image not found", + "host_id": "host-1", + "service_id": "mcp-server", + "service_instance_id": "mcp-server-host-1", + "state": "running", + "status": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "container_id": "a1b2c3d4e5f6", + "health_check": { + "checked_at": "2025-01-28T10:00:00Z", + "message": "Connection refused", + "status": "healthy" + }, + "image_version": "1.0.0", + "last_health_at": "2025-01-28T10:00:00Z", + "ports": [ + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + } + ], + "service_ready": true + }, + "updated_at": "2025-01-28T10:05:00Z" + } ] }, - "embedded_etcd_enabled": { - "type": "boolean", - "description": "True if the joining member is configured to run an embedded an etcd server.", - "example": true + "spec": { + "$ref": "#/components/schemas/DatabaseSpec3" }, - "host_id": { + "state": { "type": "string", - "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", + "description": "Current state of the database.", + "example": "deleting", + "enum": [ + "creating", + "modifying", + "available", + "deleting", + "degraded", + "failed", + "restoring", + "unknown" + ] + }, + "tenant_id": { + "type": "string", + "description": "Unique identifier for the database's owner.", "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", "minLength": 1, "maxLength": 36 }, - "token": { + "updated_at": { "type": "string", - "description": "Token to join the cluster.", - "example": "PGEDGE-dd440afcf5de20ef8e8cf54f6cb9f125fd55f90e64faa94b906130b31235e730-41e975f41d7ea61058f2fe2572cb52dd", - "pattern": "^PGEDGE-[\\w]{64}-[\\w]{32}$" + "description": "The time that the database was last updated.", + "example": "2025-01-01T02:30:00Z", + "format": "date-time" } }, "example": { - "addresses": [ - "10.1.0.113", - "ip-10-1-0-113.ec2.internal" + "created_at": "2025-06-18T16:52:05Z", + "id": "storefront", + "instances": [ + { + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2025-06-18T16:52:22Z", + "host_id": "us-east-1", + "id": "storefront-n1-689qacsi", + "node_name": "n1", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n1n3", + "provider_node": "n3", + "status": "replicating" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "replicating" + } + ], + "version": "4.0.10" + }, + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:36Z" + }, + { + "connection_info": { + "addresses": [ + "10.24.35.2", + "i-058731542fee493f.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2025-06-18T16:52:22Z", + "host_id": "ap-south-1", + "id": "storefront-n2-9ptayhma", + "node_name": "n2", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n2n1", + "provider_node": "n1", + "status": "replicating" + }, + { + "name": "sub_n2n3", + "provider_node": "n3", + "status": "replicating" + } + ], + "version": "4.0.10" + }, + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:01Z" + }, + { + "connection_info": { + "addresses": [ + "10.24.36.2", + "i-494027b7b53f6a23.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2025-06-18T16:52:22Z", + "host_id": "eu-central-1", + "id": "storefront-n3-ant97dj4", + "node_name": "n3", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n3n1", + "provider_node": "n1", + "status": "replicating" + }, + { + "name": "sub_n3n2", + "provider_node": "n2", + "status": "replicating" + } + ], + "version": "4.0.10" + }, + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:01Z" + } ], - "embedded_etcd_enabled": true, - "host_id": "host-1", - "token": "PGEDGE-dd440afcf5de20ef8e8cf54f6cb9f125fd55f90e64faa94b906130b31235e730-41e975f41d7ea61058f2fe2572cb52dd" + "spec": { + "database_name": "storefront", + "database_users": [ + { + "attributes": [ + "SUPERUSER", + "LOGIN" + ], + "db_owner": true, + "username": "admin" + } + ], + "nodes": [ + { + "host_ids": [ + "us-east-1" + ], + "name": "n1" + }, + { + "host_ids": [ + "ap-south-1" + ], + "name": "n2" + }, + { + "host_ids": [ + "eu-central-1" + ], + "name": "n3" + } + ], + "port": 5432, + "postgres_version": "17.6", + "spock_version": "5" + }, + "state": "restoring", + "updated_at": "2025-06-18T17:58:59Z" }, "required": [ - "embedded_etcd_enabled", - "token", - "host_id", - "addresses" + "id", + "created_at", + "updated_at", + "state" ] }, - "ClusterJoinToken": { + "Database3": { "type": "object", "properties": { - "server_urls": { + "available_upgrades": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AvailableUpgrade" + }, + "description": "Newer stable image versions available in the same Postgres major / Spock major bucket. Present only when ?include=available_upgrades is set.", + "example": [ + { + "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", + "postgres_version": "17.10", + "spock_version": "5" + }, + { + "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", + "postgres_version": "17.10", + "spock_version": "5" + }, + { + "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", + "postgres_version": "17.10", + "spock_version": "5" + } + ] + }, + "created_at": { + "type": "string", + "description": "The time that the database was created.", + "example": "2025-01-01T01:30:00Z", + "format": "date-time" + }, + "id": { + "type": "string", + "description": "Unique identifier for the database.", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 + }, + "instances": { "type": "array", "items": { - "type": "string", - "example": "Itaque placeat." + "$ref": "#/components/schemas/Instance" }, - "description": "Existing server to join", + "description": "All of the instances in the database.", "example": [ - "http://192.168.1.1:3000" + { + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2011-03-15T17:48:48Z", + "error": "failed to get patroni status: connection refused", + "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", + "node_name": "n1", + "postgres": { + "patroni_paused": false, + "patroni_state": "unknown", + "pending_restart": true, + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + } + ], + "version": "4.10.0" + }, + "state": "available", + "status_updated_at": "1993-04-25T23:06:28Z", + "updated_at": "1981-08-22T23:20:01Z" + }, + { + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2011-03-15T17:48:48Z", + "error": "failed to get patroni status: connection refused", + "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", + "node_name": "n1", + "postgres": { + "patroni_paused": false, + "patroni_state": "unknown", + "pending_restart": true, + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + } + ], + "version": "4.10.0" + }, + "state": "available", + "status_updated_at": "1993-04-25T23:06:28Z", + "updated_at": "1981-08-22T23:20:01Z" + } ] }, - "token": { - "type": "string", - "description": "Token to join an existing cluster.", - "example": "PGEDGE-dd440afcf5de20ef8e8cf54f6cb9f125fd55f90e64faa94b906130b31235e730-41e975f41d7ea61058f2fe2572cb52dd" - } - }, - "example": { - "server_urls": [ - "http://192.168.1.1:3000" - ], - "token": "PGEDGE-dd440afcf5de20ef8e8cf54f6cb9f125fd55f90e64faa94b906130b31235e730-41e975f41d7ea61058f2fe2572cb52dd" - }, - "required": [ - "token", - "server_urls" - ] - }, - "ClusterStatus": { - "type": "object", - "properties": { + "service_instances": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ServiceInstance" + }, + "description": "Service instances running alongside this database.", + "example": [ + { + "created_at": "2025-01-28T10:00:00Z", + "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "error": "failed to start container: image not found", + "host_id": "host-1", + "service_id": "mcp-server", + "service_instance_id": "mcp-server-host-1", + "state": "running", + "status": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "container_id": "a1b2c3d4e5f6", + "health_check": { + "checked_at": "2025-01-28T10:00:00Z", + "message": "Connection refused", + "status": "healthy" + }, + "image_version": "1.0.0", + "last_health_at": "2025-01-28T10:00:00Z", + "ports": [ + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + } + ], + "service_ready": true + }, + "updated_at": "2025-01-28T10:05:00Z" + }, + { + "created_at": "2025-01-28T10:00:00Z", + "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "error": "failed to start container: image not found", + "host_id": "host-1", + "service_id": "mcp-server", + "service_instance_id": "mcp-server-host-1", + "state": "running", + "status": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "container_id": "a1b2c3d4e5f6", + "health_check": { + "checked_at": "2025-01-28T10:00:00Z", + "message": "Connection refused", + "status": "healthy" + }, + "image_version": "1.0.0", + "last_health_at": "2025-01-28T10:00:00Z", + "ports": [ + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + } + ], + "service_ready": true + }, + "updated_at": "2025-01-28T10:05:00Z" + }, + { + "created_at": "2025-01-28T10:00:00Z", + "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "error": "failed to start container: image not found", + "host_id": "host-1", + "service_id": "mcp-server", + "service_instance_id": "mcp-server-host-1", + "state": "running", + "status": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "container_id": "a1b2c3d4e5f6", + "health_check": { + "checked_at": "2025-01-28T10:00:00Z", + "message": "Connection refused", + "status": "healthy" + }, + "image_version": "1.0.0", + "last_health_at": "2025-01-28T10:00:00Z", + "ports": [ + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + } + ], + "service_ready": true + }, + "updated_at": "2025-01-28T10:05:00Z" + } + ] + }, + "spec": { + "$ref": "#/components/schemas/DatabaseSpec4" + }, "state": { "type": "string", - "description": "The current state of the cluster.", - "example": "error", + "description": "Current state of the database.", + "example": "deleting", "enum": [ + "creating", + "modifying", "available", - "error" - ] - } - }, - "example": { - "state": "error" - }, - "required": [ - "state" - ] - }, - "ComponentStatus": { - "type": "object", - "properties": { - "details": { - "type": "object", - "description": "Additional details about the component.", - "example": { - "alarms": [ - "3: NOSPACE" - ] - }, - "additionalProperties": true - }, - "error": { - "type": "string", - "description": "Error message from any errors that occurred during the health check.", - "example": "failed to connect to etcd" - }, - "healthy": { - "type": "boolean", - "description": "Indicates if the component is healthy.", - "example": false - } - }, - "example": { - "details": { - "alarms": [ - "3: NOSPACE" + "deleting", + "degraded", + "failed", + "restoring", + "unknown" ] }, - "error": "failed to connect to etcd", - "healthy": false - }, - "required": [ - "healthy" - ] - }, - "CreateDatabaseRequest": { - "type": "object", - "properties": { - "id": { + "tenant_id": { "type": "string", - "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", + "description": "Unique identifier for the database's owner.", "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", "minLength": 1, "maxLength": 36 }, - "spec": { - "$ref": "#/components/schemas/DatabaseSpec" - }, - "tenant_id": { + "updated_at": { "type": "string", - "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", - "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "minLength": 1, - "maxLength": 36 + "description": "The time that the database was last updated.", + "example": "2025-01-01T02:30:00Z", + "format": "date-time" } }, "example": { + "created_at": "2025-06-18T16:52:05Z", "id": "storefront", - "spec": { - "database_name": "storefront", - "database_users": [ - { - "attributes": [ - "LOGIN", - "SUPERUSER" + "instances": [ + { + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" ], - "db_owner": true, - "password": "password", - "username": "admin" - } - ], - "nodes": [ - { - "host_ids": [ - "us-east-1" + "port": 5432 + }, + "created_at": "2025-06-18T16:52:22Z", + "host_id": "us-east-1", + "id": "storefront-n1-689qacsi", + "node_name": "n1", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n1n3", + "provider_node": "n3", + "status": "replicating" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "replicating" + } ], - "name": "n1" + "version": "4.0.10" }, - { - "host_ids": [ - "ap-south-1" + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:36Z" + }, + { + "connection_info": { + "addresses": [ + "10.24.35.2", + "i-058731542fee493f.ec2.internal" ], - "name": "n2" + "port": 5432 }, - { - "host_ids": [ - "eu-central-1" + "created_at": "2025-06-18T16:52:22Z", + "host_id": "ap-south-1", + "id": "storefront-n2-9ptayhma", + "node_name": "n2", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n2n1", + "provider_node": "n1", + "status": "replicating" + }, + { + "name": "sub_n2n3", + "provider_node": "n3", + "status": "replicating" + } ], - "name": "n3" - } - ], - "port": 5432, - "postgresql_conf": { - "max_connections": 5000 + "version": "4.0.10" + }, + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:01Z" + }, + { + "connection_info": { + "addresses": [ + "10.24.36.2", + "i-494027b7b53f6a23.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2025-06-18T16:52:22Z", + "host_id": "eu-central-1", + "id": "storefront-n3-ant97dj4", + "node_name": "n3", + "postgres": { + "patroni_state": "running", + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n3n1", + "provider_node": "n1", + "status": "replicating" + }, + { + "name": "sub_n3n2", + "provider_node": "n2", + "status": "replicating" + } + ], + "version": "4.0.10" + }, + "state": "available", + "status_updated_at": "2025-06-18T17:58:56Z", + "updated_at": "2025-06-18T17:54:01Z" } - } - }, - "required": [ - "spec" - ] - }, - "CreateDatabaseRequest2": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Unique identifier for the database.", - "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "minLength": 1, - "maxLength": 36 - }, - "spec": { - "$ref": "#/components/schemas/DatabaseSpec2" - }, - "tenant_id": { - "type": "string", - "description": "Unique identifier for the database's owner.", - "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "minLength": 1, - "maxLength": 36 - } - }, - "example": { - "id": "storefront", + ], "spec": { "database_name": "storefront", "database_users": [ { "attributes": [ - "LOGIN", - "SUPERUSER" + "SUPERUSER", + "LOGIN" ], "db_owner": true, - "password": "password", "username": "admin" } ], @@ -6921,148 +9431,20 @@ } ], "port": 5432, - "postgresql_conf": { - "max_connections": 5000 - } - } - }, - "required": [ - "spec" - ] - }, - "CreateDatabaseResponse": { - "type": "object", - "properties": { - "database": { - "$ref": "#/components/schemas/Database" - }, - "task": { - "$ref": "#/components/schemas/Task" - } - }, - "example": { - "database": { - "created_at": "2025-06-18T16:52:05Z", - "id": "storefront", - "spec": { - "database_name": "storefront", - "database_users": [ - { - "attributes": [ - "SUPERUSER", - "LOGIN" - ], - "db_owner": true, - "username": "admin" - } - ], - "nodes": [ - { - "host_ids": [ - "us-east-1" - ], - "name": "n1" - }, - { - "host_ids": [ - "ap-south-1" - ], - "name": "n2" - }, - { - "host_ids": [ - "eu-central-1" - ], - "name": "n3" - } - ], - "port": 5432, - "postgres_version": "17.6", - "spock_version": "5" - }, - "state": "creating", - "updated_at": "2025-06-18T16:52:05Z" - }, - "task": { - "created_at": "2025-06-18T16:52:05Z", - "database_id": "storefront", - "status": "pending", - "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", - "type": "create" - } - }, - "required": [ - "task", - "database" - ] - }, - "CreateDatabaseResponse2": { - "type": "object", - "properties": { - "database": { - "$ref": "#/components/schemas/Database2" - }, - "task": { - "$ref": "#/components/schemas/Task" - } - }, - "example": { - "database": { - "created_at": "2025-06-18T16:52:05Z", - "id": "storefront", - "spec": { - "database_name": "storefront", - "database_users": [ - { - "attributes": [ - "SUPERUSER", - "LOGIN" - ], - "db_owner": true, - "username": "admin" - } - ], - "nodes": [ - { - "host_ids": [ - "us-east-1" - ], - "name": "n1" - }, - { - "host_ids": [ - "ap-south-1" - ], - "name": "n2" - }, - { - "host_ids": [ - "eu-central-1" - ], - "name": "n3" - } - ], - "port": 5432, - "postgres_version": "17.6", - "spock_version": "5" - }, - "state": "creating", - "updated_at": "2025-06-18T16:52:05Z" + "postgres_version": "17.6", + "spock_version": "5" }, - "task": { - "created_at": "2025-06-18T16:52:05Z", - "database_id": "storefront", - "status": "pending", - "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", - "type": "create" - } + "state": "restoring", + "updated_at": "2025-06-18T17:58:59Z" }, "required": [ - "task", - "database" + "id", + "created_at", + "updated_at", + "state" ] }, - "Database": { + "Database4": { "type": "object", "properties": { "available_upgrades": { @@ -7072,6 +9454,16 @@ }, "description": "Newer stable image versions available in the same Postgres major / Spock major bucket. Present only when ?include=available_upgrades is set.", "example": [ + { + "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", + "postgres_version": "17.10", + "spock_version": "5" + }, + { + "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", + "postgres_version": "17.10", + "spock_version": "5" + }, { "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", "postgres_version": "17.10", @@ -7092,7 +9484,7 @@ }, "id": { "type": "string", - "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", + "description": "Unique identifier for the database.", "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", "minLength": 1, "maxLength": 36 @@ -7112,13 +9504,13 @@ ], "port": 5432 }, - "created_at": "1984-01-30T10:40:13Z", + "created_at": "2011-03-15T17:48:48Z", "error": "failed to get patroni status: connection refused", "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", "node_name": "n1", "postgres": { - "patroni_paused": true, + "patroni_paused": false, "patroni_state": "unknown", "pending_restart": true, "role": "primary", @@ -7145,9 +9537,9 @@ ], "version": "4.10.0" }, - "state": "modifying", - "status_updated_at": "1976-03-01T20:13:25Z", - "updated_at": "1996-05-27T17:04:41Z" + "state": "available", + "status_updated_at": "1993-04-25T23:06:28Z", + "updated_at": "1981-08-22T23:20:01Z" }, { "connection_info": { @@ -7157,13 +9549,13 @@ ], "port": 5432 }, - "created_at": "1984-01-30T10:40:13Z", + "created_at": "2011-03-15T17:48:48Z", "error": "failed to get patroni status: connection refused", "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", "node_name": "n1", "postgres": { - "patroni_paused": true, + "patroni_paused": false, "patroni_state": "unknown", "pending_restart": true, "role": "primary", @@ -7190,64 +9582,67 @@ ], "version": "4.10.0" }, - "state": "modifying", - "status_updated_at": "1976-03-01T20:13:25Z", - "updated_at": "1996-05-27T17:04:41Z" - } - ] - }, - "service_instances": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ServiceInstance" - }, - "description": "Service instances running alongside this database.", - "example": [ + "state": "available", + "status_updated_at": "1993-04-25T23:06:28Z", + "updated_at": "1981-08-22T23:20:01Z" + }, { - "created_at": "2025-01-28T10:00:00Z", - "database_id": "production", - "error": "failed to start container: image not found", - "host_id": "host-1", - "service_id": "mcp-server", - "service_instance_id": "mcp-server-host-1", - "state": "running", - "status": { + "connection_info": { "addresses": [ "10.24.34.2", "i-0123456789abcdef.ec2.internal" ], - "container_id": "a1b2c3d4e5f6", - "health_check": { - "checked_at": "2025-01-28T10:00:00Z", - "message": "Connection refused", - "status": "healthy" - }, - "image_version": "1.0.0", - "last_health_at": "2025-01-28T10:00:00Z", - "ports": [ + "port": 5432 + }, + "created_at": "2011-03-15T17:48:48Z", + "error": "failed to get patroni status: connection refused", + "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", + "node_name": "n1", + "postgres": { + "patroni_paused": false, + "patroni_state": "unknown", + "pending_restart": true, + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ { - "container_port": 8080, - "host_port": 8080, - "name": "web-client" + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" }, { - "container_port": 8080, - "host_port": 8080, - "name": "web-client" + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" }, { - "container_port": 8080, - "host_port": 8080, - "name": "web-client" + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" } ], - "service_ready": true + "version": "4.10.0" }, - "updated_at": "2025-01-28T10:05:00Z" - }, + "state": "available", + "status_updated_at": "1993-04-25T23:06:28Z", + "updated_at": "1981-08-22T23:20:01Z" + } + ] + }, + "service_instances": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ServiceInstance" + }, + "description": "Service instances running alongside this database.", + "example": [ { "created_at": "2025-01-28T10:00:00Z", - "database_id": "production", + "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "error": "failed to start container: image not found", "host_id": "host-1", "service_id": "mcp-server", @@ -7289,7 +9684,7 @@ }, { "created_at": "2025-01-28T10:00:00Z", - "database_id": "production", + "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "error": "failed to start container: image not found", "host_id": "host-1", "service_id": "mcp-server", @@ -7331,7 +9726,7 @@ }, { "created_at": "2025-01-28T10:00:00Z", - "database_id": "production", + "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "error": "failed to start container: image not found", "host_id": "host-1", "service_id": "mcp-server", @@ -7374,12 +9769,12 @@ ] }, "spec": { - "$ref": "#/components/schemas/DatabaseSpec" + "$ref": "#/components/schemas/DatabaseSpec6" }, "state": { "type": "string", "description": "Current state of the database.", - "example": "degraded", + "example": "unknown", "enum": [ "creating", "modifying", @@ -7393,7 +9788,7 @@ }, "tenant_id": { "type": "string", - "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", + "description": "Unique identifier for the database's owner.", "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", "minLength": 1, "maxLength": 36 @@ -7567,7 +9962,7 @@ "state" ] }, - "Database2": { + "Database5": { "type": "object", "properties": { "available_upgrades": { @@ -7582,6 +9977,11 @@ "postgres_version": "17.10", "spock_version": "5" }, + { + "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", + "postgres_version": "17.10", + "spock_version": "5" + }, { "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", "postgres_version": "17.10", @@ -7698,58 +10098,61 @@ "state": "available", "status_updated_at": "1993-04-25T23:06:28Z", "updated_at": "1981-08-22T23:20:01Z" - } - ] - }, - "service_instances": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ServiceInstance" - }, - "description": "Service instances running alongside this database.", - "example": [ + }, { - "created_at": "2025-01-28T10:00:00Z", - "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "error": "failed to start container: image not found", - "host_id": "host-1", - "service_id": "mcp-server", - "service_instance_id": "mcp-server-host-1", - "state": "running", - "status": { + "connection_info": { "addresses": [ "10.24.34.2", "i-0123456789abcdef.ec2.internal" ], - "container_id": "a1b2c3d4e5f6", - "health_check": { - "checked_at": "2025-01-28T10:00:00Z", - "message": "Connection refused", - "status": "healthy" - }, - "image_version": "1.0.0", - "last_health_at": "2025-01-28T10:00:00Z", - "ports": [ + "port": 5432 + }, + "created_at": "2011-03-15T17:48:48Z", + "error": "failed to get patroni status: connection refused", + "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", + "node_name": "n1", + "postgres": { + "patroni_paused": false, + "patroni_state": "unknown", + "pending_restart": true, + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ { - "container_port": 8080, - "host_port": 8080, - "name": "web-client" + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" }, { - "container_port": 8080, - "host_port": 8080, - "name": "web-client" + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" }, { - "container_port": 8080, - "host_port": 8080, - "name": "web-client" + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" } ], - "service_ready": true + "version": "4.10.0" }, - "updated_at": "2025-01-28T10:05:00Z" - }, + "state": "available", + "status_updated_at": "1993-04-25T23:06:28Z", + "updated_at": "1981-08-22T23:20:01Z" + } + ] + }, + "service_instances": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ServiceInstance" + }, + "description": "Service instances running alongside this database.", + "example": [ { "created_at": "2025-01-28T10:00:00Z", "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", @@ -7837,12 +10240,12 @@ ] }, "spec": { - "$ref": "#/components/schemas/DatabaseSpec3" + "$ref": "#/components/schemas/DatabaseSpec7" }, "state": { "type": "string", "description": "Current state of the database.", - "example": "degraded", + "example": "available", "enum": [ "creating", "modifying", @@ -8030,7 +10433,7 @@ "state" ] }, - "Database3": { + "Database6": { "type": "object", "properties": { "available_upgrades": { @@ -8050,11 +10453,6 @@ "postgres_version": "17.10", "spock_version": "5" }, - { - "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", - "postgres_version": "17.10", - "spock_version": "5" - }, { "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", "postgres_version": "17.10", @@ -8397,12 +10795,12 @@ ] }, "spec": { - "$ref": "#/components/schemas/DatabaseSpec4" + "$ref": "#/components/schemas/DatabaseSpec8" }, "state": { "type": "string", "description": "Current state of the database.", - "example": "unknown", + "example": "available", "enum": [ "creating", "modifying", @@ -8590,7 +10988,7 @@ "state" ] }, - "Database4": { + "Database7": { "type": "object", "properties": { "available_upgrades": { @@ -8610,11 +11008,6 @@ "postgres_version": "17.10", "spock_version": "5" }, - { - "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", - "postgres_version": "17.10", - "spock_version": "5" - }, { "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", "postgres_version": "17.10", @@ -8716,31 +11109,160 @@ "status": "down" }, { - "name": "sub_n1n2", - "provider_node": "n2", - "status": "down" + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + } + ], + "version": "4.10.0" + }, + "state": "available", + "status_updated_at": "1993-04-25T23:06:28Z", + "updated_at": "1981-08-22T23:20:01Z" + }, + { + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2011-03-15T17:48:48Z", + "error": "failed to get patroni status: connection refused", + "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", + "node_name": "n1", + "postgres": { + "patroni_paused": false, + "patroni_state": "unknown", + "pending_restart": true, + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + } + ], + "version": "4.10.0" + }, + "state": "available", + "status_updated_at": "1993-04-25T23:06:28Z", + "updated_at": "1981-08-22T23:20:01Z" + } + ] + }, + "service_instances": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ServiceInstance" + }, + "description": "Service instances running alongside this database.", + "example": [ + { + "created_at": "2025-01-28T10:00:00Z", + "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "error": "failed to start container: image not found", + "host_id": "host-1", + "service_id": "mcp-server", + "service_instance_id": "mcp-server-host-1", + "state": "running", + "status": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "container_id": "a1b2c3d4e5f6", + "health_check": { + "checked_at": "2025-01-28T10:00:00Z", + "message": "Connection refused", + "status": "healthy" + }, + "image_version": "1.0.0", + "last_health_at": "2025-01-28T10:00:00Z", + "ports": [ + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + } + ], + "service_ready": true + }, + "updated_at": "2025-01-28T10:05:00Z" + }, + { + "created_at": "2025-01-28T10:00:00Z", + "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "error": "failed to start container: image not found", + "host_id": "host-1", + "service_id": "mcp-server", + "service_instance_id": "mcp-server-host-1", + "state": "running", + "status": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "container_id": "a1b2c3d4e5f6", + "health_check": { + "checked_at": "2025-01-28T10:00:00Z", + "message": "Connection refused", + "status": "healthy" + }, + "image_version": "1.0.0", + "last_health_at": "2025-01-28T10:00:00Z", + "ports": [ + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" }, { - "name": "sub_n1n2", - "provider_node": "n2", - "status": "down" + "container_port": 8080, + "host_port": 8080, + "name": "web-client" } ], - "version": "4.10.0" + "service_ready": true }, - "state": "available", - "status_updated_at": "1993-04-25T23:06:28Z", - "updated_at": "1981-08-22T23:20:01Z" - } - ] - }, - "service_instances": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ServiceInstance" - }, - "description": "Service instances running alongside this database.", - "example": [ + "updated_at": "2025-01-28T10:05:00Z" + }, { "created_at": "2025-01-28T10:00:00Z", "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", @@ -8828,12 +11350,12 @@ ] }, "spec": { - "$ref": "#/components/schemas/DatabaseSpec6" + "$ref": "#/components/schemas/DatabaseSpec9" }, "state": { "type": "string", "description": "Current state of the database.", - "example": "available", + "example": "unknown", "enum": [ "creating", "modifying", @@ -9021,936 +11543,933 @@ "state" ] }, - "Database5": { + "DatabaseConnection": { "type": "object", "properties": { - "available_upgrades": { + "target_nodes": { "type": "array", "items": { - "$ref": "#/components/schemas/AvailableUpgrade" + "type": "string", + "example": "Illo dolore." }, - "description": "Newer stable image versions available in the same Postgres major / Spock major bucket. Present only when ?include=available_upgrades is set.", + "description": "Optional ordered list of database node names. When set, the service's database connection includes only the listed nodes in the specified order.", "example": [ - { - "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", - "postgres_version": "17.10", - "spock_version": "5" - }, - { - "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", - "postgres_version": "17.10", - "spock_version": "5" - } + "n1", + "n2" ] }, - "created_at": { + "target_session_attrs": { "type": "string", - "description": "The time that the database was created.", - "example": "2025-01-01T01:30:00Z", - "format": "date-time" + "description": "Optional libpq target_session_attrs value. When set, overrides the default derived from the service config. Valid values: primary, prefer-standby, standby, read-write, any.", + "example": "primary", + "enum": [ + "primary", + "prefer-standby", + "standby", + "read-write", + "any" + ] + } + }, + "description": "Controls how the service connects to the database. When omitted, all nodes are included with the local node first and target_session_attrs is derived from the service config.", + "example": { + "target_nodes": [ + "n1", + "n2" + ], + "target_session_attrs": "primary" + } + }, + "DatabaseNodeSpec": { + "type": "object", + "properties": { + "backup_config": { + "$ref": "#/components/schemas/BackupConfigSpec" }, - "id": { + "cpus": { "type": "string", - "description": "Unique identifier for the database.", - "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "minLength": 1, - "maxLength": 36 + "description": "The number of CPUs to allocate for the database on this node and to use for tuning Postgres. It can include the SI suffix 'm', e.g. '500m' for 500 millicpus. Cannot allocate units smaller than 1m. Defaults to the number of available CPUs on the host if 0 or unspecified. Cannot allocate more CPUs than are available on the host. Whether this limit is enforced depends on the orchestrator.", + "example": "500m", + "pattern": "^[0-9]+(\\.[0-9]{1,3}|m)?$" }, - "instances": { + "host_ids": { "type": "array", "items": { - "$ref": "#/components/schemas/Instance" + "type": "string", + "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 }, - "description": "All of the instances in the database.", + "description": "The IDs of the hosts that should run this node. When multiple hosts are specified, one host will chosen as a primary, and the others will be read replicas.", + "example": [ + "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + ], + "minItems": 1 + }, + "memory": { + "type": "string", + "description": "The amount of memory in SI or IEC notation to allocate for the database on this node and to use for tuning Postgres. Defaults to the total available memory on the host. Whether this limit is enforced depends on the orchestrator.", + "example": "500M", + "maxLength": 16 + }, + "name": { + "type": "string", + "description": "The name of the database node.", + "example": "n1", + "pattern": "n[0-9]+" + }, + "orchestrator_opts": { + "$ref": "#/components/schemas/OrchestratorOpts" + }, + "patroni_port": { + "type": "integer", + "description": "The port used by Patroni for this node. Overrides the Patroni port set in the DatabaseSpec. NOTE: This field is not currently supported for Docker Swarm.", + "example": 8888, + "format": "int64", + "minimum": 0, + "maximum": 65535 + }, + "pg_hba_conf": { + "type": "array", + "items": { + "type": "string", + "example": "Sint iure eum ducimus quia deserunt animi." + }, + "description": "Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity.", + "example": [ + "host example myapp_user 10.0.0.0/8 scram-sha-256" + ] + }, + "pg_ident_conf": { + "type": "array", + "items": { + "type": "string", + "example": "Nihil qui non quae sint ea." + }, + "description": "Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries.", "example": [ + "ssl_users CN=alice,O=example alice" + ] + }, + "port": { + "type": "integer", + "description": "The port used by the Postgres database for this node. Overrides the Postgres port set in the DatabaseSpec.", + "example": 5432, + "format": "int64", + "minimum": 0, + "maximum": 65535 + }, + "postgres_version": { + "type": "string", + "description": "The Postgres version for this node in 'major.minor' format. Overrides the Postgres version set in the DatabaseSpec.", + "example": "17.6", + "pattern": "^\\d{2}\\.\\d{1,2}$" + }, + "postgresql_conf": { + "type": "object", + "description": "Additional postgresql.conf settings for this particular node. Will be merged with the settings provided by control-plane.", + "example": { + "max_connections": 1000 + }, + "additionalProperties": true + }, + "restore_config": { + "$ref": "#/components/schemas/RestoreConfigSpec" + }, + "source_node": { + "type": "string", + "description": "The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node.", + "example": "n1" + }, + "spock_version": { + "type": "string", + "description": "The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice.", + "example": "6", + "pattern": "^\\d{1}$" + } + }, + "example": { + "backup_config": { + "repositories": [ { - "connection_info": { - "addresses": [ - "10.24.34.2", - "i-0123456789abcdef.ec2.internal" - ], - "port": 5432 - }, - "created_at": "2011-03-15T17:48:48Z", - "error": "failed to get patroni status: connection refused", - "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", - "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", - "node_name": "n1", - "postgres": { - "patroni_paused": false, - "patroni_state": "unknown", - "pending_restart": true, - "role": "primary", - "version": "18.1" + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" }, - "spock": { - "read_only": "off", - "subscriptions": [ - { - "name": "sub_n1n2", - "provider_node": "n2", - "status": "down" - }, - { - "name": "sub_n1n2", - "provider_node": "n2", - "status": "down" - }, - { - "name": "sub_n1n2", - "provider_node": "n2", - "status": "down" - } - ], - "version": "4.10.0" + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" }, - "state": "available", - "status_updated_at": "1993-04-25T23:06:28Z", - "updated_at": "1981-08-22T23:20:01Z" + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + } + ], + "schedules": [ + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" }, { - "connection_info": { - "addresses": [ - "10.24.34.2", - "i-0123456789abcdef.ec2.internal" - ], - "port": 5432 - }, - "created_at": "2011-03-15T17:48:48Z", - "error": "failed to get patroni status: connection refused", - "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", - "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", - "node_name": "n1", - "postgres": { - "patroni_paused": false, - "patroni_state": "unknown", - "pending_restart": true, - "role": "primary", - "version": "18.1" - }, - "spock": { - "read_only": "off", - "subscriptions": [ - { - "name": "sub_n1n2", - "provider_node": "n2", - "status": "down" - }, - { - "name": "sub_n1n2", - "provider_node": "n2", - "status": "down" - }, - { - "name": "sub_n1n2", - "provider_node": "n2", - "status": "down" - } - ], - "version": "4.10.0" - }, - "state": "available", - "status_updated_at": "1993-04-25T23:06:28Z", - "updated_at": "1981-08-22T23:20:01Z" + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" } ] }, - "service_instances": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ServiceInstance" - }, - "description": "Service instances running alongside this database.", - "example": [ - { - "created_at": "2025-01-28T10:00:00Z", - "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "error": "failed to start container: image not found", - "host_id": "host-1", - "service_id": "mcp-server", - "service_instance_id": "mcp-server-host-1", - "state": "running", - "status": { - "addresses": [ - "10.24.34.2", - "i-0123456789abcdef.ec2.internal" + "cpus": "500m", + "host_ids": [ + "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + ], + "memory": "500M", + "name": "n1", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" ], - "container_id": "a1b2c3d4e5f6", - "health_check": { - "checked_at": "2025-01-28T10:00:00Z", - "message": "Connection refused", - "status": "healthy" + "driver_opts": { + "com.docker.network.endpoint.expose": "true" }, - "image_version": "1.0.0", - "last_health_at": "2025-01-28T10:00:00Z", - "ports": [ - { - "container_port": 8080, - "host_port": 8080, - "name": "web-client" - }, - { - "container_port": 8080, - "host_port": 8080, - "name": "web-client" - }, - { - "container_port": 8080, - "host_port": 8080, - "name": "web-client" - } - ], - "service_ready": true + "id": "traefik-public" }, - "updated_at": "2025-01-28T10:05:00Z" - }, - { - "created_at": "2025-01-28T10:00:00Z", - "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "error": "failed to start container: image not found", - "host_id": "host-1", - "service_id": "mcp-server", - "service_instance_id": "mcp-server-host-1", - "state": "running", - "status": { - "addresses": [ - "10.24.34.2", - "i-0123456789abcdef.ec2.internal" + { + "aliases": [ + "pg-db", + "db-alias" ], - "container_id": "a1b2c3d4e5f6", - "health_check": { - "checked_at": "2025-01-28T10:00:00Z", - "message": "Connection refused", - "status": "healthy" + "driver_opts": { + "com.docker.network.endpoint.expose": "true" }, - "image_version": "1.0.0", - "last_health_at": "2025-01-28T10:00:00Z", - "ports": [ - { - "container_port": 8080, - "host_port": 8080, - "name": "web-client" - }, - { - "container_port": 8080, - "host_port": 8080, - "name": "web-client" - }, - { - "container_port": 8080, - "host_port": 8080, - "name": "web-client" - } + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" ], - "service_ready": true + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" }, - "updated_at": "2025-01-28T10:05:00Z" - } - ] + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Sapiente qui ullam." + } + }, + "patroni_port": 8888, + "pg_hba_conf": [ + "host example myapp_user 10.0.0.0/8 scram-sha-256" + ], + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" + ], + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 + }, + "restore_config": { + "repository": { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" + }, + "source_database_id": "02f1a7db-fca8-4521-b57a-2a375c1ced51", + "source_database_name": "northwind", + "source_node_name": "n1" + }, + "source_node": "n1", + "spock_version": "6" + }, + "required": [ + "name", + "host_ids" + ] + }, + "DatabaseNodeSpec2": { + "type": "object", + "properties": { + "backup_config": { + "$ref": "#/components/schemas/BackupConfigSpec" }, - "spec": { - "$ref": "#/components/schemas/DatabaseSpec7" + "cpus": { + "type": "string", + "description": "The number of CPUs to allocate for the database on this node and to use for tuning Postgres. It can include the SI suffix 'm', e.g. '500m' for 500 millicpus. Cannot allocate units smaller than 1m. Defaults to the number of available CPUs on the host if 0 or unspecified. Cannot allocate more CPUs than are available on the host. Whether this limit is enforced depends on the orchestrator.", + "example": "500m", + "pattern": "^[0-9]+(\\.[0-9]{1,3}|m)?$" }, - "state": { + "host_ids": { + "type": "array", + "items": { + "type": "string", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 + }, + "description": "The IDs of the hosts that should run this node. When multiple hosts are specified, one host will chosen as a primary, and the others will be read replicas.", + "example": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "minItems": 1 + }, + "memory": { "type": "string", - "description": "Current state of the database.", - "example": "restoring", - "enum": [ - "creating", - "modifying", - "available", - "deleting", - "degraded", - "failed", - "restoring", - "unknown" + "description": "The amount of memory in SI or IEC notation to allocate for the database on this node and to use for tuning Postgres. Defaults to the total available memory on the host. Whether this limit is enforced depends on the orchestrator.", + "example": "500M", + "maxLength": 16 + }, + "name": { + "type": "string", + "description": "The name of the database node.", + "example": "n1", + "pattern": "n[0-9]+" + }, + "orchestrator_opts": { + "$ref": "#/components/schemas/OrchestratorOpts" + }, + "patroni_port": { + "type": "integer", + "description": "The port used by Patroni for this node. Overrides the Patroni port set in the DatabaseSpec. NOTE: This field is not currently supported for Docker Swarm.", + "example": 8888, + "format": "int64", + "minimum": 0, + "maximum": 65535 + }, + "pg_hba_conf": { + "type": "array", + "items": { + "type": "string", + "example": "Laboriosam placeat distinctio atque dolor autem." + }, + "description": "Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity.", + "example": [ + "host example myapp_user 10.0.0.0/8 scram-sha-256" ] }, - "tenant_id": { + "pg_ident_conf": { + "type": "array", + "items": { + "type": "string", + "example": "Et excepturi sapiente." + }, + "description": "Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries.", + "example": [ + "ssl_users CN=alice,O=example alice" + ] + }, + "port": { + "type": "integer", + "description": "The port used by the Postgres database for this node. Overrides the Postgres port set in the DatabaseSpec.", + "example": 5432, + "format": "int64", + "minimum": 0, + "maximum": 65535 + }, + "postgres_version": { "type": "string", - "description": "Unique identifier for the database's owner.", - "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "minLength": 1, - "maxLength": 36 + "description": "The Postgres version for this node in 'major.minor' format. Overrides the Postgres version set in the DatabaseSpec.", + "example": "17.6", + "pattern": "^\\d{2}\\.\\d{1,2}$" }, - "updated_at": { + "postgresql_conf": { + "type": "object", + "description": "Additional postgresql.conf settings for this particular node. Will be merged with the settings provided by control-plane.", + "example": { + "max_connections": 1000 + }, + "additionalProperties": true + }, + "restore_config": { + "$ref": "#/components/schemas/RestoreConfigSpec" + }, + "source_node": { "type": "string", - "description": "The time that the database was last updated.", - "example": "2025-01-01T02:30:00Z", - "format": "date-time" + "description": "The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node.", + "example": "n1" + }, + "spock_version": { + "type": "string", + "description": "The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice.", + "example": "6", + "pattern": "^\\d{1}$" } }, "example": { - "created_at": "2025-06-18T16:52:05Z", - "id": "storefront", - "instances": [ - { - "connection_info": { - "addresses": [ - "10.24.34.2", - "i-0123456789abcdef.ec2.internal" - ], - "port": 5432 - }, - "created_at": "2025-06-18T16:52:22Z", - "host_id": "us-east-1", - "id": "storefront-n1-689qacsi", - "node_name": "n1", - "postgres": { - "patroni_state": "running", - "role": "primary", - "version": "18.1" - }, - "spock": { - "read_only": "off", - "subscriptions": [ - { - "name": "sub_n1n3", - "provider_node": "n3", - "status": "replicating" - }, - { - "name": "sub_n1n2", - "provider_node": "n2", - "status": "replicating" - } - ], - "version": "4.0.10" - }, - "state": "available", - "status_updated_at": "2025-06-18T17:58:56Z", - "updated_at": "2025-06-18T17:54:36Z" - }, - { - "connection_info": { - "addresses": [ - "10.24.35.2", - "i-058731542fee493f.ec2.internal" - ], - "port": 5432 - }, - "created_at": "2025-06-18T16:52:22Z", - "host_id": "ap-south-1", - "id": "storefront-n2-9ptayhma", - "node_name": "n2", - "postgres": { - "patroni_state": "running", - "role": "primary", - "version": "18.1" - }, - "spock": { - "read_only": "off", - "subscriptions": [ - { - "name": "sub_n2n1", - "provider_node": "n1", - "status": "replicating" - }, - { - "name": "sub_n2n3", - "provider_node": "n3", - "status": "replicating" - } - ], - "version": "4.0.10" - }, - "state": "available", - "status_updated_at": "2025-06-18T17:58:56Z", - "updated_at": "2025-06-18T17:54:01Z" - }, - { - "connection_info": { - "addresses": [ - "10.24.36.2", - "i-494027b7b53f6a23.ec2.internal" - ], - "port": 5432 - }, - "created_at": "2025-06-18T16:52:22Z", - "host_id": "eu-central-1", - "id": "storefront-n3-ant97dj4", - "node_name": "n3", - "postgres": { - "patroni_state": "running", - "role": "primary", - "version": "18.1" + "backup_config": { + "repositories": [ + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" }, - "spock": { - "read_only": "off", - "subscriptions": [ - { - "name": "sub_n3n1", - "provider_node": "n1", - "status": "replicating" - }, - { - "name": "sub_n3n2", - "provider_node": "n2", - "status": "replicating" - } - ], - "version": "4.0.10" + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" }, - "state": "available", - "status_updated_at": "2025-06-18T17:58:56Z", - "updated_at": "2025-06-18T17:54:01Z" - } - ], - "spec": { - "database_name": "storefront", - "database_users": [ { - "attributes": [ - "SUPERUSER", - "LOGIN" - ], - "db_owner": true, - "username": "admin" + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" } ], - "nodes": [ + "schedules": [ { - "host_ids": [ - "us-east-1" - ], - "name": "n1" + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" }, { - "host_ids": [ - "ap-south-1" - ], - "name": "n2" + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" }, { - "host_ids": [ - "eu-central-1" - ], - "name": "n3" + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" } - ], - "port": 5432, - "postgres_version": "17.6", - "spock_version": "5" + ] }, - "state": "restoring", - "updated_at": "2025-06-18T17:58:59Z" + "cpus": "500m", + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "500M", + "name": "n1", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Reprehenderit atque aliquid." + } + }, + "patroni_port": 8888, + "pg_hba_conf": [ + "host example myapp_user 10.0.0.0/8 scram-sha-256" + ], + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" + ], + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 + }, + "restore_config": { + "repository": { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" + }, + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "source_database_name": "northwind", + "source_node_name": "n1" + }, + "source_node": "n1", + "spock_version": "6" }, "required": [ - "id", - "created_at", - "updated_at", - "state" + "name", + "host_ids" ] }, - "Database6": { + "DatabaseNodeSpec3": { "type": "object", "properties": { - "available_upgrades": { + "backup_config": { + "$ref": "#/components/schemas/BackupConfigSpec" + }, + "cpus": { + "type": "string", + "description": "The number of CPUs to allocate for the database on this node and to use for tuning Postgres. It can include the SI suffix 'm', e.g. '500m' for 500 millicpus. Cannot allocate units smaller than 1m. Defaults to the number of available CPUs on the host if 0 or unspecified. Cannot allocate more CPUs than are available on the host. Whether this limit is enforced depends on the orchestrator.", + "example": "500m", + "pattern": "^[0-9]+(\\.[0-9]{1,3}|m)?$" + }, + "host_ids": { "type": "array", "items": { - "$ref": "#/components/schemas/AvailableUpgrade" + "type": "string", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 }, - "description": "Newer stable image versions available in the same Postgres major / Spock major bucket. Present only when ?include=available_upgrades is set.", + "description": "The IDs of the hosts that should run this node. When multiple hosts are specified, one host will chosen as a primary, and the others will be read replicas.", "example": [ - { - "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", - "postgres_version": "17.10", - "spock_version": "5" - }, - { - "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", - "postgres_version": "17.10", - "spock_version": "5" - }, - { - "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", - "postgres_version": "17.10", - "spock_version": "5" - } - ] + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "minItems": 1 }, - "created_at": { + "memory": { "type": "string", - "description": "The time that the database was created.", - "example": "2025-01-01T01:30:00Z", - "format": "date-time" + "description": "The amount of memory in SI or IEC notation to allocate for the database on this node and to use for tuning Postgres. Defaults to the total available memory on the host. Whether this limit is enforced depends on the orchestrator.", + "example": "500M", + "maxLength": 16 }, - "id": { + "name": { "type": "string", - "description": "Unique identifier for the database.", - "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "minLength": 1, - "maxLength": 36 + "description": "The name of the database node.", + "example": "n1", + "pattern": "n[0-9]+" + }, + "orchestrator_opts": { + "$ref": "#/components/schemas/OrchestratorOpts" + }, + "patroni_port": { + "type": "integer", + "description": "The port used by Patroni for this node. Overrides the Patroni port set in the DatabaseSpec. NOTE: This field is not currently supported for Docker Swarm.", + "example": 8888, + "format": "int64", + "minimum": 0, + "maximum": 65535 }, - "instances": { + "pg_hba_conf": { "type": "array", "items": { - "$ref": "#/components/schemas/Instance" + "type": "string", + "example": "Est temporibus molestias officiis sint." }, - "description": "All of the instances in the database.", + "description": "Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity.", "example": [ - { - "connection_info": { - "addresses": [ - "10.24.34.2", - "i-0123456789abcdef.ec2.internal" - ], - "port": 5432 - }, - "created_at": "2011-03-15T17:48:48Z", - "error": "failed to get patroni status: connection refused", - "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", - "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", - "node_name": "n1", - "postgres": { - "patroni_paused": false, - "patroni_state": "unknown", - "pending_restart": true, - "role": "primary", - "version": "18.1" - }, - "spock": { - "read_only": "off", - "subscriptions": [ - { - "name": "sub_n1n2", - "provider_node": "n2", - "status": "down" - }, - { - "name": "sub_n1n2", - "provider_node": "n2", - "status": "down" - }, - { - "name": "sub_n1n2", - "provider_node": "n2", - "status": "down" - } - ], - "version": "4.10.0" - }, - "state": "available", - "status_updated_at": "1993-04-25T23:06:28Z", - "updated_at": "1981-08-22T23:20:01Z" - }, - { - "connection_info": { - "addresses": [ - "10.24.34.2", - "i-0123456789abcdef.ec2.internal" - ], - "port": 5432 - }, - "created_at": "2011-03-15T17:48:48Z", - "error": "failed to get patroni status: connection refused", - "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", - "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", - "node_name": "n1", - "postgres": { - "patroni_paused": false, - "patroni_state": "unknown", - "pending_restart": true, - "role": "primary", - "version": "18.1" - }, - "spock": { - "read_only": "off", - "subscriptions": [ - { - "name": "sub_n1n2", - "provider_node": "n2", - "status": "down" - }, - { - "name": "sub_n1n2", - "provider_node": "n2", - "status": "down" - }, - { - "name": "sub_n1n2", - "provider_node": "n2", - "status": "down" - } - ], - "version": "4.10.0" - }, - "state": "available", - "status_updated_at": "1993-04-25T23:06:28Z", - "updated_at": "1981-08-22T23:20:01Z" - }, - { - "connection_info": { - "addresses": [ - "10.24.34.2", - "i-0123456789abcdef.ec2.internal" - ], - "port": 5432 - }, - "created_at": "2011-03-15T17:48:48Z", - "error": "failed to get patroni status: connection refused", - "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", - "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", - "node_name": "n1", - "postgres": { - "patroni_paused": false, - "patroni_state": "unknown", - "pending_restart": true, - "role": "primary", - "version": "18.1" - }, - "spock": { - "read_only": "off", - "subscriptions": [ - { - "name": "sub_n1n2", - "provider_node": "n2", - "status": "down" - }, - { - "name": "sub_n1n2", - "provider_node": "n2", - "status": "down" - }, - { - "name": "sub_n1n2", - "provider_node": "n2", - "status": "down" - } - ], - "version": "4.10.0" - }, - "state": "available", - "status_updated_at": "1993-04-25T23:06:28Z", - "updated_at": "1981-08-22T23:20:01Z" - } + "host example myapp_user 10.0.0.0/8 scram-sha-256" ] }, - "service_instances": { + "pg_ident_conf": { "type": "array", "items": { - "$ref": "#/components/schemas/ServiceInstance" + "type": "string", + "example": "Ad aut velit distinctio sed." }, - "description": "Service instances running alongside this database.", + "description": "Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries.", "example": [ - { - "created_at": "2025-01-28T10:00:00Z", - "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "error": "failed to start container: image not found", - "host_id": "host-1", - "service_id": "mcp-server", - "service_instance_id": "mcp-server-host-1", - "state": "running", - "status": { - "addresses": [ - "10.24.34.2", - "i-0123456789abcdef.ec2.internal" - ], - "container_id": "a1b2c3d4e5f6", - "health_check": { - "checked_at": "2025-01-28T10:00:00Z", - "message": "Connection refused", - "status": "healthy" - }, - "image_version": "1.0.0", - "last_health_at": "2025-01-28T10:00:00Z", - "ports": [ - { - "container_port": 8080, - "host_port": 8080, - "name": "web-client" - }, - { - "container_port": 8080, - "host_port": 8080, - "name": "web-client" - }, - { - "container_port": 8080, - "host_port": 8080, - "name": "web-client" - } - ], - "service_ready": true - }, - "updated_at": "2025-01-28T10:05:00Z" - }, - { - "created_at": "2025-01-28T10:00:00Z", - "database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "error": "failed to start container: image not found", - "host_id": "host-1", - "service_id": "mcp-server", - "service_instance_id": "mcp-server-host-1", - "state": "running", - "status": { - "addresses": [ - "10.24.34.2", - "i-0123456789abcdef.ec2.internal" - ], - "container_id": "a1b2c3d4e5f6", - "health_check": { - "checked_at": "2025-01-28T10:00:00Z", - "message": "Connection refused", - "status": "healthy" - }, - "image_version": "1.0.0", - "last_health_at": "2025-01-28T10:00:00Z", - "ports": [ - { - "container_port": 8080, - "host_port": 8080, - "name": "web-client" - }, - { - "container_port": 8080, - "host_port": 8080, - "name": "web-client" - }, - { - "container_port": 8080, - "host_port": 8080, - "name": "web-client" - } - ], - "service_ready": true - }, - "updated_at": "2025-01-28T10:05:00Z" - } + "ssl_users CN=alice,O=example alice" ] }, - "spec": { - "$ref": "#/components/schemas/DatabaseSpec8" + "port": { + "type": "integer", + "description": "The port used by the Postgres database for this node. Overrides the Postgres port set in the DatabaseSpec.", + "example": 5432, + "format": "int64", + "minimum": 0, + "maximum": 65535 + }, + "postgres_version": { + "type": "string", + "description": "The Postgres version for this node in 'major.minor' format. Overrides the Postgres version set in the DatabaseSpec.", + "example": "17.6", + "pattern": "^\\d{2}\\.\\d{1,2}$" + }, + "postgresql_conf": { + "type": "object", + "description": "Additional postgresql.conf settings for this particular node. Will be merged with the settings provided by control-plane.", + "example": { + "max_connections": 1000 + }, + "additionalProperties": true }, - "state": { - "type": "string", - "description": "Current state of the database.", - "example": "available", - "enum": [ - "creating", - "modifying", - "available", - "deleting", - "degraded", - "failed", - "restoring", - "unknown" - ] + "restore_config": { + "$ref": "#/components/schemas/RestoreConfigSpec" }, - "tenant_id": { + "source_node": { "type": "string", - "description": "Unique identifier for the database's owner.", - "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "minLength": 1, - "maxLength": 36 + "description": "The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node.", + "example": "n1" }, - "updated_at": { + "spock_version": { "type": "string", - "description": "The time that the database was last updated.", - "example": "2025-01-01T02:30:00Z", - "format": "date-time" + "description": "The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice.", + "example": "6", + "pattern": "^\\d{1}$" } }, "example": { - "created_at": "2025-06-18T16:52:05Z", - "id": "storefront", - "instances": [ - { - "connection_info": { - "addresses": [ - "10.24.34.2", - "i-0123456789abcdef.ec2.internal" - ], - "port": 5432 - }, - "created_at": "2025-06-18T16:52:22Z", - "host_id": "us-east-1", - "id": "storefront-n1-689qacsi", - "node_name": "n1", - "postgres": { - "patroni_state": "running", - "role": "primary", - "version": "18.1" + "backup_config": { + "repositories": [ + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" }, - "spock": { - "read_only": "off", - "subscriptions": [ - { - "name": "sub_n1n3", - "provider_node": "n3", - "status": "replicating" - }, - { - "name": "sub_n1n2", - "provider_node": "n2", - "status": "replicating" - } - ], - "version": "4.0.10" + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + } + ], + "schedules": [ + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" }, - "state": "available", - "status_updated_at": "2025-06-18T17:58:56Z", - "updated_at": "2025-06-18T17:54:36Z" - }, - { - "connection_info": { - "addresses": [ - "10.24.35.2", - "i-058731542fee493f.ec2.internal" - ], - "port": 5432 + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" }, - "created_at": "2025-06-18T16:52:22Z", - "host_id": "ap-south-1", - "id": "storefront-n2-9ptayhma", - "node_name": "n2", - "postgres": { - "patroni_state": "running", - "role": "primary", - "version": "18.1" + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + } + ] + }, + "cpus": "500m", + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "500M", + "name": "n1", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" }, - "spock": { - "read_only": "off", - "subscriptions": [ - { - "name": "sub_n2n1", - "provider_node": "n1", - "status": "replicating" + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" }, - { - "name": "sub_n2n3", - "provider_node": "n3", - "status": "replicating" - } - ], - "version": "4.0.10" - }, - "state": "available", - "status_updated_at": "2025-06-18T17:58:56Z", - "updated_at": "2025-06-18T17:54:01Z" - }, - { - "connection_info": { - "addresses": [ - "10.24.36.2", - "i-494027b7b53f6a23.ec2.internal" - ], - "port": 5432 - }, - "created_at": "2025-06-18T16:52:22Z", - "host_id": "eu-central-1", - "id": "storefront-n3-ant97dj4", - "node_name": "n3", - "postgres": { - "patroni_state": "running", - "role": "primary", - "version": "18.1" - }, - "spock": { - "read_only": "off", - "subscriptions": [ - { - "name": "sub_n3n1", - "provider_node": "n1", - "status": "replicating" + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" }, - { - "name": "sub_n3n2", - "provider_node": "n2", - "status": "replicating" - } - ], - "version": "4.0.10" - }, - "state": "available", - "status_updated_at": "2025-06-18T17:58:56Z", - "updated_at": "2025-06-18T17:54:01Z" + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Incidunt in quas totam." } + }, + "patroni_port": 8888, + "pg_hba_conf": [ + "host example myapp_user 10.0.0.0/8 scram-sha-256" ], - "spec": { - "database_name": "storefront", - "database_users": [ - { - "attributes": [ - "SUPERUSER", - "LOGIN" - ], - "db_owner": true, - "username": "admin" - } - ], - "nodes": [ - { - "host_ids": [ - "us-east-1" - ], - "name": "n1" - }, - { - "host_ids": [ - "ap-south-1" - ], - "name": "n2" + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" + ], + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 + }, + "restore_config": { + "repository": { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" }, - { - "host_ids": [ - "eu-central-1" - ], - "name": "n3" - } - ], - "port": 5432, - "postgres_version": "17.6", - "spock_version": "5" + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" + }, + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "source_database_name": "northwind", + "source_node_name": "n1" }, - "state": "restoring", - "updated_at": "2025-06-18T17:58:59Z" + "source_node": "n1", + "spock_version": "6" }, "required": [ - "id", - "created_at", - "updated_at", - "state" + "name", + "host_ids" ] }, - "DatabaseConnection": { - "type": "object", - "properties": { - "target_nodes": { - "type": "array", - "items": { - "type": "string", - "example": "Qui ut et." - }, - "description": "Optional ordered list of database node names. When set, the service's database connection includes only the listed nodes in the specified order.", - "example": [ - "n1", - "n2" - ] - }, - "target_session_attrs": { - "type": "string", - "description": "Optional libpq target_session_attrs value. When set, overrides the default derived from the service config. Valid values: primary, prefer-standby, standby, read-write, any.", - "example": "primary", - "enum": [ - "primary", - "prefer-standby", - "standby", - "read-write", - "any" - ] - } - }, - "description": "Controls how the service connects to the database. When omitted, all nodes are included with the local node first and target_session_attrs is derived from the service config.", - "example": { - "target_nodes": [ - "n1", - "n2" - ], - "target_session_attrs": "primary" - } - }, - "DatabaseNodeSpec": { + "DatabaseNodeSpec4": { "type": "object", "properties": { "backup_config": { @@ -9966,16 +12485,14 @@ "type": "array", "items": { "type": "string", - "description": "A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens.", "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", "minLength": 1, "maxLength": 36 }, "description": "The IDs of the hosts that should run this node. When multiple hosts are specified, one host will chosen as a primary, and the others will be read replicas.", "example": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec", - "de3b1388-1f0c-42f1-a86c-59ab72f255ec", - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "minItems": 1 }, @@ -10006,7 +12523,7 @@ "type": "array", "items": { "type": "string", - "example": "Non quae." + "example": "Numquam incidunt eaque totam at culpa ut." }, "description": "Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity.", "example": [ @@ -10017,7 +12534,7 @@ "type": "array", "items": { "type": "string", - "example": "Ea omnis ut dolor dolorem impedit laudantium." + "example": "Iste dignissimos exercitationem." }, "description": "Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries.", "example": [ @@ -10053,6 +12570,12 @@ "type": "string", "description": "The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node.", "example": "n1" + }, + "spock_version": { + "type": "string", + "description": "The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice.", + "example": "6", + "pattern": "^\\d{1}$" } }, "example": { @@ -10071,7 +12594,7 @@ "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "retention_full": 2, "retention_full_type": "count", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -10094,7 +12617,7 @@ "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "retention_full": 2, "retention_full_type": "count", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -10125,9 +12648,9 @@ }, "cpus": "500m", "host_ids": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec", - "de3b1388-1f0c-42f1-a86c-59ab72f255ec", - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "500M", "name": "n1", @@ -10183,7 +12706,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Animi recusandae." + "image": "Incidunt in quas totam." } }, "patroni_port": 8888, @@ -10211,7 +12734,7 @@ "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "s3_endpoint": "s3.us-east-1.amazonaws.com", "s3_key": "AKIAIOSFODNN7EXAMPLE", @@ -10224,18 +12747,19 @@ "target": "123456", "type": "xid" }, - "source_database_id": "02f1a7db-fca8-4521-b57a-2a375c1ced51", + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, "required": [ "name", "host_ids" ] }, - "DatabaseNodeSpec2": { + "DatabaseNodeSpec5": { "type": "object", "properties": { "backup_config": { @@ -10257,6 +12781,8 @@ }, "description": "The IDs of the hosts that should run this node. When multiple hosts are specified, one host will chosen as a primary, and the others will be read replicas.", "example": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "minItems": 1 @@ -10288,7 +12814,7 @@ "type": "array", "items": { "type": "string", - "example": "Sapiente neque doloribus consequatur voluptatibus sed." + "example": "Et qui et." }, "description": "Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity.", "example": [ @@ -10299,7 +12825,7 @@ "type": "array", "items": { "type": "string", - "example": "Nisi nihil corporis perspiciatis et." + "example": "Omnis nobis." }, "description": "Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries.", "example": [ @@ -10335,6 +12861,12 @@ "type": "string", "description": "The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node.", "example": "n1" + }, + "spock_version": { + "type": "string", + "description": "The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice.", + "example": "6", + "pattern": "^\\d{1}$" } }, "example": { @@ -10430,7 +12962,6 @@ }, "cpus": "500m", "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "500M", @@ -10487,7 +13018,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Reprehenderit atque aliquid." + "image": "Et odio." } }, "patroni_port": 8888, @@ -10532,14 +13063,15 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, "required": [ "name", "host_ids" ] }, - "DatabaseNodeSpec3": { + "DatabaseNodeSpec6": { "type": "object", "properties": { "backup_config": { @@ -10592,7 +13124,7 @@ "type": "array", "items": { "type": "string", - "example": "Distinctio sed amet rem voluptas qui." + "example": "Quia quis." }, "description": "Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity.", "example": [ @@ -10603,7 +13135,7 @@ "type": "array", "items": { "type": "string", - "example": "Voluptatem nesciunt dignissimos voluptas vel earum." + "example": "Ducimus deserunt quis commodi officiis libero mollitia." }, "description": "Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries.", "example": [ @@ -10639,6 +13171,12 @@ "type": "string", "description": "The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node.", "example": "n1" + }, + "spock_version": { + "type": "string", + "description": "The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice.", + "example": "6", + "pattern": "^\\d{1}$" } }, "example": { @@ -10711,8 +13249,6 @@ }, "cpus": "500m", "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "500M", @@ -10814,14 +13350,15 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, "required": [ "name", "host_ids" ] }, - "DatabaseNodeSpec4": { + "DatabaseNodeSpec7": { "type": "object", "properties": { "backup_config": { @@ -10843,7 +13380,6 @@ }, "description": "The IDs of the hosts that should run this node. When multiple hosts are specified, one host will chosen as a primary, and the others will be read replicas.", "example": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], @@ -10876,7 +13412,7 @@ "type": "array", "items": { "type": "string", - "example": "Harum iste dignissimos." + "example": "Excepturi debitis aperiam." }, "description": "Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity.", "example": [ @@ -10887,7 +13423,7 @@ "type": "array", "items": { "type": "string", - "example": "Beatae nobis quam sequi quasi aliquid." + "example": "At eveniet consectetur." }, "description": "Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries.", "example": [ @@ -10923,6 +13459,12 @@ "type": "string", "description": "The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node.", "example": "n1" + }, + "spock_version": { + "type": "string", + "description": "The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice.", + "example": "6", + "pattern": "^\\d{1}$" } }, "example": { @@ -11096,14 +13638,15 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, "required": [ "name", "host_ids" ] }, - "DatabaseNodeSpec5": { + "DatabaseNodeSpec8": { "type": "object", "properties": { "backup_config": { @@ -11125,8 +13668,6 @@ }, "description": "The IDs of the hosts that should run this node. When multiple hosts are specified, one host will chosen as a primary, and the others will be read replicas.", "example": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "minItems": 1 @@ -11158,7 +13699,7 @@ "type": "array", "items": { "type": "string", - "example": "Dolor sit quae et tempore et aut." + "example": "Quod facere possimus sit commodi." }, "description": "Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity.", "example": [ @@ -11169,7 +13710,7 @@ "type": "array", "items": { "type": "string", - "example": "Nisi eveniet sit dignissimos ducimus." + "example": "Dolor unde optio illo ut sint cumque." }, "description": "Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries.", "example": [ @@ -11205,6 +13746,12 @@ "type": "string", "description": "The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node.", "example": "n1" + }, + "spock_version": { + "type": "string", + "description": "The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice.", + "example": "6", + "pattern": "^\\d{1}$" } }, "example": { @@ -11233,29 +13780,6 @@ "s3_region": "us-east-1", "type": "s3" }, - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, { "azure_account": "pgedge-backups", "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -11356,7 +13880,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Et odio." + "image": "Incidunt in quas totam." } }, "patroni_port": 8888, @@ -11401,14 +13925,15 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, "required": [ "name", "host_ids" ] }, - "DatabaseNodeSpec6": { + "DatabaseNodeSpec9": { "type": "object", "properties": { "backup_config": { @@ -11430,7 +13955,6 @@ }, "description": "The IDs of the hosts that should run this node. When multiple hosts are specified, one host will chosen as a primary, and the others will be read replicas.", "example": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "minItems": 1 @@ -11462,7 +13986,7 @@ "type": "array", "items": { "type": "string", - "example": "Laudantium molestiae error quas iste." + "example": "Et exercitationem sequi saepe velit." }, "description": "Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity.", "example": [ @@ -11473,7 +13997,7 @@ "type": "array", "items": { "type": "string", - "example": "Assumenda et." + "example": "Ex sint dolorum vel." }, "description": "Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries.", "example": [ @@ -11509,6 +14033,12 @@ "type": "string", "description": "The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node.", "example": "n1" + }, + "spock_version": { + "type": "string", + "description": "The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice.", + "example": "6", + "pattern": "^\\d{1}$" } }, "example": { @@ -11682,14 +14212,36 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, "required": [ "name", "host_ids" ] }, - "DatabaseNodeSpec7": { + "DatabaseScripts": { + "type": "object", + "properties": { + "post_database_create": { + "$ref": "#/components/schemas/SQLScript" + }, + "post_init": { + "$ref": "#/components/schemas/SQLScript" + } + }, + "example": { + "post_database_create": [ + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" + ], + "post_init": [ + "CREATE ROLE accounting_admin NOLOGIN" + ] + } + }, + "DatabaseSpec": { "type": "object", "properties": { "backup_config": { @@ -11697,325 +14249,617 @@ }, "cpus": { "type": "string", - "description": "The number of CPUs to allocate for the database on this node and to use for tuning Postgres. It can include the SI suffix 'm', e.g. '500m' for 500 millicpus. Cannot allocate units smaller than 1m. Defaults to the number of available CPUs on the host if 0 or unspecified. Cannot allocate more CPUs than are available on the host. Whether this limit is enforced depends on the orchestrator.", + "description": "The number of CPUs to allocate for the database and to use for tuning Postgres. Defaults to the number of available CPUs on the host. Can include an SI suffix, e.g. '500m' for 500 millicpus. Whether this limit is enforced depends on the orchestrator.", "example": "500m", "pattern": "^[0-9]+(\\.[0-9]{1,3}|m)?$" }, - "host_ids": { + "database_name": { + "type": "string", + "description": "The name of the Postgres database.", + "example": "northwind", + "minLength": 1, + "maxLength": 31 + }, + "database_users": { "type": "array", "items": { - "type": "string", - "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "minLength": 1, - "maxLength": 36 + "$ref": "#/components/schemas/DatabaseUserSpec" }, - "description": "The IDs of the hosts that should run this node. When multiple hosts are specified, one host will chosen as a primary, and the others will be read replicas.", + "description": "The users to create for this database.", "example": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + }, + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + }, + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + } ], - "minItems": 1 + "maxItems": 16 }, "memory": { "type": "string", - "description": "The amount of memory in SI or IEC notation to allocate for the database on this node and to use for tuning Postgres. Defaults to the total available memory on the host. Whether this limit is enforced depends on the orchestrator.", + "description": "The amount of memory in SI or IEC notation to allocate for the database and to use for tuning Postgres. Defaults to the total available memory on the host. Whether this limit is enforced depends on the orchestrator.", "example": "500M", "maxLength": 16 }, - "name": { - "type": "string", - "description": "The name of the database node.", - "example": "n1", - "pattern": "n[0-9]+" - }, - "orchestrator_opts": { - "$ref": "#/components/schemas/OrchestratorOpts" - }, - "patroni_port": { - "type": "integer", - "description": "The port used by Patroni for this node. Overrides the Patroni port set in the DatabaseSpec. NOTE: This field is not currently supported for Docker Swarm.", - "example": 8888, - "format": "int64", - "minimum": 0, - "maximum": 65535 - }, - "pg_hba_conf": { - "type": "array", - "items": { - "type": "string", - "example": "Alias est mollitia." - }, - "description": "Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity.", - "example": [ - "host example myapp_user 10.0.0.0/8 scram-sha-256" - ] - }, - "pg_ident_conf": { + "nodes": { "type": "array", "items": { - "type": "string", - "example": "Possimus id laudantium sed delectus." + "$ref": "#/components/schemas/DatabaseNodeSpec" }, - "description": "Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries.", + "description": "The Spock nodes for this database.", "example": [ - "ssl_users CN=alice,O=example alice" - ] - }, - "port": { - "type": "integer", - "description": "The port used by the Postgres database for this node. Overrides the Postgres port set in the DatabaseSpec.", - "example": 5432, - "format": "int64", - "minimum": 0, - "maximum": 65535 - }, - "postgres_version": { - "type": "string", - "description": "The Postgres version for this node in 'major.minor' format. Overrides the Postgres version set in the DatabaseSpec.", - "example": "17.6", - "pattern": "^\\d{2}\\.\\d{1,2}$" - }, - "postgresql_conf": { - "type": "object", - "description": "Additional postgresql.conf settings for this particular node. Will be merged with the settings provided by control-plane.", - "example": { - "max_connections": 1000 - }, - "additionalProperties": true - }, - "restore_config": { - "$ref": "#/components/schemas/RestoreConfigSpec" - }, - "source_node": { - "type": "string", - "description": "The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node.", - "example": "n1" - } - }, - "example": { - "backup_config": { - "repositories": [ { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" + "backup_config": { + "repositories": [ + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + } + ], + "schedules": [ + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + } + ] + }, + "cpus": "500m", + "host_ids": [ + "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + ], + "memory": "500M", + "name": "n1", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Sapiente qui ullam." + } + }, + "patroni_port": 8888, + "pg_hba_conf": [ + "host example myapp_user 10.0.0.0/8 scram-sha-256" + ], + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" + ], + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" + "restore_config": { + "repository": { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" + }, + "source_database_id": "02f1a7db-fca8-4521-b57a-2a375c1ced51", + "source_database_name": "northwind", + "source_node_name": "n1" }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - } - ], - "schedules": [ - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "source_node": "n1", + "spock_version": "6" }, { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - } - ] - }, - "cpus": "500m", - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "500M", - "name": "n1", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" + "backup_config": { + "repositories": [ + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + } ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" + "schedules": [ + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + } + ] + }, + "cpus": "500m", + "host_ids": [ + "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + ], + "memory": "500M", + "name": "n1", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Sapiente qui ullam." + } + }, + "patroni_port": 8888, + "pg_hba_conf": [ + "host example myapp_user 10.0.0.0/8 scram-sha-256" + ], + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" + ], + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 + }, + "restore_config": { + "repository": { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" }, - "id": "traefik-public" + "source_database_id": "02f1a7db-fca8-4521-b57a-2a375c1ced51", + "source_database_name": "northwind", + "source_node_name": "n1" }, - { - "aliases": [ - "pg-db", - "db-alias" + "source_node": "n1", + "spock_version": "6" + }, + { + "backup_config": { + "repositories": [ + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + } ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" + "schedules": [ + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + } + ] }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Incidunt in quas totam." - } - }, - "patroni_port": 8888, - "pg_hba_conf": [ - "host example myapp_user 10.0.0.0/8 scram-sha-256" - ], - "pg_ident_conf": [ - "ssl_users CN=alice,O=example alice" - ], - "port": 5432, - "postgres_version": "17.6", - "postgresql_conf": { - "max_connections": 1000 - }, - "restore_config": { - "repository": { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - "restore_options": { - "set": "20250505-153628F", - "target": "123456", - "type": "xid" - }, - "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "source_database_name": "northwind", - "source_node_name": "n1" - }, - "source_node": "n1" - }, - "required": [ - "name", - "host_ids" - ] - }, - "DatabaseNodeSpec8": { - "type": "object", - "properties": { - "backup_config": { - "$ref": "#/components/schemas/BackupConfigSpec" - }, - "cpus": { - "type": "string", - "description": "The number of CPUs to allocate for the database on this node and to use for tuning Postgres. It can include the SI suffix 'm', e.g. '500m' for 500 millicpus. Cannot allocate units smaller than 1m. Defaults to the number of available CPUs on the host if 0 or unspecified. Cannot allocate more CPUs than are available on the host. Whether this limit is enforced depends on the orchestrator.", - "example": "500m", - "pattern": "^[0-9]+(\\.[0-9]{1,3}|m)?$" - }, - "host_ids": { - "type": "array", - "items": { - "type": "string", - "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "minLength": 1, - "maxLength": 36 - }, - "description": "The IDs of the hosts that should run this node. When multiple hosts are specified, one host will chosen as a primary, and the others will be read replicas.", - "example": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" + "cpus": "500m", + "host_ids": [ + "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + ], + "memory": "500M", + "name": "n1", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Sapiente qui ullam." + } + }, + "patroni_port": 8888, + "pg_hba_conf": [ + "host example myapp_user 10.0.0.0/8 scram-sha-256" + ], + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" + ], + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 + }, + "restore_config": { + "repository": { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" + }, + "source_database_id": "02f1a7db-fca8-4521-b57a-2a375c1ced51", + "source_database_name": "northwind", + "source_node_name": "n1" + }, + "source_node": "n1", + "spock_version": "6" + } ], - "minItems": 1 - }, - "memory": { - "type": "string", - "description": "The amount of memory in SI or IEC notation to allocate for the database on this node and to use for tuning Postgres. Defaults to the total available memory on the host. Whether this limit is enforced depends on the orchestrator.", - "example": "500M", - "maxLength": 16 - }, - "name": { - "type": "string", - "description": "The name of the database node.", - "example": "n1", - "pattern": "n[0-9]+" + "minItems": 1, + "maxItems": 9 }, "orchestrator_opts": { "$ref": "#/components/schemas/OrchestratorOpts" }, "patroni_port": { "type": "integer", - "description": "The port used by Patroni for this node. Overrides the Patroni port set in the DatabaseSpec. NOTE: This field is not currently supported for Docker Swarm.", + "description": "The port used by Patroni for this database. If the port is 0, each instance will be assigned a random port. NOTE: This field is not currently supported for Docker Swarm.", "example": 8888, "format": "int64", "minimum": 0, @@ -12025,27 +14869,28 @@ "type": "array", "items": { "type": "string", - "example": "Id natus aut." + "example": "Magni quaerat qui quam id aut velit." }, - "description": "Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity.", + "description": "Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these.", "example": [ - "host example myapp_user 10.0.0.0/8 scram-sha-256" + "hostssl all myapp_user 203.0.113.0/24 scram-sha-256", + "hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users" ] }, "pg_ident_conf": { "type": "array", "items": { "type": "string", - "example": "Minus sint totam et et." + "example": "Labore in." }, - "description": "Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries.", + "description": "Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames.", "example": [ "ssl_users CN=alice,O=example alice" ] }, "port": { "type": "integer", - "description": "The port used by the Postgres database for this node. Overrides the Postgres port set in the DatabaseSpec.", + "description": "The port used by the Postgres database. If the port is 0, each instance will be assigned a random port. If the port is unspecified, the database will not be exposed on any port, dependent on orchestrator support for that feature.", "example": 5432, "format": "int64", "minimum": 0, @@ -12053,25 +14898,199 @@ }, "postgres_version": { "type": "string", - "description": "The Postgres version for this node in 'major.minor' format. Overrides the Postgres version set in the DatabaseSpec.", + "description": "The Postgres version in 'major.minor' format.", "example": "17.6", "pattern": "^\\d{2}\\.\\d{1,2}$" }, "postgresql_conf": { "type": "object", - "description": "Additional postgresql.conf settings for this particular node. Will be merged with the settings provided by control-plane.", + "description": "Additional postgresql.conf settings. Will be merged with the settings provided by control-plane.", "example": { "max_connections": 1000 }, + "maxLength": 64, "additionalProperties": true }, "restore_config": { "$ref": "#/components/schemas/RestoreConfigSpec" }, - "source_node": { + "scripts": { + "$ref": "#/components/schemas/DatabaseScripts" + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ServiceSpec" + }, + "description": "Service instances to run alongside the database (e.g., MCP servers).", + "example": [ + { + "config": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "connect_as": "app", + "cpus": "500m", + "database_connection": { + "target_nodes": [ + "n1", + "n2" + ], + "target_session_attrs": "primary" + }, + "host_ids": [ + "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + ], + "memory": "512M", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Sapiente qui ullam." + } + }, + "port": 0, + "service_id": "analytics-service", + "service_type": "rag", + "version": "latest" + }, + { + "config": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "connect_as": "app", + "cpus": "500m", + "database_connection": { + "target_nodes": [ + "n1", + "n2" + ], + "target_session_attrs": "primary" + }, + "host_ids": [ + "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + ], + "memory": "512M", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Sapiente qui ullam." + } + }, + "port": 0, + "service_id": "analytics-service", + "service_type": "rag", + "version": "latest" + } + ] + }, + "spock_version": { "type": "string", - "description": "The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node.", - "example": "n1" + "description": "The major version of the Spock extension.", + "example": "5", + "pattern": "^\\d{1}$" } }, "example": { @@ -12087,69 +15106,283 @@ "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", "storage-upload-chunk-size": "5MiB" }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + } + ], + "schedules": [ + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + } + ] + }, + "cpus": "500m", + "database_name": "northwind", + "database_users": [ + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + }, + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + }, + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + } + ], + "memory": "500M", + "nodes": [ + { + "backup_config": { + "repositories": [ + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + } + ], + "schedules": [ + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + } + ] + }, + "cpus": "500m", + "host_ids": [ + "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + ], + "memory": "500M", + "name": "n1", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Sapiente qui ullam." + } + }, + "patroni_port": 8888, + "pg_hba_conf": [ + "host example myapp_user 10.0.0.0/8 scram-sha-256" + ], + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" + ], + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 + }, + "restore_config": { + "repository": { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - } - ], - "schedules": [ - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "source_database_id": "02f1a7db-fca8-4521-b57a-2a375c1ced51", + "source_database_name": "northwind", + "source_node_name": "n1" }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - } - ] - }, - "cpus": "500m", - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" + "source_node": "n1", + "spock_version": "6" + } ], - "memory": "500M", - "name": "n1", "orchestrator_opts": { "swarm": { "extra_labels": { @@ -12202,12 +15435,13 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Sapiente qui ullam." } }, "patroni_port": 8888, "pg_hba_conf": [ - "host example myapp_user 10.0.0.0/8 scram-sha-256" + "hostssl all myapp_user 203.0.113.0/24 scram-sha-256", + "hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users" ], "pg_ident_conf": [ "ssl_users CN=alice,O=example alice" @@ -12227,55 +15461,206 @@ "custom_options": { "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - "restore_options": { - "set": "20250505-153628F", - "target": "123456", - "type": "xid" - }, - "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "source_database_name": "northwind", - "source_node_name": "n1" - }, - "source_node": "n1" + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" + }, + "source_database_id": "02f1a7db-fca8-4521-b57a-2a375c1ced51", + "source_database_name": "northwind", + "source_node_name": "n1" + }, + "scripts": { + "post_database_create": [ + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" + ], + "post_init": [ + "CREATE ROLE accounting_admin NOLOGIN" + ] + }, + "services": [ + { + "config": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "connect_as": "app", + "cpus": "500m", + "database_connection": { + "target_nodes": [ + "n1", + "n2" + ], + "target_session_attrs": "primary" + }, + "host_ids": [ + "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + ], + "memory": "512M", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Sapiente qui ullam." + } + }, + "port": 0, + "service_id": "analytics-service", + "service_type": "rag", + "version": "latest" + }, + { + "config": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "connect_as": "app", + "cpus": "500m", + "database_connection": { + "target_nodes": [ + "n1", + "n2" + ], + "target_session_attrs": "primary" + }, + "host_ids": [ + "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + ], + "memory": "512M", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Sapiente qui ullam." + } + }, + "port": 0, + "service_id": "analytics-service", + "service_type": "rag", + "version": "latest" + } + ], + "spock_version": "5" }, "required": [ - "name", - "host_ids" + "database_name", + "nodes" ] }, - "DatabaseScripts": { - "type": "object", - "properties": { - "post_database_create": { - "$ref": "#/components/schemas/SQLScript" - }, - "post_init": { - "$ref": "#/components/schemas/SQLScript" - } - }, - "example": { - "post_database_create": [ - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" - ], - "post_init": [ - "CREATE ROLE accounting_admin NOLOGIN" - ] - } - }, - "DatabaseSpec": { + "DatabaseSpec2": { "type": "object", "properties": { "backup_config": { @@ -12307,7 +15692,20 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": false, + "db_owner": true, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + }, + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": true, "password": "secret", "roles": [ "pgedge_superuser" @@ -12320,42 +15718,228 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": false, - "password": "secret", - "roles": [ - "pgedge_superuser" + "db_owner": true, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + } + ], + "maxItems": 16 + }, + "memory": { + "type": "string", + "description": "The amount of memory in SI or IEC notation to allocate for the database and to use for tuning Postgres. Defaults to the total available memory on the host. Whether this limit is enforced depends on the orchestrator.", + "example": "500M", + "maxLength": 16 + }, + "nodes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DatabaseNodeSpec2" + }, + "description": "The Spock nodes for this database.", + "example": [ + { + "backup_config": { + "repositories": [ + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + } + ], + "schedules": [ + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + } + ] + }, + "cpus": "500m", + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "500M", + "name": "n1", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Reprehenderit atque aliquid." + } + }, + "patroni_port": 8888, + "pg_hba_conf": [ + "host example myapp_user 10.0.0.0/8 scram-sha-256" + ], + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" ], - "username": "admin" + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 + }, + "restore_config": { + "repository": { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" + }, + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "source_database_name": "northwind", + "source_node_name": "n1" + }, + "source_node": "n1", + "spock_version": "6" }, - { - "attributes": [ - "LOGIN", - "CREATEDB", - "CREATEROLE" - ], - "db_owner": false, - "password": "secret", - "roles": [ - "pgedge_superuser" - ], - "username": "admin" - } - ], - "maxItems": 16 - }, - "memory": { - "type": "string", - "description": "The amount of memory in SI or IEC notation to allocate for the database and to use for tuning Postgres. Defaults to the total available memory on the host. Whether this limit is enforced depends on the orchestrator.", - "example": "500M", - "maxLength": 16 - }, - "nodes": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DatabaseNodeSpec" - }, - "description": "The Spock nodes for this database.", - "example": [ { "backup_config": { "repositories": [ @@ -12372,7 +15956,7 @@ "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "retention_full": 2, "retention_full_type": "count", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -12395,7 +15979,30 @@ "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "retention_full": 2, "retention_full_type": "count", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -12426,9 +16033,9 @@ }, "cpus": "500m", "host_ids": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec", - "de3b1388-1f0c-42f1-a86c-59ab72f255ec", - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "500M", "name": "n1", @@ -12484,7 +16091,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Animi recusandae." + "image": "Reprehenderit atque aliquid." } }, "patroni_port": 8888, @@ -12512,7 +16119,7 @@ "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "s3_endpoint": "s3.us-east-1.amazonaws.com", "s3_key": "AKIAIOSFODNN7EXAMPLE", @@ -12525,11 +16132,12 @@ "target": "123456", "type": "xid" }, - "source_database_id": "02f1a7db-fca8-4521-b57a-2a375c1ced51", + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, { "backup_config": { @@ -12547,7 +16155,7 @@ "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "retention_full": 2, "retention_full_type": "count", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -12570,7 +16178,30 @@ "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "retention_full": 2, "retention_full_type": "count", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -12601,9 +16232,9 @@ }, "cpus": "500m", "host_ids": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec", - "de3b1388-1f0c-42f1-a86c-59ab72f255ec", - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "500M", "name": "n1", @@ -12659,7 +16290,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Animi recusandae." + "image": "Reprehenderit atque aliquid." } }, "patroni_port": 8888, @@ -12687,7 +16318,7 @@ "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "s3_endpoint": "s3.us-east-1.amazonaws.com", "s3_key": "AKIAIOSFODNN7EXAMPLE", @@ -12700,11 +16331,12 @@ "target": "123456", "type": "xid" }, - "source_database_id": "02f1a7db-fca8-4521-b57a-2a375c1ced51", + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" } ], "minItems": 1, @@ -12725,7 +16357,7 @@ "type": "array", "items": { "type": "string", - "example": "Velit et labore in dolor quisquam placeat." + "example": "Nihil corporis perspiciatis et veniam blanditiis." }, "description": "Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these.", "example": [ @@ -12737,7 +16369,7 @@ "type": "array", "items": { "type": "string", - "example": "Eos molestiae voluptates laborum." + "example": "Accusamus repellat fuga occaecati." }, "description": "Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames.", "example": [ @@ -12776,7 +16408,7 @@ "services": { "type": "array", "items": { - "$ref": "#/components/schemas/ServiceSpec" + "$ref": "#/components/schemas/ServiceSpec2" }, "description": "Service instances to run alongside the database (e.g., MCP servers).", "example": [ @@ -12796,7 +16428,7 @@ "target_session_attrs": "primary" }, "host_ids": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", "orchestrator_opts": { @@ -12851,11 +16483,11 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Animi recusandae." + "image": "Reprehenderit atque aliquid." } }, "port": 0, - "service_id": "analytics-service", + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "service_type": "rag", "version": "latest" }, @@ -12875,7 +16507,7 @@ "target_session_attrs": "primary" }, "host_ids": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", "orchestrator_opts": { @@ -12930,11 +16562,11 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Animi recusandae." + "image": "Reprehenderit atque aliquid." } }, "port": 0, - "service_id": "analytics-service", + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "service_type": "rag", "version": "latest" }, @@ -12954,7 +16586,7 @@ "target_session_attrs": "primary" }, "host_ids": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", "orchestrator_opts": { @@ -13009,11 +16641,11 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Animi recusandae." + "image": "Reprehenderit atque aliquid." } }, "port": 0, - "service_id": "analytics-service", + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "service_type": "rag", "version": "latest" } @@ -13042,7 +16674,7 @@ "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "retention_full": 2, "retention_full_type": "count", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -13065,7 +16697,30 @@ "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "retention_full": 2, "retention_full_type": "count", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -13103,7 +16758,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": false, + "db_owner": true, "password": "secret", "roles": [ "pgedge_superuser" @@ -13116,7 +16771,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": false, + "db_owner": true, "password": "secret", "roles": [ "pgedge_superuser" @@ -13129,7 +16784,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": false, + "db_owner": true, "password": "secret", "roles": [ "pgedge_superuser" @@ -13155,7 +16810,7 @@ "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "retention_full": 2, "retention_full_type": "count", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -13178,7 +16833,30 @@ "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "retention_full": 2, "retention_full_type": "count", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -13209,9 +16887,9 @@ }, "cpus": "500m", "host_ids": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec", - "de3b1388-1f0c-42f1-a86c-59ab72f255ec", - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "500M", "name": "n1", @@ -13267,7 +16945,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Animi recusandae." + "image": "Reprehenderit atque aliquid." } }, "patroni_port": 8888, @@ -13295,7 +16973,7 @@ "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "s3_endpoint": "s3.us-east-1.amazonaws.com", "s3_key": "AKIAIOSFODNN7EXAMPLE", @@ -13308,11 +16986,12 @@ "target": "123456", "type": "xid" }, - "source_database_id": "02f1a7db-fca8-4521-b57a-2a375c1ced51", + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, { "backup_config": { @@ -13330,7 +17009,30 @@ "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "retention_full": 2, "retention_full_type": "count", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -13353,7 +17055,7 @@ "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "retention_full": 2, "retention_full_type": "count", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -13384,9 +17086,9 @@ }, "cpus": "500m", "host_ids": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec", - "de3b1388-1f0c-42f1-a86c-59ab72f255ec", - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "500M", "name": "n1", @@ -13442,7 +17144,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Animi recusandae." + "image": "Reprehenderit atque aliquid." } }, "patroni_port": 8888, @@ -13470,7 +17172,7 @@ "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "s3_endpoint": "s3.us-east-1.amazonaws.com", "s3_key": "AKIAIOSFODNN7EXAMPLE", @@ -13483,11 +17185,12 @@ "target": "123456", "type": "xid" }, - "source_database_id": "02f1a7db-fca8-4521-b57a-2a375c1ced51", + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" } ], "orchestrator_opts": { @@ -13508,255 +17211,99 @@ "id": "traefik-public" }, { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Animi recusandae." - } - }, - "patroni_port": 8888, - "pg_hba_conf": [ - "hostssl all myapp_user 203.0.113.0/24 scram-sha-256", - "hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users" - ], - "pg_ident_conf": [ - "ssl_users CN=alice,O=example alice" - ], - "port": 5432, - "postgres_version": "17.6", - "postgresql_conf": { - "max_connections": 1000 - }, - "restore_config": { - "repository": { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - "restore_options": { - "set": "20250505-153628F", - "target": "123456", - "type": "xid" - }, - "source_database_id": "02f1a7db-fca8-4521-b57a-2a375c1ced51", - "source_database_name": "northwind", - "source_node_name": "n1" - }, - "scripts": { - "post_database_create": [ - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" - ], - "post_init": [ - "CREATE ROLE accounting_admin NOLOGIN" - ] - }, - "services": [ - { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." - }, - "connect_as": "app", - "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" - ], - "target_session_attrs": "primary" - }, - "host_ids": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" - ], - "memory": "512M", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Animi recusandae." - } - }, - "port": 0, - "service_id": "analytics-service", - "service_type": "rag", - "version": "latest" - }, - { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." - }, - "connect_as": "app", - "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" - ], - "target_session_attrs": "primary" - }, - "host_ids": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" - ], - "memory": "512M", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" ], - "image": "Animi recusandae." + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" } + ], + "image": "Reprehenderit atque aliquid." + } + }, + "patroni_port": 8888, + "pg_hba_conf": [ + "hostssl all myapp_user 203.0.113.0/24 scram-sha-256", + "hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users" + ], + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" + ], + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 + }, + "restore_config": { + "repository": { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" }, - "port": 0, - "service_id": "analytics-service", - "service_type": "rag", - "version": "latest" + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" }, + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "source_database_name": "northwind", + "source_node_name": "n1" + }, + "scripts": { + "post_database_create": [ + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" + ], + "post_init": [ + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" + ] + }, + "services": [ { "config": { "llm_model": "gpt-4", @@ -13773,7 +17320,7 @@ "target_session_attrs": "primary" }, "host_ids": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", "orchestrator_opts": { @@ -13828,11 +17375,11 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Animi recusandae." + "image": "Reprehenderit atque aliquid." } }, "port": 0, - "service_id": "analytics-service", + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "service_type": "rag", "version": "latest" }, @@ -13852,7 +17399,7 @@ "target_session_attrs": "primary" }, "host_ids": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", "orchestrator_opts": { @@ -13907,11 +17454,11 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Animi recusandae." + "image": "Reprehenderit atque aliquid." } }, "port": 0, - "service_id": "analytics-service", + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "service_type": "rag", "version": "latest" } @@ -13923,7 +17470,7 @@ "nodes" ] }, - "DatabaseSpec2": { + "DatabaseSpec3": { "type": "object", "properties": { "backup_config": { @@ -13955,7 +17502,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": true, + "db_owner": false, "password": "secret", "roles": [ "pgedge_superuser" @@ -13968,7 +17515,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": true, + "db_owner": false, "password": "secret", "roles": [ "pgedge_superuser" @@ -13981,7 +17528,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": true, + "db_owner": false, "password": "secret", "roles": [ "pgedge_superuser" @@ -14000,7 +17547,7 @@ "nodes": { "type": "array", "items": { - "$ref": "#/components/schemas/DatabaseNodeSpec2" + "$ref": "#/components/schemas/DatabaseNodeSpec3" }, "description": "The Spock nodes for this database.", "example": [ @@ -14030,29 +17577,6 @@ "s3_region": "us-east-1", "type": "s3" }, - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, { "azure_account": "pgedge-backups", "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -14155,7 +17679,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Reprehenderit atque aliquid." + "image": "Incidunt in quas totam." } }, "patroni_port": 8888, @@ -14200,7 +17724,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" } ], "minItems": 1, @@ -14221,7 +17746,7 @@ "type": "array", "items": { "type": "string", - "example": "Optio accusantium." + "example": "Dignissimos voluptas vel earum eaque." }, "description": "Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these.", "example": [ @@ -14233,7 +17758,7 @@ "type": "array", "items": { "type": "string", - "example": "Voluptatibus sunt deserunt sapiente doloribus est." + "example": "Et minima ipsum ut impedit." }, "description": "Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames.", "example": [ @@ -14272,7 +17797,7 @@ "services": { "type": "array", "items": { - "$ref": "#/components/schemas/ServiceSpec2" + "$ref": "#/components/schemas/ServiceSpec3" }, "description": "Service instances to run alongside the database (e.g., MCP servers).", "example": [ @@ -14292,6 +17817,7 @@ "target_session_attrs": "primary" }, "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", @@ -14347,7 +17873,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Reprehenderit atque aliquid." + "image": "Incidunt in quas totam." } }, "port": 0, @@ -14371,6 +17897,7 @@ "target_session_attrs": "primary" }, "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", @@ -14426,7 +17953,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Reprehenderit atque aliquid." + "image": "Incidunt in quas totam." } }, "port": 0, @@ -14450,6 +17977,7 @@ "target_session_attrs": "primary" }, "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", @@ -14505,7 +18033,87 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Reprehenderit atque aliquid." + "image": "Incidunt in quas totam." + } + }, + "port": 0, + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "service_type": "rag", + "version": "latest" + }, + { + "config": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "connect_as": "app", + "cpus": "500m", + "database_connection": { + "target_nodes": [ + "n1", + "n2" + ], + "target_session_attrs": "primary" + }, + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "512M", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Incidunt in quas totam." } }, "port": 0, @@ -14521,33 +18129,10 @@ "example": "5", "pattern": "^\\d{1}$" } - }, - "example": { - "backup_config": { - "repositories": [ - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, + }, + "example": { + "backup_config": { + "repositories": [ { "azure_account": "pgedge-backups", "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -14622,7 +18207,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": true, + "db_owner": false, "password": "secret", "roles": [ "pgedge_superuser" @@ -14635,7 +18220,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": true, + "db_owner": false, "password": "secret", "roles": [ "pgedge_superuser" @@ -14648,7 +18233,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": true, + "db_owner": false, "password": "secret", "roles": [ "pgedge_superuser" @@ -14684,29 +18269,6 @@ "s3_region": "us-east-1", "type": "s3" }, - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, { "azure_account": "pgedge-backups", "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -14809,7 +18371,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Reprehenderit atque aliquid." + "image": "Incidunt in quas totam." } }, "patroni_port": 8888, @@ -14854,7 +18416,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, { "backup_config": { @@ -14882,29 +18445,6 @@ "s3_region": "us-east-1", "type": "s3" }, - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, { "azure_account": "pgedge-backups", "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -15007,7 +18547,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Reprehenderit atque aliquid." + "image": "Incidunt in quas totam." } }, "patroni_port": 8888, @@ -15052,7 +18592,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, { "backup_config": { @@ -15080,29 +18621,6 @@ "s3_region": "us-east-1", "type": "s3" }, - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, { "azure_account": "pgedge-backups", "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -15205,7 +18723,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Reprehenderit atque aliquid." + "image": "Incidunt in quas totam." } }, "patroni_port": 8888, @@ -15250,7 +18768,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" } ], "orchestrator_opts": { @@ -15305,7 +18824,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Reprehenderit atque aliquid." + "image": "Incidunt in quas totam." } }, "patroni_port": 8888, @@ -15380,6 +18899,7 @@ "target_session_attrs": "primary" }, "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", @@ -15435,7 +18955,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Reprehenderit atque aliquid." + "image": "Incidunt in quas totam." } }, "port": 0, @@ -15459,6 +18979,7 @@ "target_session_attrs": "primary" }, "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", @@ -15514,7 +19035,167 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Reprehenderit atque aliquid." + "image": "Incidunt in quas totam." + } + }, + "port": 0, + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "service_type": "rag", + "version": "latest" + }, + { + "config": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "connect_as": "app", + "cpus": "500m", + "database_connection": { + "target_nodes": [ + "n1", + "n2" + ], + "target_session_attrs": "primary" + }, + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "512M", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Incidunt in quas totam." + } + }, + "port": 0, + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "service_type": "rag", + "version": "latest" + }, + { + "config": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "connect_as": "app", + "cpus": "500m", + "database_connection": { + "target_nodes": [ + "n1", + "n2" + ], + "target_session_attrs": "primary" + }, + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "512M", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Incidunt in quas totam." } }, "port": 0, @@ -15530,7 +19211,7 @@ "nodes" ] }, - "DatabaseSpec3": { + "DatabaseSpec4": { "type": "object", "properties": { "backup_config": { @@ -15607,7 +19288,7 @@ "nodes": { "type": "array", "items": { - "$ref": "#/components/schemas/DatabaseNodeSpec3" + "$ref": "#/components/schemas/DatabaseNodeSpec4" }, "description": "The Spock nodes for this database.", "example": [ @@ -15784,7 +19465,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, { "backup_config": { @@ -15931,270 +19613,111 @@ }, "restore_config": { "repository": { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - "restore_options": { - "set": "20250505-153628F", - "target": "123456", - "type": "xid" - }, - "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "source_database_name": "northwind", - "source_node_name": "n1" - }, - "source_node": "n1" - } - ], - "minItems": 1, - "maxItems": 9 - }, - "orchestrator_opts": { - "$ref": "#/components/schemas/OrchestratorOpts" - }, - "patroni_port": { - "type": "integer", - "description": "The port used by Patroni for this database. If the port is 0, each instance will be assigned a random port. NOTE: This field is not currently supported for Docker Swarm.", - "example": 8888, - "format": "int64", - "minimum": 0, - "maximum": 65535 - }, - "pg_hba_conf": { - "type": "array", - "items": { - "type": "string", - "example": "Quo perferendis et qui." - }, - "description": "Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these.", - "example": [ - "hostssl all myapp_user 203.0.113.0/24 scram-sha-256", - "hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users" - ] - }, - "pg_ident_conf": { - "type": "array", - "items": { - "type": "string", - "example": "Quaerat rem." - }, - "description": "Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames.", - "example": [ - "ssl_users CN=alice,O=example alice" - ] - }, - "port": { - "type": "integer", - "description": "The port used by the Postgres database. If the port is 0, each instance will be assigned a random port. If the port is unspecified, the database will not be exposed on any port, dependent on orchestrator support for that feature.", - "example": 5432, - "format": "int64", - "minimum": 0, - "maximum": 65535 - }, - "postgres_version": { - "type": "string", - "description": "The Postgres version in 'major.minor' format.", - "example": "17.6", - "pattern": "^\\d{2}\\.\\d{1,2}$" - }, - "postgresql_conf": { - "type": "object", - "description": "Additional postgresql.conf settings. Will be merged with the settings provided by control-plane.", - "example": { - "max_connections": 1000 - }, - "maxLength": 64, - "additionalProperties": true - }, - "restore_config": { - "$ref": "#/components/schemas/RestoreConfigSpec" - }, - "scripts": { - "$ref": "#/components/schemas/DatabaseScripts" - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ServiceSpec3" - }, - "description": "Service instances to run alongside the database (e.g., MCP servers).", - "example": [ - { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." - }, - "connect_as": "app", - "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" - ], - "target_session_attrs": "primary" - }, - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "512M", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Incidunt in quas totam." - } - }, - "port": 0, - "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "service_type": "rag", - "version": "latest" - }, - { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." - }, - "connect_as": "app", - "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" - ], - "target_session_attrs": "primary" - }, - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "512M", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Incidunt in quas totam." - } + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" + }, + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "source_database_name": "northwind", + "source_node_name": "n1" }, - "port": 0, - "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "service_type": "rag", - "version": "latest" - }, + "source_node": "n1", + "spock_version": "6" + } + ], + "minItems": 1, + "maxItems": 9 + }, + "orchestrator_opts": { + "$ref": "#/components/schemas/OrchestratorOpts" + }, + "patroni_port": { + "type": "integer", + "description": "The port used by Patroni for this database. If the port is 0, each instance will be assigned a random port. NOTE: This field is not currently supported for Docker Swarm.", + "example": 8888, + "format": "int64", + "minimum": 0, + "maximum": 65535 + }, + "pg_hba_conf": { + "type": "array", + "items": { + "type": "string", + "example": "Dolorum natus sunt harum magnam sunt." + }, + "description": "Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these.", + "example": [ + "hostssl all myapp_user 203.0.113.0/24 scram-sha-256", + "hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users" + ] + }, + "pg_ident_conf": { + "type": "array", + "items": { + "type": "string", + "example": "In veniam officia ratione." + }, + "description": "Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames.", + "example": [ + "ssl_users CN=alice,O=example alice" + ] + }, + "port": { + "type": "integer", + "description": "The port used by the Postgres database. If the port is 0, each instance will be assigned a random port. If the port is unspecified, the database will not be exposed on any port, dependent on orchestrator support for that feature.", + "example": 5432, + "format": "int64", + "minimum": 0, + "maximum": 65535 + }, + "postgres_version": { + "type": "string", + "description": "The Postgres version in 'major.minor' format.", + "example": "17.6", + "pattern": "^\\d{2}\\.\\d{1,2}$" + }, + "postgresql_conf": { + "type": "object", + "description": "Additional postgresql.conf settings. Will be merged with the settings provided by control-plane.", + "example": { + "max_connections": 1000 + }, + "maxLength": 64, + "additionalProperties": true + }, + "restore_config": { + "$ref": "#/components/schemas/RestoreConfigSpec" + }, + "scripts": { + "$ref": "#/components/schemas/DatabaseScripts" + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ServiceSpec4" + }, + "description": "Service instances to run alongside the database (e.g., MCP servers).", + "example": [ { "config": { "llm_model": "gpt-4", @@ -16454,29 +19977,205 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": false, - "password": "secret", - "roles": [ - "pgedge_superuser" + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + }, + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + } + ], + "memory": "500M", + "nodes": [ + { + "backup_config": { + "repositories": [ + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + } + ], + "schedules": [ + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + } + ] + }, + "cpus": "500m", + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "500M", + "name": "n1", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Incidunt in quas totam." + } + }, + "patroni_port": 8888, + "pg_hba_conf": [ + "host example myapp_user 10.0.0.0/8 scram-sha-256" + ], + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" ], - "username": "admin" + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 + }, + "restore_config": { + "repository": { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" + }, + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "source_database_name": "northwind", + "source_node_name": "n1" + }, + "source_node": "n1", + "spock_version": "6" }, - { - "attributes": [ - "LOGIN", - "CREATEDB", - "CREATEROLE" - ], - "db_owner": false, - "password": "secret", - "roles": [ - "pgedge_superuser" - ], - "username": "admin" - } - ], - "memory": "500M", - "nodes": [ { "backup_config": { "repositories": [ @@ -16650,7 +20349,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, { "backup_config": { @@ -16825,7 +20525,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" } ], "orchestrator_opts": { @@ -17267,7 +20968,7 @@ "nodes" ] }, - "DatabaseSpec4": { + "DatabaseSpec5": { "type": "object", "properties": { "backup_config": { @@ -17293,236 +20994,61 @@ }, "description": "The users to create for this database.", "example": [ - { - "attributes": [ - "LOGIN", - "CREATEDB", - "CREATEROLE" - ], - "db_owner": false, - "password": "secret", - "roles": [ - "pgedge_superuser" - ], - "username": "admin" - }, - { - "attributes": [ - "LOGIN", - "CREATEDB", - "CREATEROLE" - ], - "db_owner": false, - "password": "secret", - "roles": [ - "pgedge_superuser" - ], - "username": "admin" - }, - { - "attributes": [ - "LOGIN", - "CREATEDB", - "CREATEROLE" - ], - "db_owner": false, - "password": "secret", - "roles": [ - "pgedge_superuser" - ], - "username": "admin" - } - ], - "maxItems": 16 - }, - "memory": { - "type": "string", - "description": "The amount of memory in SI or IEC notation to allocate for the database and to use for tuning Postgres. Defaults to the total available memory on the host. Whether this limit is enforced depends on the orchestrator.", - "example": "500M", - "maxLength": 16 - }, - "nodes": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DatabaseNodeSpec4" - }, - "description": "The Spock nodes for this database.", - "example": [ - { - "backup_config": { - "repositories": [ - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - } - ], - "schedules": [ - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - } - ] - }, - "cpus": "500m", - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "500M", - "name": "n1", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Incidunt in quas totam." - } - }, - "patroni_port": 8888, - "pg_hba_conf": [ - "host example myapp_user 10.0.0.0/8 scram-sha-256" + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" ], - "pg_ident_conf": [ - "ssl_users CN=alice,O=example alice" + "db_owner": true, + "password": "secret", + "roles": [ + "pgedge_superuser" ], - "port": 5432, - "postgres_version": "17.6", - "postgresql_conf": { - "max_connections": 1000 - }, - "restore_config": { - "repository": { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - "restore_options": { - "set": "20250505-153628F", - "target": "123456", - "type": "xid" - }, - "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "source_database_name": "northwind", - "source_node_name": "n1" - }, - "source_node": "n1" + "username": "admin" + }, + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": true, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" }, + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": true, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + } + ], + "maxItems": 16 + }, + "memory": { + "type": "string", + "description": "The amount of memory in SI or IEC notation to allocate for the database and to use for tuning Postgres. Defaults to the total available memory on the host. Whether this limit is enforced depends on the orchestrator.", + "example": "500M", + "maxLength": 16 + }, + "nodes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DatabaseNodeSpec5" + }, + "description": "The Spock nodes for this database.", + "example": [ { "backup_config": { "repositories": [ @@ -17549,158 +21075,6 @@ "s3_region": "us-east-1", "type": "s3" }, - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - } - ], - "schedules": [ - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - } - ] - }, - "cpus": "500m", - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "500M", - "name": "n1", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Incidunt in quas totam." - } - }, - "patroni_port": 8888, - "pg_hba_conf": [ - "host example myapp_user 10.0.0.0/8 scram-sha-256" - ], - "pg_ident_conf": [ - "ssl_users CN=alice,O=example alice" - ], - "port": 5432, - "postgres_version": "17.6", - "postgresql_conf": { - "max_connections": 1000 - }, - "restore_config": { - "repository": { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - "restore_options": { - "set": "20250505-153628F", - "target": "123456", - "type": "xid" - }, - "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "source_database_name": "northwind", - "source_node_name": "n1" - }, - "source_node": "n1" - }, - { - "backup_config": { - "repositories": [ { "azure_account": "pgedge-backups", "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -17768,7 +21142,6 @@ }, "cpus": "500m", "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], @@ -17826,7 +21199,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Et odio." } }, "patroni_port": 8888, @@ -17871,7 +21244,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" } ], "minItems": 1, @@ -17892,7 +21266,7 @@ "type": "array", "items": { "type": "string", - "example": "Tempora in veniam officia ratione minus." + "example": "Est nisi." }, "description": "Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these.", "example": [ @@ -17904,7 +21278,7 @@ "type": "array", "items": { "type": "string", - "example": "Occaecati et et consequuntur." + "example": "Sit dignissimos ducimus reiciendis asperiores explicabo." }, "description": "Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames.", "example": [ @@ -17943,7 +21317,7 @@ "services": { "type": "array", "items": { - "$ref": "#/components/schemas/ServiceSpec4" + "$ref": "#/components/schemas/ServiceSpec5" }, "description": "Service instances to run alongside the database (e.g., MCP servers).", "example": [ @@ -18019,7 +21393,87 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Et odio." + } + }, + "port": 0, + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "service_type": "rag", + "version": "latest" + }, + { + "config": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "connect_as": "app", + "cpus": "500m", + "database_connection": { + "target_nodes": [ + "n1", + "n2" + ], + "target_session_attrs": "primary" + }, + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "512M", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Et odio." } }, "port": 0, @@ -18099,7 +21553,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Et odio." } }, "port": 0, @@ -18179,7 +21633,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Et odio." } }, "port": 0, @@ -18222,6 +21676,29 @@ "s3_region": "us-east-1", "type": "s3" }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, { "azure_account": "pgedge-backups", "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -18273,7 +21750,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": false, + "db_owner": true, "password": "secret", "roles": [ "pgedge_superuser" @@ -18286,7 +21763,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": false, + "db_owner": true, "password": "secret", "roles": [ "pgedge_superuser" @@ -18299,7 +21776,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": false, + "db_owner": true, "password": "secret", "roles": [ "pgedge_superuser" @@ -18335,158 +21812,6 @@ "s3_region": "us-east-1", "type": "s3" }, - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - } - ], - "schedules": [ - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - } - ] - }, - "cpus": "500m", - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "500M", - "name": "n1", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Incidunt in quas totam." - } - }, - "patroni_port": 8888, - "pg_hba_conf": [ - "host example myapp_user 10.0.0.0/8 scram-sha-256" - ], - "pg_ident_conf": [ - "ssl_users CN=alice,O=example alice" - ], - "port": 5432, - "postgres_version": "17.6", - "postgresql_conf": { - "max_connections": 1000 - }, - "restore_config": { - "repository": { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - "restore_options": { - "set": "20250505-153628F", - "target": "123456", - "type": "xid" - }, - "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "source_database_name": "northwind", - "source_node_name": "n1" - }, - "source_node": "n1" - }, - { - "backup_config": { - "repositories": [ { "azure_account": "pgedge-backups", "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -18554,7 +21879,6 @@ }, "cpus": "500m", "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], @@ -18612,7 +21936,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Et odio." } }, "patroni_port": 8888, @@ -18657,7 +21981,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, { "backup_config": { @@ -18685,6 +22010,29 @@ "s3_region": "us-east-1", "type": "s3" }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, { "azure_account": "pgedge-backups", "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -18729,7 +22077,6 @@ }, "cpus": "500m", "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], @@ -18787,7 +22134,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Et odio." } }, "patroni_port": 8888, @@ -18832,7 +22179,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" } ], "orchestrator_opts": { @@ -18872,240 +22220,80 @@ }, "id": "traefik-public" } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Incidunt in quas totam." - } - }, - "patroni_port": 8888, - "pg_hba_conf": [ - "hostssl all myapp_user 203.0.113.0/24 scram-sha-256", - "hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users" - ], - "pg_ident_conf": [ - "ssl_users CN=alice,O=example alice" - ], - "port": 5432, - "postgres_version": "17.6", - "postgresql_conf": { - "max_connections": 1000 - }, - "restore_config": { - "repository": { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - "restore_options": { - "set": "20250505-153628F", - "target": "123456", - "type": "xid" - }, - "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "source_database_name": "northwind", - "source_node_name": "n1" - }, - "scripts": { - "post_database_create": [ - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" - ], - "post_init": [ - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" - ] - }, - "services": [ - { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." - }, - "connect_as": "app", - "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" - ], - "target_session_attrs": "primary" - }, - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "512M", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Incidunt in quas totam." - } - }, - "port": 0, - "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "service_type": "rag", - "version": "latest" - }, - { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." - }, - "connect_as": "app", - "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" - ], - "target_session_attrs": "primary" - }, - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "512M", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Incidunt in quas totam." - } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Et odio." + } + }, + "patroni_port": 8888, + "pg_hba_conf": [ + "hostssl all myapp_user 203.0.113.0/24 scram-sha-256", + "hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users" + ], + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" + ], + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 + }, + "restore_config": { + "repository": { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" }, - "port": 0, - "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "service_type": "rag", - "version": "latest" + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" }, + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "source_database_name": "northwind", + "source_node_name": "n1" + }, + "scripts": { + "post_database_create": [ + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" + ], + "post_init": [ + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" + ] + }, + "services": [ { "config": { "llm_model": "gpt-4", @@ -19178,7 +22366,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Et odio." } }, "port": 0, @@ -19225,784 +22413,292 @@ }, { "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Incidunt in quas totam." - } - }, - "port": 0, - "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "service_type": "rag", - "version": "latest" - } - ], - "spock_version": "5" - }, - "required": [ - "database_name", - "nodes" - ] - }, - "DatabaseSpec5": { - "type": "object", - "properties": { - "backup_config": { - "$ref": "#/components/schemas/BackupConfigSpec" - }, - "cpus": { - "type": "string", - "description": "The number of CPUs to allocate for the database and to use for tuning Postgres. Defaults to the number of available CPUs on the host. Can include an SI suffix, e.g. '500m' for 500 millicpus. Whether this limit is enforced depends on the orchestrator.", - "example": "500m", - "pattern": "^[0-9]+(\\.[0-9]{1,3}|m)?$" - }, - "database_name": { - "type": "string", - "description": "The name of the Postgres database.", - "example": "northwind", - "minLength": 1, - "maxLength": 31 - }, - "database_users": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DatabaseUserSpec" - }, - "description": "The users to create for this database.", - "example": [ - { - "attributes": [ - "LOGIN", - "CREATEDB", - "CREATEROLE" - ], - "db_owner": true, - "password": "secret", - "roles": [ - "pgedge_superuser" - ], - "username": "admin" - }, - { - "attributes": [ - "LOGIN", - "CREATEDB", - "CREATEROLE" - ], - "db_owner": true, - "password": "secret", - "roles": [ - "pgedge_superuser" - ], - "username": "admin" - }, - { - "attributes": [ - "LOGIN", - "CREATEDB", - "CREATEROLE" - ], - "db_owner": true, - "password": "secret", - "roles": [ - "pgedge_superuser" - ], - "username": "admin" - } - ], - "maxItems": 16 - }, - "memory": { - "type": "string", - "description": "The amount of memory in SI or IEC notation to allocate for the database and to use for tuning Postgres. Defaults to the total available memory on the host. Whether this limit is enforced depends on the orchestrator.", - "example": "500M", - "maxLength": 16 - }, - "nodes": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DatabaseNodeSpec5" - }, - "description": "The Spock nodes for this database.", - "example": [ - { - "backup_config": { - "repositories": [ - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" }, { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" + "id": "traefik-public" } ], - "schedules": [ + "extra_volumes": [ { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" }, { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" }, { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" } - ] - }, - "cpus": "500m", - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "500M", - "name": "n1", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Et odio." - } - }, - "patroni_port": 8888, - "pg_hba_conf": [ - "host example myapp_user 10.0.0.0/8 scram-sha-256" - ], - "pg_ident_conf": [ - "ssl_users CN=alice,O=example alice" + ], + "image": "Et odio." + } + }, + "port": 0, + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "service_type": "rag", + "version": "latest" + }, + { + "config": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "connect_as": "app", + "cpus": "500m", + "database_connection": { + "target_nodes": [ + "n1", + "n2" ], - "port": 5432, - "postgres_version": "17.6", - "postgresql_conf": { - "max_connections": 1000 - }, - "restore_config": { - "repository": { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - "restore_options": { - "set": "20250505-153628F", - "target": "123456", - "type": "xid" - }, - "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "source_database_name": "northwind", - "source_node_name": "n1" - }, - "source_node": "n1" + "target_session_attrs": "primary" }, - { - "backup_config": { - "repositories": [ + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "512M", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" + "id": "traefik-public" }, { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" + "id": "traefik-public" }, - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" + "id": "traefik-public" } ], - "schedules": [ + "extra_volumes": [ { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" }, { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" }, { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" } - ] - }, - "cpus": "500m", - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "500M", - "name": "n1", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Et odio." - } - }, - "patroni_port": 8888, - "pg_hba_conf": [ - "host example myapp_user 10.0.0.0/8 scram-sha-256" - ], - "pg_ident_conf": [ - "ssl_users CN=alice,O=example alice" - ], - "port": 5432, - "postgres_version": "17.6", - "postgresql_conf": { - "max_connections": 1000 - }, - "restore_config": { - "repository": { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - "restore_options": { - "set": "20250505-153628F", - "target": "123456", - "type": "xid" - }, - "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "source_database_name": "northwind", - "source_node_name": "n1" - }, - "source_node": "n1" - } - ], - "minItems": 1, - "maxItems": 9 - }, - "orchestrator_opts": { - "$ref": "#/components/schemas/OrchestratorOpts" + ], + "image": "Et odio." + } + }, + "port": 0, + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "service_type": "rag", + "version": "latest" + } + ], + "spock_version": "5" + }, + "required": [ + "database_name", + "nodes" + ] + }, + "DatabaseSpec6": { + "type": "object", + "properties": { + "backup_config": { + "$ref": "#/components/schemas/BackupConfigSpec" }, - "patroni_port": { - "type": "integer", - "description": "The port used by Patroni for this database. If the port is 0, each instance will be assigned a random port. NOTE: This field is not currently supported for Docker Swarm.", - "example": 8888, - "format": "int64", - "minimum": 0, - "maximum": 65535 + "cpus": { + "type": "string", + "description": "The number of CPUs to allocate for the database and to use for tuning Postgres. Defaults to the number of available CPUs on the host. Can include an SI suffix, e.g. '500m' for 500 millicpus. Whether this limit is enforced depends on the orchestrator.", + "example": "500m", + "pattern": "^[0-9]+(\\.[0-9]{1,3}|m)?$" }, - "pg_hba_conf": { - "type": "array", - "items": { - "type": "string", - "example": "Iure molestiae." - }, - "description": "Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these.", - "example": [ - "hostssl all myapp_user 203.0.113.0/24 scram-sha-256", - "hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users" - ] + "database_name": { + "type": "string", + "description": "The name of the Postgres database.", + "example": "northwind", + "minLength": 1, + "maxLength": 31 }, - "pg_ident_conf": { + "database_users": { "type": "array", "items": { - "type": "string", - "example": "Nesciunt quia quis aut ducimus deserunt." + "$ref": "#/components/schemas/DatabaseUserSpec" }, - "description": "Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames.", + "description": "The users to create for this database.", "example": [ - "ssl_users CN=alice,O=example alice" - ] - }, - "port": { - "type": "integer", - "description": "The port used by the Postgres database. If the port is 0, each instance will be assigned a random port. If the port is unspecified, the database will not be exposed on any port, dependent on orchestrator support for that feature.", - "example": 5432, - "format": "int64", - "minimum": 0, - "maximum": 65535 + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + }, + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + }, + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + } + ], + "maxItems": 16 }, - "postgres_version": { + "memory": { "type": "string", - "description": "The Postgres version in 'major.minor' format.", - "example": "17.6", - "pattern": "^\\d{2}\\.\\d{1,2}$" - }, - "postgresql_conf": { - "type": "object", - "description": "Additional postgresql.conf settings. Will be merged with the settings provided by control-plane.", - "example": { - "max_connections": 1000 - }, - "maxLength": 64, - "additionalProperties": true - }, - "restore_config": { - "$ref": "#/components/schemas/RestoreConfigSpec" - }, - "scripts": { - "$ref": "#/components/schemas/DatabaseScripts" + "description": "The amount of memory in SI or IEC notation to allocate for the database and to use for tuning Postgres. Defaults to the total available memory on the host. Whether this limit is enforced depends on the orchestrator.", + "example": "500M", + "maxLength": 16 }, - "services": { + "nodes": { "type": "array", "items": { - "$ref": "#/components/schemas/ServiceSpec5" + "$ref": "#/components/schemas/DatabaseNodeSpec6" }, - "description": "Service instances to run alongside the database (e.g., MCP servers).", + "description": "The Spock nodes for this database.", "example": [ { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." - }, - "connect_as": "app", - "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" - ], - "target_session_attrs": "primary" - }, - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "512M", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" + "backup_config": { + "repositories": [ + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Et odio." - } - }, - "port": 0, - "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "service_type": "rag", - "version": "latest" - }, - { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." - }, - "connect_as": "app", - "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" - ], - "target_session_attrs": "primary" - }, - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "512M", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Et odio." - } - }, - "port": 0, - "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "service_type": "rag", - "version": "latest" - }, - { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." - }, - "connect_as": "app", - "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + } ], - "target_session_attrs": "primary" + "schedules": [ + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + } + ] }, + "cpus": "500m", "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], - "memory": "512M", + "memory": "500M", + "name": "n1", "orchestrator_opts": { "swarm": { "extra_labels": { @@ -20012,418 +22708,254 @@ "extra_networks": [ { "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Et odio." - } - }, - "port": 0, - "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "service_type": "rag", - "version": "latest" - } - ] - }, - "spock_version": { - "type": "string", - "description": "The major version of the Spock extension.", - "example": "5", - "pattern": "^\\d{1}$" - } - }, - "example": { - "backup_config": { - "repositories": [ - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - } - ], - "schedules": [ - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - } - ] - }, - "cpus": "500m", - "database_name": "northwind", - "database_users": [ - { - "attributes": [ - "LOGIN", - "CREATEDB", - "CREATEROLE" - ], - "db_owner": true, - "password": "secret", - "roles": [ - "pgedge_superuser" - ], - "username": "admin" - }, - { - "attributes": [ - "LOGIN", - "CREATEDB", - "CREATEROLE" - ], - "db_owner": true, - "password": "secret", - "roles": [ - "pgedge_superuser" - ], - "username": "admin" - }, - { - "attributes": [ - "LOGIN", - "CREATEDB", - "CREATEROLE" - ], - "db_owner": true, - "password": "secret", - "roles": [ - "pgedge_superuser" - ], - "username": "admin" - } - ], - "memory": "500M", - "nodes": [ - { - "backup_config": { - "repositories": [ - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - { + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Incidunt in quas totam." + } + }, + "patroni_port": 8888, + "pg_hba_conf": [ + "host example myapp_user 10.0.0.0/8 scram-sha-256" + ], + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" + ], + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 + }, + "restore_config": { + "repository": { "azure_account": "pgedge-backups", "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "azure_endpoint": "blob.core.usgovcloudapi.net", "azure_key": "YXpLZXk=", "base_path": "/backups", "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" }, "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "s3_endpoint": "s3.us-east-1.amazonaws.com", "s3_key": "AKIAIOSFODNN7EXAMPLE", "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", "s3_region": "us-east-1", "type": "s3" - } - ], - "schedules": [ - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - } - ] + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "source_database_name": "northwind", + "source_node_name": "n1" + }, + "source_node": "n1", + "spock_version": "6" }, - "cpus": "500m", - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "500M", - "name": "n1", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, + { + "backup_config": { + "repositories": [ { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" }, - "id": "traefik-public" + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" }, { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" }, - "id": "traefik-public" + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" } ], - "extra_volumes": [ + "schedules": [ { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" }, { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" }, { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" } - ], - "image": "Et odio." - } - }, - "patroni_port": 8888, - "pg_hba_conf": [ - "host example myapp_user 10.0.0.0/8 scram-sha-256" - ], - "pg_ident_conf": [ - "ssl_users CN=alice,O=example alice" - ], - "port": 5432, - "postgres_version": "17.6", - "postgresql_conf": { - "max_connections": 1000 - }, - "restore_config": { - "repository": { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" + ] + }, + "cpus": "500m", + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "500M", + "name": "n1", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Incidunt in quas totam." + } }, - "restore_options": { - "set": "20250505-153628F", - "target": "123456", - "type": "xid" + "patroni_port": 8888, + "pg_hba_conf": [ + "host example myapp_user 10.0.0.0/8 scram-sha-256" + ], + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" + ], + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 }, - "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "source_database_name": "northwind", - "source_node_name": "n1" - }, - "source_node": "n1" - }, - { - "backup_config": { - "repositories": [ - { + "restore_config": { + "repository": { "azure_account": "pgedge-backups", "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "azure_endpoint": "blob.core.usgovcloudapi.net", "azure_key": "YXpLZXk=", "base_path": "/backups", "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" }, "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "s3_endpoint": "s3.us-east-1.amazonaws.com", "s3_key": "AKIAIOSFODNN7EXAMPLE", @@ -20431,389 +22963,450 @@ "s3_region": "us-east-1", "type": "s3" }, - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" }, - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - } + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "source_database_name": "northwind", + "source_node_name": "n1" + }, + "source_node": "n1", + "spock_version": "6" + } + ], + "minItems": 1, + "maxItems": 9 + }, + "orchestrator_opts": { + "$ref": "#/components/schemas/OrchestratorOpts" + }, + "patroni_port": { + "type": "integer", + "description": "The port used by Patroni for this database. If the port is 0, each instance will be assigned a random port. NOTE: This field is not currently supported for Docker Swarm.", + "example": 8888, + "format": "int64", + "minimum": 0, + "maximum": 65535 + }, + "pg_hba_conf": { + "type": "array", + "items": { + "type": "string", + "example": "Iste dicta assumenda et." + }, + "description": "Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these.", + "example": [ + "hostssl all myapp_user 203.0.113.0/24 scram-sha-256", + "hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users" + ] + }, + "pg_ident_conf": { + "type": "array", + "items": { + "type": "string", + "example": "Dolorem aut." + }, + "description": "Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames.", + "example": [ + "ssl_users CN=alice,O=example alice" + ] + }, + "port": { + "type": "integer", + "description": "The port used by the Postgres database. If the port is 0, each instance will be assigned a random port. If the port is unspecified, the database will not be exposed on any port, dependent on orchestrator support for that feature.", + "example": 5432, + "format": "int64", + "minimum": 0, + "maximum": 65535 + }, + "postgres_version": { + "type": "string", + "description": "The Postgres version in 'major.minor' format.", + "example": "17.6", + "pattern": "^\\d{2}\\.\\d{1,2}$" + }, + "postgresql_conf": { + "type": "object", + "description": "Additional postgresql.conf settings. Will be merged with the settings provided by control-plane.", + "example": { + "max_connections": 1000 + }, + "maxLength": 64, + "additionalProperties": true + }, + "restore_config": { + "$ref": "#/components/schemas/RestoreConfigSpec" + }, + "scripts": { + "$ref": "#/components/schemas/DatabaseScripts" + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ServiceSpec6" + }, + "description": "Service instances to run alongside the database (e.g., MCP servers).", + "example": [ + { + "config": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "connect_as": "app", + "cpus": "500m", + "database_connection": { + "target_nodes": [ + "n1", + "n2" + ], + "target_session_attrs": "primary" + }, + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" ], - "schedules": [ - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - } - ] - }, - "cpus": "500m", - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "500M", - "name": "n1", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" + "memory": "512M", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" }, - "id": "traefik-public" - } + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Incidunt in quas totam." + } + }, + "port": 0, + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "service_type": "rag", + "version": "latest" + }, + { + "config": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "connect_as": "app", + "cpus": "500m", + "database_connection": { + "target_nodes": [ + "n1", + "n2" ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" + "target_session_attrs": "primary" + }, + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "512M", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Et odio." - } - }, - "patroni_port": 8888, - "pg_hba_conf": [ - "host example myapp_user 10.0.0.0/8 scram-sha-256" - ], - "pg_ident_conf": [ - "ssl_users CN=alice,O=example alice" - ], - "port": 5432, - "postgres_version": "17.6", - "postgresql_conf": { - "max_connections": 1000 - }, - "restore_config": { - "repository": { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Incidunt in quas totam." + } }, - "restore_options": { - "set": "20250505-153628F", - "target": "123456", - "type": "xid" + "port": 0, + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "service_type": "rag", + "version": "latest" + } + ] + }, + "spock_version": { + "type": "string", + "description": "The major version of the Spock extension.", + "example": "5", + "pattern": "^\\d{1}$" + } + }, + "example": { + "backup_config": { + "repositories": [ + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" }, - "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "source_database_name": "northwind", - "source_node_name": "n1" + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + } + ], + "schedules": [ + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" }, - "source_node": "n1" - } - ], - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + } + ] + }, + "cpus": "500m", + "database_name": "northwind", + "database_users": [ + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" ], - "image": "Et odio." - } - }, - "patroni_port": 8888, - "pg_hba_conf": [ - "hostssl all myapp_user 203.0.113.0/24 scram-sha-256", - "hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users" - ], - "pg_ident_conf": [ - "ssl_users CN=alice,O=example alice" - ], - "port": 5432, - "postgres_version": "17.6", - "postgresql_conf": { - "max_connections": 1000 - }, - "restore_config": { - "repository": { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" + "username": "admin" }, - "restore_options": { - "set": "20250505-153628F", - "target": "123456", - "type": "xid" + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" }, - "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "source_database_name": "northwind", - "source_node_name": "n1" - }, - "scripts": { - "post_database_create": [ - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" - ], - "post_init": [ - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" - ] - }, - "services": [ { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." - }, - "connect_as": "app", - "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" - ], - "target_session_attrs": "primary" - }, - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" ], - "memory": "512M", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + } + ], + "memory": "500M", + "nodes": [ + { + "backup_config": { + "repositories": [ + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Et odio." - } - }, - "port": 0, - "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "service_type": "rag", - "version": "latest" - }, - { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." - }, - "connect_as": "app", - "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + } ], - "target_session_attrs": "primary" + "schedules": [ + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + } + ] }, + "cpus": "500m", "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], - "memory": "512M", + "memory": "500M", + "name": "n1", "orchestrator_opts": { "swarm": { "extra_labels": { @@ -20866,114 +23459,130 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Et odio." + "image": "Incidunt in quas totam." } }, - "port": 0, - "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "service_type": "rag", - "version": "latest" - }, - { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." - }, - "connect_as": "app", - "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" - ], - "target_session_attrs": "primary" - }, - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" + "patroni_port": 8888, + "pg_hba_conf": [ + "host example myapp_user 10.0.0.0/8 scram-sha-256" ], - "memory": "512M", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" + ], + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 + }, + "restore_config": { + "repository": { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Et odio." - } + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" + }, + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "source_database_name": "northwind", + "source_node_name": "n1" }, - "port": 0, - "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "service_type": "rag", - "version": "latest" + "source_node": "n1", + "spock_version": "6" }, { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." + "backup_config": { + "repositories": [ + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + } + ], + "schedules": [ + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + } + ] }, - "connect_as": "app", "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" - ], - "target_session_attrs": "primary" - }, "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], - "memory": "512M", + "memory": "500M", + "name": "n1", "orchestrator_opts": { "swarm": { "extra_labels": { @@ -21026,787 +23635,651 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Et odio." + "image": "Incidunt in quas totam." } }, - "port": 0, - "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "service_type": "rag", - "version": "latest" + "patroni_port": 8888, + "pg_hba_conf": [ + "host example myapp_user 10.0.0.0/8 scram-sha-256" + ], + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" + ], + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 + }, + "restore_config": { + "repository": { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" + }, + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "source_database_name": "northwind", + "source_node_name": "n1" + }, + "source_node": "n1", + "spock_version": "6" } ], - "spock_version": "5" - }, - "required": [ - "database_name", - "nodes" - ] - }, - "DatabaseSpec6": { - "type": "object", - "properties": { - "backup_config": { - "$ref": "#/components/schemas/BackupConfigSpec" - }, - "cpus": { - "type": "string", - "description": "The number of CPUs to allocate for the database and to use for tuning Postgres. Defaults to the number of available CPUs on the host. Can include an SI suffix, e.g. '500m' for 500 millicpus. Whether this limit is enforced depends on the orchestrator.", - "example": "500m", - "pattern": "^[0-9]+(\\.[0-9]{1,3}|m)?$" + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Incidunt in quas totam." + } }, - "database_name": { - "type": "string", - "description": "The name of the Postgres database.", - "example": "northwind", - "minLength": 1, - "maxLength": 31 + "patroni_port": 8888, + "pg_hba_conf": [ + "hostssl all myapp_user 203.0.113.0/24 scram-sha-256", + "hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users" + ], + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" + ], + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 }, - "database_users": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DatabaseUserSpec" - }, - "description": "The users to create for this database.", - "example": [ - { - "attributes": [ - "LOGIN", - "CREATEDB", - "CREATEROLE" - ], - "db_owner": false, - "password": "secret", - "roles": [ - "pgedge_superuser" - ], - "username": "admin" - }, - { - "attributes": [ - "LOGIN", - "CREATEDB", - "CREATEROLE" - ], - "db_owner": false, - "password": "secret", - "roles": [ - "pgedge_superuser" - ], - "username": "admin" + "restore_config": { + "repository": { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" }, - { - "attributes": [ - "LOGIN", - "CREATEDB", - "CREATEROLE" - ], - "db_owner": false, - "password": "secret", - "roles": [ - "pgedge_superuser" - ], - "username": "admin" - } - ], - "maxItems": 16 + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" + }, + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "source_database_name": "northwind", + "source_node_name": "n1" }, - "memory": { - "type": "string", - "description": "The amount of memory in SI or IEC notation to allocate for the database and to use for tuning Postgres. Defaults to the total available memory on the host. Whether this limit is enforced depends on the orchestrator.", - "example": "500M", - "maxLength": 16 + "scripts": { + "post_database_create": [ + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" + ], + "post_init": [ + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" + ] }, - "nodes": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DatabaseNodeSpec6" - }, - "description": "The Spock nodes for this database.", - "example": [ - { - "backup_config": { - "repositories": [ + "services": [ + { + "config": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "connect_as": "app", + "cpus": "500m", + "database_connection": { + "target_nodes": [ + "n1", + "n2" + ], + "target_session_attrs": "primary" + }, + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "512M", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" + "id": "traefik-public" }, { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" } ], - "schedules": [ + "extra_volumes": [ { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" }, { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" }, { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" } - ] - }, - "cpus": "500m", - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "500M", - "name": "n1", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Incidunt in quas totam." - } - }, - "patroni_port": 8888, - "pg_hba_conf": [ - "host example myapp_user 10.0.0.0/8 scram-sha-256" - ], - "pg_ident_conf": [ - "ssl_users CN=alice,O=example alice" + ], + "image": "Incidunt in quas totam." + } + }, + "port": 0, + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "service_type": "rag", + "version": "latest" + }, + { + "config": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "connect_as": "app", + "cpus": "500m", + "database_connection": { + "target_nodes": [ + "n1", + "n2" ], - "port": 5432, - "postgres_version": "17.6", - "postgresql_conf": { - "max_connections": 1000 - }, - "restore_config": { - "repository": { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - "restore_options": { - "set": "20250505-153628F", - "target": "123456", - "type": "xid" - }, - "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "source_database_name": "northwind", - "source_node_name": "n1" - }, - "source_node": "n1" + "target_session_attrs": "primary" }, - { - "backup_config": { - "repositories": [ + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "512M", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" + "id": "traefik-public" }, { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" + "id": "traefik-public" } ], - "schedules": [ + "extra_volumes": [ { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" }, { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" }, { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" } - ] - }, - "cpus": "500m", - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "image": "Incidunt in quas totam." + } + }, + "port": 0, + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "service_type": "rag", + "version": "latest" + }, + { + "config": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "connect_as": "app", + "cpus": "500m", + "database_connection": { + "target_nodes": [ + "n1", + "n2" ], - "memory": "500M", - "name": "n1", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + "target_session_attrs": "primary" + }, + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "512M", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Incidunt in quas totam." + } + }, + "port": 0, + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "service_type": "rag", + "version": "latest" + }, + { + "config": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "connect_as": "app", + "cpus": "500m", + "database_connection": { + "target_nodes": [ + "n1", + "n2" + ], + "target_session_attrs": "primary" + }, + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "512M", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Incidunt in quas totam." - } - }, - "patroni_port": 8888, - "pg_hba_conf": [ - "host example myapp_user 10.0.0.0/8 scram-sha-256" - ], - "pg_ident_conf": [ - "ssl_users CN=alice,O=example alice" - ], - "port": 5432, - "postgres_version": "17.6", - "postgresql_conf": { - "max_connections": 1000 - }, - "restore_config": { - "repository": { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - "restore_options": { - "set": "20250505-153628F", - "target": "123456", - "type": "xid" - }, - "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "source_database_name": "northwind", - "source_node_name": "n1" - }, - "source_node": "n1" - } - ], - "minItems": 1, - "maxItems": 9 - }, - "orchestrator_opts": { - "$ref": "#/components/schemas/OrchestratorOpts" - }, - "patroni_port": { - "type": "integer", - "description": "The port used by Patroni for this database. If the port is 0, each instance will be assigned a random port. NOTE: This field is not currently supported for Docker Swarm.", - "example": 8888, - "format": "int64", - "minimum": 0, - "maximum": 65535 - }, - "pg_hba_conf": { - "type": "array", - "items": { - "type": "string", - "example": "Modi facere est." - }, - "description": "Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these.", - "example": [ - "hostssl all myapp_user 203.0.113.0/24 scram-sha-256", - "hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users" - ] - }, - "pg_ident_conf": { - "type": "array", - "items": { - "type": "string", - "example": "Qui excepturi debitis aperiam rerum at." - }, - "description": "Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames.", - "example": [ - "ssl_users CN=alice,O=example alice" - ] - }, - "port": { - "type": "integer", - "description": "The port used by the Postgres database. If the port is 0, each instance will be assigned a random port. If the port is unspecified, the database will not be exposed on any port, dependent on orchestrator support for that feature.", - "example": 5432, - "format": "int64", - "minimum": 0, - "maximum": 65535 + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Incidunt in quas totam." + } + }, + "port": 0, + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "service_type": "rag", + "version": "latest" + } + ], + "spock_version": "5" + }, + "required": [ + "database_name", + "nodes" + ] + }, + "DatabaseSpec7": { + "type": "object", + "properties": { + "backup_config": { + "$ref": "#/components/schemas/BackupConfigSpec" }, - "postgres_version": { + "cpus": { "type": "string", - "description": "The Postgres version in 'major.minor' format.", - "example": "17.6", - "pattern": "^\\d{2}\\.\\d{1,2}$" - }, - "postgresql_conf": { - "type": "object", - "description": "Additional postgresql.conf settings. Will be merged with the settings provided by control-plane.", - "example": { - "max_connections": 1000 - }, - "maxLength": 64, - "additionalProperties": true - }, - "restore_config": { - "$ref": "#/components/schemas/RestoreConfigSpec" + "description": "The number of CPUs to allocate for the database and to use for tuning Postgres. Defaults to the number of available CPUs on the host. Can include an SI suffix, e.g. '500m' for 500 millicpus. Whether this limit is enforced depends on the orchestrator.", + "example": "500m", + "pattern": "^[0-9]+(\\.[0-9]{1,3}|m)?$" }, - "scripts": { - "$ref": "#/components/schemas/DatabaseScripts" + "database_name": { + "type": "string", + "description": "The name of the Postgres database.", + "example": "northwind", + "minLength": 1, + "maxLength": 31 }, - "services": { + "database_users": { "type": "array", "items": { - "$ref": "#/components/schemas/ServiceSpec6" + "$ref": "#/components/schemas/DatabaseUserSpec" }, - "description": "Service instances to run alongside the database (e.g., MCP servers).", + "description": "The users to create for this database.", "example": [ { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." - }, - "connect_as": "app", - "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" - ], - "target_session_attrs": "primary" - }, - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" ], - "memory": "512M", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Incidunt in quas totam." - } - }, - "port": 0, - "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "service_type": "rag", - "version": "latest" + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" }, { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." - }, - "connect_as": "app", - "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" - ], - "target_session_attrs": "primary" - }, - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" ], - "memory": "512M", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Incidunt in quas totam." - } - }, - "port": 0, - "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "service_type": "rag", - "version": "latest" + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" }, { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." - }, - "connect_as": "app", - "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" - ], - "target_session_attrs": "primary" - }, - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" ], - "memory": "512M", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + } + ], + "maxItems": 16 + }, + "memory": { + "type": "string", + "description": "The amount of memory in SI or IEC notation to allocate for the database and to use for tuning Postgres. Defaults to the total available memory on the host. Whether this limit is enforced depends on the orchestrator.", + "example": "500M", + "maxLength": 16 + }, + "nodes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DatabaseNodeSpec7" + }, + "description": "The Spock nodes for this database.", + "example": [ + { + "backup_config": { + "repositories": [ + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Incidunt in quas totam." - } - }, - "port": 0, - "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "service_type": "rag", - "version": "latest" - }, - { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + } + ], + "schedules": [ + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + } + ] }, - "connect_as": "app", "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" - ], - "target_session_attrs": "primary" - }, "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], - "memory": "512M", + "memory": "500M", + "name": "n1", "orchestrator_opts": { "swarm": { "extra_labels": { @@ -21862,152 +24335,32 @@ "image": "Incidunt in quas totam." } }, - "port": 0, - "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "service_type": "rag", - "version": "latest" - } - ] - }, - "spock_version": { - "type": "string", - "description": "The major version of the Spock extension.", - "example": "5", - "pattern": "^\\d{1}$" - } - }, - "example": { - "backup_config": { - "repositories": [ - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" + "patroni_port": 8888, + "pg_hba_conf": [ + "host example myapp_user 10.0.0.0/8 scram-sha-256" + ], + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" + ], + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - } - ], - "schedules": [ - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - } - ] - }, - "cpus": "500m", - "database_name": "northwind", - "database_users": [ - { - "attributes": [ - "LOGIN", - "CREATEDB", - "CREATEROLE" - ], - "db_owner": false, - "password": "secret", - "roles": [ - "pgedge_superuser" - ], - "username": "admin" - }, - { - "attributes": [ - "LOGIN", - "CREATEDB", - "CREATEROLE" - ], - "db_owner": false, - "password": "secret", - "roles": [ - "pgedge_superuser" - ], - "username": "admin" - }, - { - "attributes": [ - "LOGIN", - "CREATEDB", - "CREATEROLE" - ], - "db_owner": false, - "password": "secret", - "roles": [ - "pgedge_superuser" - ], - "username": "admin" - } - ], - "memory": "500M", - "nodes": [ - { - "backup_config": { - "repositories": [ - { + "restore_config": { + "repository": { "azure_account": "pgedge-backups", "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "azure_endpoint": "blob.core.usgovcloudapi.net", "azure_key": "YXpLZXk=", "base_path": "/backups", "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" }, "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "s3_endpoint": "s3.us-east-1.amazonaws.com", "s3_key": "AKIAIOSFODNN7EXAMPLE", @@ -22015,330 +24368,806 @@ "s3_region": "us-east-1", "type": "s3" }, - { + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" + }, + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "source_database_name": "northwind", + "source_node_name": "n1" + }, + "source_node": "n1", + "spock_version": "6" + }, + { + "backup_config": { + "repositories": [ + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + } + ], + "schedules": [ + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + } + ] + }, + "cpus": "500m", + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "500M", + "name": "n1", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Incidunt in quas totam." + } + }, + "patroni_port": 8888, + "pg_hba_conf": [ + "host example myapp_user 10.0.0.0/8 scram-sha-256" + ], + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" + ], + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 + }, + "restore_config": { + "repository": { "azure_account": "pgedge-backups", "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "azure_endpoint": "blob.core.usgovcloudapi.net", "azure_key": "YXpLZXk=", "base_path": "/backups", "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" }, "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "s3_endpoint": "s3.us-east-1.amazonaws.com", "s3_key": "AKIAIOSFODNN7EXAMPLE", "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", "s3_region": "us-east-1", "type": "s3" - } - ], - "schedules": [ - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - } - ] + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "source_database_name": "northwind", + "source_node_name": "n1" + }, + "source_node": "n1", + "spock_version": "6" }, - "cpus": "500m", - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "500M", - "name": "n1", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, + { + "backup_config": { + "repositories": [ { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" }, - "id": "traefik-public" + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" }, { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" }, - "id": "traefik-public" + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" } ], - "extra_volumes": [ + "schedules": [ { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" }, { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" }, { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" } - ], - "image": "Incidunt in quas totam." - } - }, - "patroni_port": 8888, - "pg_hba_conf": [ - "host example myapp_user 10.0.0.0/8 scram-sha-256" - ], - "pg_ident_conf": [ - "ssl_users CN=alice,O=example alice" - ], - "port": 5432, - "postgres_version": "17.6", - "postgresql_conf": { - "max_connections": 1000 - }, - "restore_config": { - "repository": { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" + ] + }, + "cpus": "500m", + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "500M", + "name": "n1", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Incidunt in quas totam." + } }, - "restore_options": { - "set": "20250505-153628F", - "target": "123456", - "type": "xid" + "patroni_port": 8888, + "pg_hba_conf": [ + "host example myapp_user 10.0.0.0/8 scram-sha-256" + ], + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" + ], + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 }, - "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "source_database_name": "northwind", - "source_node_name": "n1" - }, - "source_node": "n1" - }, - { - "backup_config": { - "repositories": [ - { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - { + "restore_config": { + "repository": { "azure_account": "pgedge-backups", "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "azure_endpoint": "blob.core.usgovcloudapi.net", "azure_key": "YXpLZXk=", "base_path": "/backups", "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", - "storage-upload-chunk-size": "5MiB" + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" }, "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "retention_full": 2, - "retention_full_type": "count", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "s3_endpoint": "s3.us-east-1.amazonaws.com", "s3_key": "AKIAIOSFODNN7EXAMPLE", "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", "s3_region": "us-east-1", "type": "s3" - } - ], - "schedules": [ - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "source_database_name": "northwind", + "source_node_name": "n1" + }, + "source_node": "n1", + "spock_version": "6" + } + ], + "minItems": 1, + "maxItems": 9 + }, + "orchestrator_opts": { + "$ref": "#/components/schemas/OrchestratorOpts" + }, + "patroni_port": { + "type": "integer", + "description": "The port used by Patroni for this database. If the port is 0, each instance will be assigned a random port. NOTE: This field is not currently supported for Docker Swarm.", + "example": 8888, + "format": "int64", + "minimum": 0, + "maximum": 65535 + }, + "pg_hba_conf": { + "type": "array", + "items": { + "type": "string", + "example": "Alias est mollitia." + }, + "description": "Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these.", + "example": [ + "hostssl all myapp_user 203.0.113.0/24 scram-sha-256", + "hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users" + ] + }, + "pg_ident_conf": { + "type": "array", + "items": { + "type": "string", + "example": "Possimus id laudantium sed delectus." + }, + "description": "Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames.", + "example": [ + "ssl_users CN=alice,O=example alice" + ] + }, + "port": { + "type": "integer", + "description": "The port used by the Postgres database. If the port is 0, each instance will be assigned a random port. If the port is unspecified, the database will not be exposed on any port, dependent on orchestrator support for that feature.", + "example": 5432, + "format": "int64", + "minimum": 0, + "maximum": 65535 + }, + "postgres_version": { + "type": "string", + "description": "The Postgres version in 'major.minor' format.", + "example": "17.6", + "pattern": "^\\d{2}\\.\\d{1,2}$" + }, + "postgresql_conf": { + "type": "object", + "description": "Additional postgresql.conf settings. Will be merged with the settings provided by control-plane.", + "example": { + "max_connections": 1000 + }, + "maxLength": 64, + "additionalProperties": true + }, + "restore_config": { + "$ref": "#/components/schemas/RestoreConfigSpec" + }, + "scripts": { + "$ref": "#/components/schemas/DatabaseScripts" + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ServiceSpec7" + }, + "description": "Service instances to run alongside the database (e.g., MCP servers).", + "example": [ + { + "config": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "connect_as": "app", + "cpus": "500m", + "database_connection": { + "target_nodes": [ + "n1", + "n2" + ], + "target_session_attrs": "primary" + }, + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "512M", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Incidunt in quas totam." } - ] + }, + "port": 0, + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "service_type": "rag", + "version": "latest" }, - "cpus": "500m", - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "500M", - "name": "n1", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" + { + "config": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "connect_as": "app", + "cpus": "500m", + "database_connection": { + "target_nodes": [ + "n1", + "n2" + ], + "target_session_attrs": "primary" + }, + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "512M", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" }, - "id": "traefik-public" - } + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Incidunt in quas totam." + } + }, + "port": 0, + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "service_type": "rag", + "version": "latest" + }, + { + "config": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "connect_as": "app", + "cpus": "500m", + "database_connection": { + "target_nodes": [ + "n1", + "n2" ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" + "target_session_attrs": "primary" + }, + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "512M", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Incidunt in quas totam." - } - }, - "patroni_port": 8888, - "pg_hba_conf": [ - "host example myapp_user 10.0.0.0/8 scram-sha-256" - ], - "pg_ident_conf": [ - "ssl_users CN=alice,O=example alice" - ], - "port": 5432, - "postgres_version": "17.6", - "postgresql_conf": { - "max_connections": 1000 - }, - "restore_config": { - "repository": { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" - }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Incidunt in quas totam." + } + }, + "port": 0, + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "service_type": "rag", + "version": "latest" + } + ] + }, + "spock_version": { + "type": "string", + "description": "The major version of the Spock extension.", + "example": "5", + "pattern": "^\\d{1}$" + } + }, + "example": { + "backup_config": { + "repositories": [ + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" }, - "restore_options": { - "set": "20250505-153628F", - "target": "123456", - "type": "xid" + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" }, - "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "source_database_name": "northwind", - "source_node_name": "n1" + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + } + ], + "schedules": [ + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" }, - "source_node": "n1" + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + } + ] + }, + "cpus": "500m", + "database_name": "northwind", + "database_users": [ + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + }, + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" }, + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + } + ], + "memory": "500M", + "nodes": [ { "backup_config": { "repositories": [ @@ -22512,7 +25341,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" } ], "orchestrator_opts": { @@ -22566,66 +25396,146 @@ "destination_path": "/backups/container", "host_path": "/Users/user/backups/host" } - ], - "image": "Incidunt in quas totam." - } - }, - "patroni_port": 8888, - "pg_hba_conf": [ - "hostssl all myapp_user 203.0.113.0/24 scram-sha-256", - "hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users" - ], - "pg_ident_conf": [ - "ssl_users CN=alice,O=example alice" - ], - "port": 5432, - "postgres_version": "17.6", - "postgresql_conf": { - "max_connections": 1000 - }, - "restore_config": { - "repository": { - "azure_account": "pgedge-backups", - "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "azure_endpoint": "blob.core.usgovcloudapi.net", - "azure_key": "YXpLZXk=", - "base_path": "/backups", - "custom_options": { - "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" + ], + "image": "Incidunt in quas totam." + } + }, + "patroni_port": 8888, + "pg_hba_conf": [ + "hostssl all myapp_user 203.0.113.0/24 scram-sha-256", + "hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users" + ], + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" + ], + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 + }, + "restore_config": { + "repository": { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" + }, + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "source_database_name": "northwind", + "source_node_name": "n1" + }, + "scripts": { + "post_database_create": [ + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" + ], + "post_init": [ + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" + ] + }, + "services": [ + { + "config": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "connect_as": "app", + "cpus": "500m", + "database_connection": { + "target_nodes": [ + "n1", + "n2" + ], + "target_session_attrs": "primary" + }, + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "512M", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Incidunt in quas totam." + } }, - "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "gcs_endpoint": "localhost", - "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", - "s3_endpoint": "s3.us-east-1.amazonaws.com", - "s3_key": "AKIAIOSFODNN7EXAMPLE", - "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", - "s3_region": "us-east-1", - "type": "s3" - }, - "restore_options": { - "set": "20250505-153628F", - "target": "123456", - "type": "xid" + "port": 0, + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "service_type": "rag", + "version": "latest" }, - "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "source_database_name": "northwind", - "source_node_name": "n1" - }, - "scripts": { - "post_database_create": [ - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" - ], - "post_init": [ - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" - ] - }, - "services": [ { "config": { "llm_model": "gpt-4", @@ -22794,7 +25704,7 @@ "nodes" ] }, - "DatabaseSpec7": { + "DatabaseSpec8": { "type": "object", "properties": { "backup_config": { @@ -22871,7 +25781,7 @@ "nodes": { "type": "array", "items": { - "$ref": "#/components/schemas/DatabaseNodeSpec7" + "$ref": "#/components/schemas/DatabaseNodeSpec8" }, "description": "The Spock nodes for this database.", "example": [ @@ -23048,7 +25958,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, { "backup_config": { @@ -23223,7 +26134,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, { "backup_config": { @@ -23398,7 +26310,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" } ], "minItems": 1, @@ -23419,7 +26332,7 @@ "type": "array", "items": { "type": "string", - "example": "Odit placeat quod facere possimus sit." + "example": "Sed esse id natus aut." }, "description": "Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these.", "example": [ @@ -23431,7 +26344,7 @@ "type": "array", "items": { "type": "string", - "example": "In dolor unde optio illo." + "example": "Minus sint totam et et." }, "description": "Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames.", "example": [ @@ -23470,7 +26383,7 @@ "services": { "type": "array", "items": { - "$ref": "#/components/schemas/ServiceSpec7" + "$ref": "#/components/schemas/ServiceSpec8" }, "description": "Service instances to run alongside the database (e.g., MCP servers).", "example": [ @@ -24009,7 +26922,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, { "backup_config": { @@ -24184,7 +27098,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, { "backup_config": { @@ -24359,7 +27274,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" } ], "orchestrator_opts": { @@ -24452,187 +27368,27 @@ "type": "s3" }, "restore_options": { - "set": "20250505-153628F", - "target": "123456", - "type": "xid" - }, - "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "source_database_name": "northwind", - "source_node_name": "n1" - }, - "scripts": { - "post_database_create": [ - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" - ], - "post_init": [ - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", - "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" - ] - }, - "services": [ - { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." - }, - "connect_as": "app", - "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" - ], - "target_session_attrs": "primary" - }, - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "512M", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Incidunt in quas totam." - } - }, - "port": 0, - "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "service_type": "rag", - "version": "latest" - }, - { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." - }, - "connect_as": "app", - "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" - ], - "target_session_attrs": "primary" - }, - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "512M", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Incidunt in quas totam." - } - }, - "port": 0, - "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "service_type": "rag", - "version": "latest" + "set": "20250505-153628F", + "target": "123456", + "type": "xid" }, + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "source_database_name": "northwind", + "source_node_name": "n1" + }, + "scripts": { + "post_database_create": [ + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" + ], + "post_init": [ + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app", + "ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app" + ] + }, + "services": [ { "config": { "llm_model": "gpt-4", @@ -24801,7 +27557,7 @@ "nodes" ] }, - "DatabaseSpec8": { + "DatabaseSpec9": { "type": "object", "properties": { "backup_config": { @@ -24878,7 +27634,7 @@ "nodes": { "type": "array", "items": { - "$ref": "#/components/schemas/DatabaseNodeSpec8" + "$ref": "#/components/schemas/DatabaseNodeSpec9" }, "description": "The Spock nodes for this database.", "example": [ @@ -25054,243 +27810,84 @@ "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "source_database_name": "northwind", "source_node_name": "n1" - }, - "source_node": "n1" - } - ], - "minItems": 1, - "maxItems": 9 - }, - "orchestrator_opts": { - "$ref": "#/components/schemas/OrchestratorOpts" - }, - "patroni_port": { - "type": "integer", - "description": "The port used by Patroni for this database. If the port is 0, each instance will be assigned a random port. NOTE: This field is not currently supported for Docker Swarm.", - "example": 8888, - "format": "int64", - "minimum": 0, - "maximum": 65535 - }, - "pg_hba_conf": { - "type": "array", - "items": { - "type": "string", - "example": "Dignissimos voluptates est numquam perspiciatis et." - }, - "description": "Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these.", - "example": [ - "hostssl all myapp_user 203.0.113.0/24 scram-sha-256", - "hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users" - ] - }, - "pg_ident_conf": { - "type": "array", - "items": { - "type": "string", - "example": "Sequi saepe velit." - }, - "description": "Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames.", - "example": [ - "ssl_users CN=alice,O=example alice" - ] - }, - "port": { - "type": "integer", - "description": "The port used by the Postgres database. If the port is 0, each instance will be assigned a random port. If the port is unspecified, the database will not be exposed on any port, dependent on orchestrator support for that feature.", - "example": 5432, - "format": "int64", - "minimum": 0, - "maximum": 65535 - }, - "postgres_version": { - "type": "string", - "description": "The Postgres version in 'major.minor' format.", - "example": "17.6", - "pattern": "^\\d{2}\\.\\d{1,2}$" - }, - "postgresql_conf": { - "type": "object", - "description": "Additional postgresql.conf settings. Will be merged with the settings provided by control-plane.", - "example": { - "max_connections": 1000 - }, - "maxLength": 64, - "additionalProperties": true - }, - "restore_config": { - "$ref": "#/components/schemas/RestoreConfigSpec" - }, - "scripts": { - "$ref": "#/components/schemas/DatabaseScripts" - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ServiceSpec8" - }, - "description": "Service instances to run alongside the database (e.g., MCP servers).", - "example": [ - { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." - }, - "connect_as": "app", - "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" - ], - "target_session_attrs": "primary" - }, - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "512M", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Incidunt in quas totam." - } - }, - "port": 0, - "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "service_type": "rag", - "version": "latest" - }, - { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." - }, - "connect_as": "app", - "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" - ], - "target_session_attrs": "primary" - }, - "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "memory": "512M", - "orchestrator_opts": { - "swarm": { - "extra_labels": { - "traefik.enable": "true", - "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" - }, - "extra_networks": [ - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - }, - { - "aliases": [ - "pg-db", - "db-alias" - ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" - } - ], - "image": "Incidunt in quas totam." - } - }, - "port": 0, - "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "service_type": "rag", - "version": "latest" - }, + }, + "source_node": "n1", + "spock_version": "6" + } + ], + "minItems": 1, + "maxItems": 9 + }, + "orchestrator_opts": { + "$ref": "#/components/schemas/OrchestratorOpts" + }, + "patroni_port": { + "type": "integer", + "description": "The port used by Patroni for this database. If the port is 0, each instance will be assigned a random port. NOTE: This field is not currently supported for Docker Swarm.", + "example": 8888, + "format": "int64", + "minimum": 0, + "maximum": 65535 + }, + "pg_hba_conf": { + "type": "array", + "items": { + "type": "string", + "example": "Mollitia illo delectus." + }, + "description": "Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these.", + "example": [ + "hostssl all myapp_user 203.0.113.0/24 scram-sha-256", + "hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users" + ] + }, + "pg_ident_conf": { + "type": "array", + "items": { + "type": "string", + "example": "Aut ducimus aut aut veritatis ut." + }, + "description": "Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames.", + "example": [ + "ssl_users CN=alice,O=example alice" + ] + }, + "port": { + "type": "integer", + "description": "The port used by the Postgres database. If the port is 0, each instance will be assigned a random port. If the port is unspecified, the database will not be exposed on any port, dependent on orchestrator support for that feature.", + "example": 5432, + "format": "int64", + "minimum": 0, + "maximum": 65535 + }, + "postgres_version": { + "type": "string", + "description": "The Postgres version in 'major.minor' format.", + "example": "17.6", + "pattern": "^\\d{2}\\.\\d{1,2}$" + }, + "postgresql_conf": { + "type": "object", + "description": "Additional postgresql.conf settings. Will be merged with the settings provided by control-plane.", + "example": { + "max_connections": 1000 + }, + "maxLength": 64, + "additionalProperties": true + }, + "restore_config": { + "$ref": "#/components/schemas/RestoreConfigSpec" + }, + "scripts": { + "$ref": "#/components/schemas/DatabaseScripts" + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ServiceSpec9" + }, + "description": "Service instances to run alongside the database (e.g., MCP servers).", + "example": [ { "config": { "llm_model": "gpt-4", @@ -25521,58 +28118,234 @@ "id": "daily-full-backup", "type": "full" }, - { - "cron_expression": "0 6 * * ?", - "id": "daily-full-backup", - "type": "full" - } - ] - }, - "cpus": "500m", - "database_name": "northwind", - "database_users": [ - { - "attributes": [ - "LOGIN", - "CREATEDB", - "CREATEROLE" - ], - "db_owner": false, - "password": "secret", - "roles": [ - "pgedge_superuser" - ], - "username": "admin" - }, - { - "attributes": [ - "LOGIN", - "CREATEDB", - "CREATEROLE" + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + } + ] + }, + "cpus": "500m", + "database_name": "northwind", + "database_users": [ + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + }, + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + }, + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + } + ], + "memory": "500M", + "nodes": [ + { + "backup_config": { + "repositories": [ + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab", + "storage-upload-chunk-size": "5MiB" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "retention_full": 2, + "retention_full_type": "count", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + } + ], + "schedules": [ + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + }, + { + "cron_expression": "0 6 * * ?", + "id": "daily-full-backup", + "type": "full" + } + ] + }, + "cpus": "500m", + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "500M", + "name": "n1", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Incidunt in quas totam." + } + }, + "patroni_port": 8888, + "pg_hba_conf": [ + "host example myapp_user 10.0.0.0/8 scram-sha-256" ], - "db_owner": false, - "password": "secret", - "roles": [ - "pgedge_superuser" + "pg_ident_conf": [ + "ssl_users CN=alice,O=example alice" ], - "username": "admin" + "port": 5432, + "postgres_version": "17.6", + "postgresql_conf": { + "max_connections": 1000 + }, + "restore_config": { + "repository": { + "azure_account": "pgedge-backups", + "azure_container": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "azure_endpoint": "blob.core.usgovcloudapi.net", + "azure_key": "YXpLZXk=", + "base_path": "/backups", + "custom_options": { + "s3-kms-key-id": "1234abcd-12ab-34cd-56ef-1234567890ab" + }, + "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "gcs_endpoint": "localhost", + "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", + "s3_endpoint": "s3.us-east-1.amazonaws.com", + "s3_key": "AKIAIOSFODNN7EXAMPLE", + "s3_key_secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "s3_region": "us-east-1", + "type": "s3" + }, + "restore_options": { + "set": "20250505-153628F", + "target": "123456", + "type": "xid" + }, + "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "source_database_name": "northwind", + "source_node_name": "n1" + }, + "source_node": "n1", + "spock_version": "6" }, - { - "attributes": [ - "LOGIN", - "CREATEDB", - "CREATEROLE" - ], - "db_owner": false, - "password": "secret", - "roles": [ - "pgedge_superuser" - ], - "username": "admin" - } - ], - "memory": "500M", - "nodes": [ { "backup_config": { "repositories": [ @@ -25746,7 +28519,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" }, { "backup_config": { @@ -25921,7 +28695,8 @@ "source_database_name": "northwind", "source_node_name": "n1" }, - "source_node": "n1" + "source_node": "n1", + "spock_version": "6" } ], "orchestrator_opts": { @@ -26303,6 +29078,11 @@ "postgres_version": "17.10", "spock_version": "5" }, + { + "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", + "postgres_version": "17.10", + "spock_version": "5" + }, { "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", "postgres_version": "17.10", @@ -26338,15 +29118,15 @@ ], "port": 5432 }, - "created_at": "1984-01-30T10:40:13Z", + "created_at": "2011-12-03T04:20:14Z", "error": "failed to get patroni status: connection refused", "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", "node_name": "n1", "postgres": { - "patroni_paused": true, + "patroni_paused": false, "patroni_state": "unknown", - "pending_restart": true, + "pending_restart": false, "role": "primary", "version": "18.1" }, @@ -26363,6 +29143,11 @@ "provider_node": "n2", "status": "down" }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, { "name": "sub_n1n2", "provider_node": "n2", @@ -26371,9 +29156,9 @@ ], "version": "4.10.0" }, - "state": "modifying", - "status_updated_at": "1976-03-01T20:13:25Z", - "updated_at": "1996-05-27T17:04:41Z" + "state": "stopped", + "status_updated_at": "1998-03-14T08:14:25Z", + "updated_at": "1978-12-17T01:14:06Z" }, { "connection_info": { @@ -26383,15 +29168,65 @@ ], "port": 5432 }, - "created_at": "1984-01-30T10:40:13Z", + "created_at": "2011-12-03T04:20:14Z", "error": "failed to get patroni status: connection refused", "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", "node_name": "n1", "postgres": { - "patroni_paused": true, + "patroni_paused": false, "patroni_state": "unknown", - "pending_restart": true, + "pending_restart": false, + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + } + ], + "version": "4.10.0" + }, + "state": "stopped", + "status_updated_at": "1998-03-14T08:14:25Z", + "updated_at": "1978-12-17T01:14:06Z" + }, + { + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2011-12-03T04:20:14Z", + "error": "failed to get patroni status: connection refused", + "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", + "node_name": "n1", + "postgres": { + "patroni_paused": false, + "patroni_state": "unknown", + "pending_restart": false, "role": "primary", "version": "18.1" }, @@ -26408,6 +29243,11 @@ "provider_node": "n2", "status": "down" }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, { "name": "sub_n1n2", "provider_node": "n2", @@ -26416,16 +29256,16 @@ ], "version": "4.10.0" }, - "state": "modifying", - "status_updated_at": "1976-03-01T20:13:25Z", - "updated_at": "1996-05-27T17:04:41Z" + "state": "stopped", + "status_updated_at": "1998-03-14T08:14:25Z", + "updated_at": "1978-12-17T01:14:06Z" } ] }, "state": { "type": "string", "description": "Current state of the database.", - "example": "creating", + "example": "modifying", "enum": [ "creating", "modifying", @@ -26481,15 +29321,15 @@ ], "port": 5432 }, - "created_at": "1984-01-30T10:40:13Z", + "created_at": "2011-12-03T04:20:14Z", "error": "failed to get patroni status: connection refused", "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", "node_name": "n1", "postgres": { - "patroni_paused": true, + "patroni_paused": false, "patroni_state": "unknown", - "pending_restart": true, + "pending_restart": false, "role": "primary", "version": "18.1" }, @@ -26506,6 +29346,11 @@ "provider_node": "n2", "status": "down" }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, { "name": "sub_n1n2", "provider_node": "n2", @@ -26514,9 +29359,9 @@ ], "version": "4.10.0" }, - "state": "modifying", - "status_updated_at": "1976-03-01T20:13:25Z", - "updated_at": "1996-05-27T17:04:41Z" + "state": "stopped", + "status_updated_at": "1998-03-14T08:14:25Z", + "updated_at": "1978-12-17T01:14:06Z" }, { "connection_info": { @@ -26526,15 +29371,15 @@ ], "port": 5432 }, - "created_at": "1984-01-30T10:40:13Z", + "created_at": "2011-12-03T04:20:14Z", "error": "failed to get patroni status: connection refused", "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", "node_name": "n1", "postgres": { - "patroni_paused": true, + "patroni_paused": false, "patroni_state": "unknown", - "pending_restart": true, + "pending_restart": false, "role": "primary", "version": "18.1" }, @@ -26551,6 +29396,11 @@ "provider_node": "n2", "status": "down" }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, { "name": "sub_n1n2", "provider_node": "n2", @@ -26559,9 +29409,9 @@ ], "version": "4.10.0" }, - "state": "modifying", - "status_updated_at": "1976-03-01T20:13:25Z", - "updated_at": "1996-05-27T17:04:41Z" + "state": "stopped", + "status_updated_at": "1998-03-14T08:14:25Z", + "updated_at": "1978-12-17T01:14:06Z" }, { "connection_info": { @@ -26571,15 +29421,15 @@ ], "port": 5432 }, - "created_at": "1984-01-30T10:40:13Z", + "created_at": "2011-12-03T04:20:14Z", "error": "failed to get patroni status: connection refused", "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", "node_name": "n1", "postgres": { - "patroni_paused": true, + "patroni_paused": false, "patroni_state": "unknown", - "pending_restart": true, + "pending_restart": false, "role": "primary", "version": "18.1" }, @@ -26596,6 +29446,11 @@ "provider_node": "n2", "status": "down" }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, { "name": "sub_n1n2", "provider_node": "n2", @@ -26604,9 +29459,9 @@ ], "version": "4.10.0" }, - "state": "modifying", - "status_updated_at": "1976-03-01T20:13:25Z", - "updated_at": "1996-05-27T17:04:41Z" + "state": "stopped", + "status_updated_at": "1998-03-14T08:14:25Z", + "updated_at": "1978-12-17T01:14:06Z" }, { "connection_info": { @@ -26616,15 +29471,15 @@ ], "port": 5432 }, - "created_at": "1984-01-30T10:40:13Z", + "created_at": "2011-12-03T04:20:14Z", "error": "failed to get patroni status: connection refused", "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", "node_name": "n1", "postgres": { - "patroni_paused": true, + "patroni_paused": false, "patroni_state": "unknown", - "pending_restart": true, + "pending_restart": false, "role": "primary", "version": "18.1" }, @@ -26641,6 +29496,11 @@ "provider_node": "n2", "status": "down" }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, { "name": "sub_n1n2", "provider_node": "n2", @@ -26649,12 +29509,12 @@ ], "version": "4.10.0" }, - "state": "modifying", - "status_updated_at": "1976-03-01T20:13:25Z", - "updated_at": "1996-05-27T17:04:41Z" + "state": "stopped", + "status_updated_at": "1998-03-14T08:14:25Z", + "updated_at": "1978-12-17T01:14:06Z" } ], - "state": "available", + "state": "unknown", "tenant_id": "8210ec10-2dca-406c-ac4a-0661d2189954", "updated_at": "2025-01-01T02:30:00Z" }, @@ -26672,7 +29532,7 @@ "type": "array", "items": { "type": "string", - "example": "Autem eum et et eius at praesentium." + "example": "Eum et et eius at." }, "description": "The attributes to assign to this database user.", "example": [ @@ -26685,7 +29545,7 @@ "db_owner": { "type": "boolean", "description": "If true, this user will be granted database ownership.", - "example": false + "example": true }, "password": { "type": "string", @@ -26697,7 +29557,7 @@ "type": "array", "items": { "type": "string", - "example": "Dolorem sapiente placeat illo dolore totam accusamus." + "example": "Ut dolorem." }, "description": "The roles to assign to this database user.", "example": [ @@ -26756,7 +29616,7 @@ "type": "array", "items": { "type": "string", - "example": "Voluptates maxime hic aut omnis magnam." + "example": "Magnam aspernatur." }, "description": "The Etcd client endpoint for this cluster member.", "example": [ @@ -26772,7 +29632,7 @@ "type": "array", "items": { "type": "string", - "example": "A enim." + "example": "Maxime hic aut." }, "description": "The Etcd peer endpoint for this cluster member.", "example": [ @@ -26802,7 +29662,7 @@ "type": "array", "items": { "type": "string", - "example": "Quia non atque facilis non modi." + "example": "Ut possimus error." }, "description": "Optional network-scoped aliases for the container.", "example": [ @@ -26819,7 +29679,7 @@ }, "additionalProperties": { "type": "string", - "example": "Illum alias qui et." + "example": "Recusandae similique sed neque eos rerum." } }, "id": { @@ -26901,7 +29761,7 @@ "candidate_instance_id": "68f50878-44d2-4524-a823-e31bd478706d-n1-689qacsi", "database_id": "my-app", "node_name": "n1", - "skip_validation": false + "skip_validation": true }, "required": [ "database_id", @@ -26991,7 +29851,7 @@ "type": "array", "items": { "type": "string", - "example": "Consequuntur reprehenderit esse id labore." + "example": "Iure quisquam." }, "description": "The addresses that this host advertises to client applications.", "example": [ @@ -27046,7 +29906,7 @@ "type": "array", "items": { "type": "string", - "example": "Veritatis et omnis non." + "example": "Quibusdam quis ipsa nihil facere ad." }, "description": "The addresses that this host advertises to other hosts.", "example": [ @@ -27068,10 +29928,6 @@ "postgres_version": "17.6", "spock_version": "5" }, - { - "postgres_version": "17.6", - "spock_version": "5" - }, { "postgres_version": "17.6", "spock_version": "5" @@ -27192,7 +30048,16 @@ "type": "object", "description": "The status of each component of the host.", "example": { - "Harum voluptatum nulla commodi quo.": { + "Illo aut et corporis harum.": { + "details": { + "alarms": [ + "3: NOSPACE" + ] + }, + "error": "failed to connect to etcd", + "healthy": false + }, + "Molestiae voluptates laborum.": { "details": { "alarms": [ "3: NOSPACE" @@ -27225,7 +30090,7 @@ }, "example": { "components": { - "Eius totam dolorem itaque aut aut.": { + "Commodi quo.": { "details": { "alarms": [ "3: NOSPACE" @@ -27234,7 +30099,7 @@ "error": "failed to connect to etcd", "healthy": false }, - "Nihil facere ad tenetur iure quisquam.": { + "Facere eius totam.": { "details": { "alarms": [ "3: NOSPACE" @@ -27243,7 +30108,7 @@ "error": "failed to connect to etcd", "healthy": false }, - "Sunt quibusdam quis.": { + "Itaque aut aut cupiditate.": { "details": { "alarms": [ "3: NOSPACE" @@ -27287,7 +30152,7 @@ "created_at": { "type": "string", "description": "The time that the instance was created.", - "example": "1994-08-08T11:48:05Z", + "example": "1994-11-10T04:44:10Z", "format": "date-time" }, "error": { @@ -27334,13 +30199,13 @@ "status_updated_at": { "type": "string", "description": "The time that the instance status information was last updated.", - "example": "2006-09-13T00:37:13Z", + "example": "1994-07-03T05:16:56Z", "format": "date-time" }, "updated_at": { "type": "string", "description": "The time that the instance was last modified.", - "example": "1970-10-18T00:04:10Z", + "example": "2008-07-07T16:22:31Z", "format": "date-time" } }, @@ -27353,15 +30218,15 @@ ], "port": 5432 }, - "created_at": "1972-11-23T09:23:25Z", + "created_at": "2014-04-20T04:34:11Z", "error": "failed to get patroni status: connection refused", "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", "node_name": "n1", "postgres": { - "patroni_paused": true, + "patroni_paused": false, "patroni_state": "unknown", - "pending_restart": true, + "pending_restart": false, "role": "primary", "version": "18.1" }, @@ -27378,6 +30243,11 @@ "provider_node": "n2", "status": "down" }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, { "name": "sub_n1n2", "provider_node": "n2", @@ -27386,9 +30256,9 @@ ], "version": "4.10.0" }, - "state": "creating", - "status_updated_at": "2005-07-17T23:25:59Z", - "updated_at": "1997-05-17T16:59:26Z" + "state": "backing_up", + "status_updated_at": "2011-10-12T20:33:23Z", + "updated_at": "1994-09-09T06:25:01Z" }, "required": [ "id", @@ -27406,7 +30276,7 @@ "type": "array", "items": { "type": "string", - "example": "Eaque eos quos autem perspiciatis." + "example": "Nesciunt consequuntur reprehenderit esse id." }, "description": "The addresses of the host that's running this instance.", "example": [ @@ -27459,9 +30329,9 @@ }, "description": "Postgres status information for a pgEdge instance.", "example": { - "patroni_paused": true, + "patroni_paused": false, "patroni_state": "unknown", - "pending_restart": false, + "pending_restart": true, "role": "primary", "version": "18.1" } @@ -27486,11 +30356,6 @@ "provider_node": "n2", "status": "down" }, - { - "name": "sub_n1n2", - "provider_node": "n2", - "status": "down" - }, { "name": "sub_n1n2", "provider_node": "n2", @@ -27579,6 +30444,16 @@ "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", "type": "create" }, + { + "completed_at": "2025-06-18T16:52:35Z", + "created_at": "2025-06-18T16:52:05Z", + "database_id": "storefront", + "entity_id": "storefront", + "scope": "database", + "status": "completed", + "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", + "type": "create" + }, { "completed_at": "2025-06-18T16:52:35Z", "created_at": "2025-06-18T16:52:05Z", @@ -27664,19 +30539,119 @@ "spock_version": "5" }, { - "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", - "postgres_version": "17.10", - "spock_version": "5" + "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", + "postgres_version": "17.10", + "spock_version": "5" + }, + { + "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", + "postgres_version": "17.10", + "spock_version": "5" + } + ], + "created_at": "2025-01-01T01:30:00Z", + "id": "02f1a7db-fca8-4521-b57a-2a375c1ced51", + "instances": [ + { + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2011-12-03T04:20:14Z", + "error": "failed to get patroni status: connection refused", + "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", + "node_name": "n1", + "postgres": { + "patroni_paused": false, + "patroni_state": "unknown", + "pending_restart": false, + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + } + ], + "version": "4.10.0" + }, + "state": "stopped", + "status_updated_at": "1998-03-14T08:14:25Z", + "updated_at": "1978-12-17T01:14:06Z" + }, + { + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 + }, + "created_at": "2011-12-03T04:20:14Z", + "error": "failed to get patroni status: connection refused", + "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", + "node_name": "n1", + "postgres": { + "patroni_paused": false, + "patroni_state": "unknown", + "pending_restart": false, + "role": "primary", + "version": "18.1" + }, + "spock": { + "read_only": "off", + "subscriptions": [ + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + } + ], + "version": "4.10.0" + }, + "state": "stopped", + "status_updated_at": "1998-03-14T08:14:25Z", + "updated_at": "1978-12-17T01:14:06Z" }, - { - "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", - "postgres_version": "17.10", - "spock_version": "5" - } - ], - "created_at": "2025-01-01T01:30:00Z", - "id": "02f1a7db-fca8-4521-b57a-2a375c1ced51", - "instances": [ { "connection_info": { "addresses": [ @@ -27685,15 +30660,15 @@ ], "port": 5432 }, - "created_at": "1984-01-30T10:40:13Z", + "created_at": "2011-12-03T04:20:14Z", "error": "failed to get patroni status: connection refused", "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", "node_name": "n1", "postgres": { - "patroni_paused": true, + "patroni_paused": false, "patroni_state": "unknown", - "pending_restart": true, + "pending_restart": false, "role": "primary", "version": "18.1" }, @@ -27710,6 +30685,11 @@ "provider_node": "n2", "status": "down" }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, { "name": "sub_n1n2", "provider_node": "n2", @@ -27718,9 +30698,9 @@ ], "version": "4.10.0" }, - "state": "modifying", - "status_updated_at": "1976-03-01T20:13:25Z", - "updated_at": "1996-05-27T17:04:41Z" + "state": "stopped", + "status_updated_at": "1998-03-14T08:14:25Z", + "updated_at": "1978-12-17T01:14:06Z" }, { "connection_info": { @@ -27730,15 +30710,15 @@ ], "port": 5432 }, - "created_at": "1984-01-30T10:40:13Z", + "created_at": "2011-12-03T04:20:14Z", "error": "failed to get patroni status: connection refused", "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", "node_name": "n1", "postgres": { - "patroni_paused": true, + "patroni_paused": false, "patroni_state": "unknown", - "pending_restart": true, + "pending_restart": false, "role": "primary", "version": "18.1" }, @@ -27755,6 +30735,11 @@ "provider_node": "n2", "status": "down" }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, { "name": "sub_n1n2", "provider_node": "n2", @@ -27763,12 +30748,12 @@ ], "version": "4.10.0" }, - "state": "modifying", - "status_updated_at": "1976-03-01T20:13:25Z", - "updated_at": "1996-05-27T17:04:41Z" + "state": "stopped", + "status_updated_at": "1998-03-14T08:14:25Z", + "updated_at": "1978-12-17T01:14:06Z" } ], - "state": "backing_up", + "state": "degraded", "tenant_id": "8210ec10-2dca-406c-ac4a-0661d2189954", "updated_at": "2025-01-01T02:30:00Z" }, @@ -27806,15 +30791,15 @@ ], "port": 5432 }, - "created_at": "1984-01-30T10:40:13Z", + "created_at": "2011-12-03T04:20:14Z", "error": "failed to get patroni status: connection refused", "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", "node_name": "n1", "postgres": { - "patroni_paused": true, + "patroni_paused": false, "patroni_state": "unknown", - "pending_restart": true, + "pending_restart": false, "role": "primary", "version": "18.1" }, @@ -27831,6 +30816,11 @@ "provider_node": "n2", "status": "down" }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, { "name": "sub_n1n2", "provider_node": "n2", @@ -27839,9 +30829,9 @@ ], "version": "4.10.0" }, - "state": "modifying", - "status_updated_at": "1976-03-01T20:13:25Z", - "updated_at": "1996-05-27T17:04:41Z" + "state": "stopped", + "status_updated_at": "1998-03-14T08:14:25Z", + "updated_at": "1978-12-17T01:14:06Z" }, { "connection_info": { @@ -27851,15 +30841,15 @@ ], "port": 5432 }, - "created_at": "1984-01-30T10:40:13Z", + "created_at": "2011-12-03T04:20:14Z", "error": "failed to get patroni status: connection refused", "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", "node_name": "n1", "postgres": { - "patroni_paused": true, + "patroni_paused": false, "patroni_state": "unknown", - "pending_restart": true, + "pending_restart": false, "role": "primary", "version": "18.1" }, @@ -27876,6 +30866,11 @@ "provider_node": "n2", "status": "down" }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, { "name": "sub_n1n2", "provider_node": "n2", @@ -27884,41 +30879,10 @@ ], "version": "4.10.0" }, - "state": "modifying", - "status_updated_at": "1976-03-01T20:13:25Z", - "updated_at": "1996-05-27T17:04:41Z" - } - ], - "state": "backing_up", - "tenant_id": "8210ec10-2dca-406c-ac4a-0661d2189954", - "updated_at": "2025-01-01T02:30:00Z" - }, - { - "available_upgrades": [ - { - "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", - "postgres_version": "17.10", - "spock_version": "5" - }, - { - "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", - "postgres_version": "17.10", - "spock_version": "5" - }, - { - "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", - "postgres_version": "17.10", - "spock_version": "5" + "state": "stopped", + "status_updated_at": "1998-03-14T08:14:25Z", + "updated_at": "1978-12-17T01:14:06Z" }, - { - "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1", - "postgres_version": "17.10", - "spock_version": "5" - } - ], - "created_at": "2025-01-01T01:30:00Z", - "id": "02f1a7db-fca8-4521-b57a-2a375c1ced51", - "instances": [ { "connection_info": { "addresses": [ @@ -27927,15 +30891,15 @@ ], "port": 5432 }, - "created_at": "1984-01-30T10:40:13Z", + "created_at": "2011-12-03T04:20:14Z", "error": "failed to get patroni status: connection refused", "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", "node_name": "n1", "postgres": { - "patroni_paused": true, + "patroni_paused": false, "patroni_state": "unknown", - "pending_restart": true, + "pending_restart": false, "role": "primary", "version": "18.1" }, @@ -27952,6 +30916,11 @@ "provider_node": "n2", "status": "down" }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, { "name": "sub_n1n2", "provider_node": "n2", @@ -27960,9 +30929,9 @@ ], "version": "4.10.0" }, - "state": "modifying", - "status_updated_at": "1976-03-01T20:13:25Z", - "updated_at": "1996-05-27T17:04:41Z" + "state": "stopped", + "status_updated_at": "1998-03-14T08:14:25Z", + "updated_at": "1978-12-17T01:14:06Z" }, { "connection_info": { @@ -27972,15 +30941,15 @@ ], "port": 5432 }, - "created_at": "1984-01-30T10:40:13Z", + "created_at": "2011-12-03T04:20:14Z", "error": "failed to get patroni status: connection refused", "host_id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", "id": "a67cbb36-c3c3-49c9-8aac-f4a0438a883d", "node_name": "n1", "postgres": { - "patroni_paused": true, + "patroni_paused": false, "patroni_state": "unknown", - "pending_restart": true, + "pending_restart": false, "role": "primary", "version": "18.1" }, @@ -27997,6 +30966,11 @@ "provider_node": "n2", "status": "down" }, + { + "name": "sub_n1n2", + "provider_node": "n2", + "status": "down" + }, { "name": "sub_n1n2", "provider_node": "n2", @@ -28005,12 +30979,12 @@ ], "version": "4.10.0" }, - "state": "modifying", - "status_updated_at": "1976-03-01T20:13:25Z", - "updated_at": "1996-05-27T17:04:41Z" + "state": "stopped", + "status_updated_at": "1998-03-14T08:14:25Z", + "updated_at": "1978-12-17T01:14:06Z" } ], - "state": "backing_up", + "state": "degraded", "tenant_id": "8210ec10-2dca-406c-ac4a-0661d2189954", "updated_at": "2025-01-01T02:30:00Z" } @@ -28283,47 +31257,130 @@ "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", "type": "create" }, - { - "completed_at": "2025-06-18T16:52:35Z", - "created_at": "2025-06-18T16:52:05Z", - "database_id": "storefront", - "entity_id": "storefront", - "scope": "database", - "status": "completed", - "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", - "type": "create" - } - ] - } - }, - "example": { - "tasks": [ - { - "completed_at": "2025-06-18T17:54:36Z", - "created_at": "2025-06-18T17:54:28Z", - "entity_id": "host-1", - "host_id": "host-1", - "scope": "host", - "status": "completed", - "task_id": "0197842d-9082-7496-b787-77bd2e11809f", - "type": "remove_host" - } - ] - }, - "required": [ - "tasks" - ] - }, - "ListHostsResponse": { - "type": "object", - "properties": { - "hosts": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Host" - }, - "description": "List of hosts in the cluster", - "example": [ + { + "completed_at": "2025-06-18T16:52:35Z", + "created_at": "2025-06-18T16:52:05Z", + "database_id": "storefront", + "entity_id": "storefront", + "scope": "database", + "status": "completed", + "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", + "type": "create" + }, + { + "completed_at": "2025-06-18T16:52:35Z", + "created_at": "2025-06-18T16:52:05Z", + "database_id": "storefront", + "entity_id": "storefront", + "scope": "database", + "status": "completed", + "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", + "type": "create" + }, + { + "completed_at": "2025-06-18T16:52:35Z", + "created_at": "2025-06-18T16:52:05Z", + "database_id": "storefront", + "entity_id": "storefront", + "scope": "database", + "status": "completed", + "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", + "type": "create" + } + ] + } + }, + "example": { + "tasks": [ + { + "completed_at": "2025-06-18T17:54:36Z", + "created_at": "2025-06-18T17:54:28Z", + "entity_id": "host-1", + "host_id": "host-1", + "scope": "host", + "status": "completed", + "task_id": "0197842d-9082-7496-b787-77bd2e11809f", + "type": "remove_host" + } + ] + }, + "required": [ + "tasks" + ] + }, + "ListHostsResponse": { + "type": "object", + "properties": { + "hosts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Host" + }, + "description": "List of hosts in the cluster", + "example": [ + { + "client_addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "cohort": { + "control_available": true, + "member_id": "lah4bsznw6kc0hp7biylmmmll", + "type": "swarm" + }, + "cpus": 4, + "data_dir": "/data", + "default_pgedge_version": { + "postgres_version": "17.6", + "spock_version": "5" + }, + "etcd_mode": "server", + "id": "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "memory": "16GiB", + "orchestrator": "swarm", + "peer_addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "status": { + "components": { + "Enim et voluptatum ex ea dolore.": { + "details": { + "alarms": [ + "3: NOSPACE" + ] + }, + "error": "failed to connect to etcd", + "healthy": false + }, + "Tenetur nostrum repellendus sint qui.": { + "details": { + "alarms": [ + "3: NOSPACE" + ] + }, + "error": "failed to connect to etcd", + "healthy": false + } + }, + "state": "available", + "updated_at": "2021-07-01T12:34:56Z" + }, + "supported_pgedge_versions": [ + { + "postgres_version": "17.6", + "spock_version": "5" + }, + { + "postgres_version": "17.6", + "spock_version": "5" + }, + { + "postgres_version": "17.6", + "spock_version": "5" + } + ] + }, { "client_addresses": [ "10.24.34.2", @@ -28773,7 +31830,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Animi recusandae." + "image": "Sapiente qui ullam." } } }, @@ -28913,6 +31970,16 @@ "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", "type": "create" }, + { + "completed_at": "2025-06-18T16:52:35Z", + "created_at": "2025-06-18T16:52:05Z", + "database_id": "storefront", + "entity_id": "storefront", + "scope": "database", + "status": "completed", + "task_id": "019783f4-75f4-71e7-85a3-c9b96b345d77", + "type": "create" + }, { "completed_at": "2025-06-18T16:52:35Z", "created_at": "2025-06-18T16:52:05Z", @@ -28971,7 +32038,7 @@ "maxLength": 32, "additionalProperties": { "type": "string", - "example": "Eos aut dignissimos cum voluptate modi consequatur." + "example": "Minus dolore eos et sunt culpa animi." } }, "source_database_id": { @@ -29042,7 +32109,7 @@ "type": "array", "items": { "type": "string", - "example": "Error eligendi recusandae similique sed neque eos." + "example": "Modi consequatur non at." }, "description": "The nodes to restore. Defaults to all nodes if empty or unspecified.", "example": [ @@ -29311,7 +32378,7 @@ "type": "object", "properties": { "database": { - "$ref": "#/components/schemas/Database6" + "$ref": "#/components/schemas/Database7" }, "node_tasks": { "type": "array", @@ -29609,7 +32676,7 @@ }, "additionalProperties": { "type": "string", - "example": "Dolor quam aliquid cupiditate." + "example": "Rem culpa." } }, "gcs_bucket": { @@ -29713,7 +32780,7 @@ "type": "array", "items": { "type": "string", - "example": "n", + "example": "ol", "minLength": 1, "maxLength": 1024 }, @@ -29811,11 +32878,6 @@ "host_port": 8080, "name": "web-client" }, - { - "container_port": 8080, - "host_port": 8080, - "name": "web-client" - }, { "container_port": 8080, "host_port": 8080, @@ -29843,7 +32905,7 @@ "type": "array", "items": { "type": "string", - "example": "Dignissimos occaecati cupiditate." + "example": "Quia laborum tenetur nesciunt et quas." }, "description": "The addresses of the host that's running this service instance.", "example": [ @@ -29887,11 +32949,6 @@ "host_port": 8080, "name": "web-client" }, - { - "container_port": 8080, - "host_port": 8080, - "name": "web-client" - }, { "container_port": 8080, "host_port": 8080, @@ -29925,6 +32982,11 @@ "host_port": 8080, "name": "web-client" }, + { + "container_port": 8080, + "host_port": 8080, + "name": "web-client" + }, { "container_port": 8080, "host_port": 8080, @@ -29972,6 +33034,8 @@ }, "description": "The IDs of the hosts that should run this service. One service instance will be created per host.", "example": [ + "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "de3b1388-1f0c-42f1-a86c-59ab72f255ec", "de3b1388-1f0c-42f1-a86c-59ab72f255ec" ], "minItems": 1 @@ -30033,7 +33097,6 @@ "target_session_attrs": "primary" }, "host_ids": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec", "de3b1388-1f0c-42f1-a86c-59ab72f255ec" ], "memory": "512M", @@ -30089,7 +33152,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Animi recusandae." + "image": "Sapiente qui ullam." } }, "port": 0, @@ -30142,6 +33205,7 @@ }, "description": "The IDs of the hosts that should run this service. One service instance will be created per host.", "example": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "minItems": 1 @@ -30203,7 +33267,6 @@ "target_session_attrs": "primary" }, "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], @@ -30374,6 +33437,7 @@ "target_session_attrs": "primary" }, "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], @@ -30654,6 +33718,7 @@ }, "description": "The IDs of the hosts that should run this service. One service instance will be created per host.", "example": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], @@ -30825,7 +33890,6 @@ }, "description": "The IDs of the hosts that should run this service. One service instance will be created per host.", "example": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "minItems": 1 @@ -30961,6 +34025,175 @@ ] }, "ServiceSpec7": { + "type": "object", + "properties": { + "config": { + "type": "object", + "description": "Service-specific configuration. For MCP services, this includes llm_provider, llm_model, and provider-specific API keys.", + "example": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "additionalProperties": true + }, + "connect_as": { + "type": "string", + "description": "Username of the database_users entry this service connects as. The user must exist in database_users and have appropriate roles for the service's needs.", + "example": "app" + }, + "cpus": { + "type": "string", + "description": "The number of CPUs to allocate for this service. It can include the SI suffix 'm', e.g. '500m' for 500 millicpus. Defaults to container defaults if unspecified.", + "example": "500m", + "pattern": "^[0-9]+(\\.[0-9]{1,3}|m)?$" + }, + "database_connection": { + "$ref": "#/components/schemas/DatabaseConnection" + }, + "host_ids": { + "type": "array", + "items": { + "type": "string", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 + }, + "description": "The IDs of the hosts that should run this service. One service instance will be created per host.", + "example": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "minItems": 1 + }, + "memory": { + "type": "string", + "description": "The amount of memory in SI or IEC notation to allocate for this service. Defaults to container defaults if unspecified.", + "example": "512M", + "maxLength": 16 + }, + "orchestrator_opts": { + "$ref": "#/components/schemas/OrchestratorOpts" + }, + "port": { + "type": "integer", + "description": "The port to publish the service on the host. If 0, Docker assigns a random port. If unspecified, no port is published and the service is not accessible from outside the Docker network.", + "example": 0, + "format": "int64", + "minimum": 0, + "maximum": 65535 + }, + "service_id": { + "type": "string", + "description": "The unique identifier for this service.", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 + }, + "service_type": { + "type": "string", + "description": "The type of service to run.", + "example": "rag", + "enum": [ + "mcp", + "postgrest", + "rag" + ] + }, + "version": { + "type": "string", + "description": "The version of the service (e.g., '1.0.0', '14.5') or the literal 'latest'.", + "example": "latest", + "pattern": "^(\\d+\\.\\d+(\\.\\d+)?|latest)$" + } + }, + "example": { + "config": { + "llm_model": "gpt-4", + "llm_provider": "openai", + "openai_api_key": "sk-..." + }, + "connect_as": "app", + "cpus": "500m", + "database_connection": { + "target_nodes": [ + "n1", + "n2" + ], + "target_session_attrs": "primary" + }, + "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696" + ], + "memory": "512M", + "orchestrator_opts": { + "swarm": { + "extra_labels": { + "traefik.enable": "true", + "traefik.tcp.routers.mydb.rule": "HostSNI(`mydb.example.com`)" + }, + "extra_networks": [ + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + }, + { + "aliases": [ + "pg-db", + "db-alias" + ], + "driver_opts": { + "com.docker.network.endpoint.expose": "true" + }, + "id": "traefik-public" + } + ], + "extra_volumes": [ + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + }, + { + "destination_path": "/backups/container", + "host_path": "/Users/user/backups/host" + } + ], + "image": "Incidunt in quas totam." + } + }, + "port": 0, + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "service_type": "rag", + "version": "latest" + }, + "required": [ + "service_id", + "service_type", + "version", + "host_ids", + "connect_as" + ] + }, + "ServiceSpec8": { "type": "object", "properties": { "config": { @@ -30997,6 +34230,7 @@ }, "description": "The IDs of the hosts that should run this service. One service instance will be created per host.", "example": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], @@ -31132,7 +34366,7 @@ "connect_as" ] }, - "ServiceSpec8": { + "ServiceSpec9": { "type": "object", "properties": { "config": { @@ -31169,6 +34403,7 @@ }, "description": "The IDs of the hosts that should run this service. One service instance will be created per host.", "example": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], @@ -31231,7 +34466,6 @@ "target_session_attrs": "primary" }, "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], @@ -31364,7 +34598,7 @@ }, "additionalProperties": { "type": "string", - "example": "Veritatis quo recusandae quibusdam fuga." + "example": "Facilis non modi explicabo illum." } }, "extra_networks": { @@ -31432,7 +34666,7 @@ "image": { "type": "string", "description": "User-specified container image override. Bypasses manifest version constraints entirely — the CP will deploy this image without validating it against the version manifest. The CP verifies the image exists in its registry before accepting the spec. Clearing this field causes the CP to fall back to the manifest-resolved image on the next reconcile.", - "example": "Repellat quas nostrum eos." + "example": "Qui et eius reiciendis accusamus." } }, "description": "Docker Swarm-specific options.", @@ -31487,7 +34721,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Qui ullam qui quam sint iure eum." + "image": "Quibusdam fuga molestiae repellat quas nostrum." } }, "SwitchoverDatabaseNodeRequest": { @@ -31704,14 +34938,6 @@ "message": "task started", "timestamp": "2025-05-29T15:43:13Z" }, - { - "fields": { - "option.enabled": true, - "status": "creating" - }, - "message": "task started", - "timestamp": "2025-05-29T15:43:13Z" - }, { "fields": { "option.enabled": true, diff --git a/api/apiv1/gen/http/openapi3.yaml b/api/apiv1/gen/http/openapi3.yaml index efa04d9a..bd057ebe 100644 --- a/api/apiv1/gen/http/openapi3.yaml +++ b/api/apiv1/gen/http/openapi3.yaml @@ -345,7 +345,7 @@ paths: type: array items: type: string - example: Tempora laboriosam aut. + example: Qui dolores quibusdam. description: 'Optional fields to include in each database response. Supported values: available_upgrades.' example: - available_upgrades @@ -972,7 +972,7 @@ paths: type: array items: type: string - example: Est dolor consequatur. + example: Repellat recusandae sequi. description: 'Optional fields to include in the response. Supported values: available_upgrades.' example: - available_upgrades @@ -1171,17 +1171,16 @@ paths: type: array items: type: string - example: Illo delectus dolorum. + example: Aspernatur libero nihil sunt ut dicta. description: Host IDs to treat as removed during this update. Events targeting these hosts will be skipped. example: - - Aut aut veritatis ut nulla. - - Earum distinctio qui qui dolores quibusdam officiis. - - Recusandae sequi vel aspernatur libero nihil sunt. + - Maiores minima. + - Qui sit. + - Autem explicabo nemo et architecto qui. example: - - Quasi quo maiores minima velit. - - Sit rerum autem explicabo nemo et architecto. - - In cum enim est. - - Repudiandae in quis eum. + - Enim est enim repudiandae in. + - Eum quasi aspernatur cum quod sed id. + - Rerum quo autem facere incidunt asperiores. - name: database_id in: path description: ID of the database to update. @@ -2889,6 +2888,205 @@ paths: example: message: A longer description of the error. name: error_name + /v1/databases/{database_id}/upgrade-major: + post: + tags: + - Database + summary: Apply Spock major-version upgrade + description: Applies a dedicated Spock major-version upgrade (e.g. 5.x to 6.x) to a database, rolling through each node one at a time rather than redeploying uniformly. Independent of apply-upgrade, which is restricted to same-major minor/patch bumps and cannot reach a different Spock major. + operationId: apply-major-upgrade + parameters: + - name: database_id + in: path + description: ID of the database to upgrade. + required: true + schema: + type: string + description: A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens. + example: 76f9b8c0-4958-11f0-a489-3bb29577c696 + minLength: 1 + maxLength: 36 + example: my-app + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ApplyMajorUpgradeRequest' + example: + image: ghcr.io/pgedge/pgedge-postgres:18.4-spock6.0.0-standard-1 + node_order: + - n2 + - n1 + - n3 + target_spock_version: "6" + responses: + "200": + description: OK response. + content: + application/json: + schema: + $ref: '#/components/schemas/ApplyMajorUpgradeResponse2' + example: + database: + created_at: "2025-06-18T16:52:05Z" + id: storefront + instances: + - connection_info: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + port: 5432 + created_at: "2025-06-18T16:52:22Z" + host_id: us-east-1 + id: storefront-n1-689qacsi + node_name: n1 + postgres: + patroni_state: running + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n1n3 + provider_node: n3 + status: replicating + - name: sub_n1n2 + provider_node: n2 + status: replicating + version: 4.0.10 + state: available + status_updated_at: "2025-06-18T17:58:56Z" + updated_at: "2025-06-18T17:54:36Z" + - connection_info: + addresses: + - 10.24.35.2 + - i-058731542fee493f.ec2.internal + port: 5432 + created_at: "2025-06-18T16:52:22Z" + host_id: ap-south-1 + id: storefront-n2-9ptayhma + node_name: n2 + postgres: + patroni_state: running + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n2n1 + provider_node: n1 + status: replicating + - name: sub_n2n3 + provider_node: n3 + status: replicating + version: 4.0.10 + state: available + status_updated_at: "2025-06-18T17:58:56Z" + updated_at: "2025-06-18T17:54:01Z" + - connection_info: + addresses: + - 10.24.36.2 + - i-494027b7b53f6a23.ec2.internal + port: 5432 + created_at: "2025-06-18T16:52:22Z" + host_id: eu-central-1 + id: storefront-n3-ant97dj4 + node_name: n3 + postgres: + patroni_state: running + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n3n1 + provider_node: n1 + status: replicating + - name: sub_n3n2 + provider_node: n2 + status: replicating + version: 4.0.10 + state: available + status_updated_at: "2025-06-18T17:58:56Z" + updated_at: "2025-06-18T17:54:01Z" + spec: + database_name: storefront + database_users: + - attributes: + - SUPERUSER + - LOGIN + db_owner: true + username: admin + nodes: + - host_ids: + - us-east-1 + name: n1 + - host_ids: + - ap-south-1 + name: n2 + - host_ids: + - eu-central-1 + name: n3 + port: 5432 + postgres_version: "17.6" + spock_version: "5" + state: restoring + updated_at: "2025-06-18T17:58:59Z" + task: + completed_at: "2025-06-18T16:52:35Z" + created_at: "2025-06-18T16:52:05Z" + database_id: storefront + entity_id: storefront + scope: database + status: completed + task_id: 019783f4-75f4-71e7-85a3-c9b96b345d77 + type: create + "400": + description: 'invalid_input: Bad Request response.' + content: + application/json: + schema: + $ref: '#/components/schemas/APIError' + example: + message: A longer description of the error. + name: error_name + "404": + description: 'not_found: Not Found response.' + content: + application/json: + schema: + $ref: '#/components/schemas/APIError' + example: + message: A longer description of the error. + name: error_name + "409": + description: 'operation_already_in_progress: Conflict response.' + content: + application/json: + schema: + $ref: '#/components/schemas/APIError' + example: + message: A longer description of the error. + name: error_name + "500": + description: 'server_error: Internal Server Error response.' + content: + application/json: + schema: + $ref: '#/components/schemas/APIError' + example: + message: A longer description of the error. + name: error_name + default: + description: Unexpected error response + content: + application/json: + schema: + $ref: '#/components/schemas/APIError' + example: + message: A longer description of the error. + name: error_name /v1/hosts: get: tags: @@ -3832,19 +4030,41 @@ components: required: - name - message - ApplyUpgradeRequest: + ApplyMajorUpgradeRequest: type: object properties: image: type: string - description: Full container image reference of the upgrade target. Must match the image field of a stable manifest entry in the same Postgres major / Spock major bucket as the current version and be strictly newer. - example: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.8-standard-1 + description: Full container image reference of the upgrade target. Must match the image field of a manifest entry whose spock_version is target_spock_version and whose postgres_version matches the database's current postgres_version. Unlike ApplyUpgradeRequest, the target entry is not required to have stability "stable" — a Spock major version is expected to still be in a "dev" stability window while this action is in use for it. + example: ghcr.io/pgedge/pgedge-postgres:18.4-spock6.0.0-standard-1 minLength: 1 + node_order: + type: array + items: + type: string + example: Sapiente eos aut. + description: Explicit order (by node name) in which nodes are upgraded, one at a time. Defaults to the order nodes appear in the database spec if omitted. Every node in the database must appear exactly once. + example: + - n2 + - n1 + - n3 + target_spock_version: + type: string + description: The Spock major version to upgrade to. + example: "6" + pattern: ^\d{1}$ + description: 'Request to upgrade a database across a Spock major version boundary (e.g. 5.x to 6.x). Deliberately separate from ApplyUpgradeRequest: a major-version bump changes replication protocol behavior and is executed one node at a time (rolling), not redeployed uniformly like a minor/patch bump.' example: - image: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.8-standard-1 + image: ghcr.io/pgedge/pgedge-postgres:18.4-spock6.0.0-standard-1 + node_order: + - n2 + - n1 + - n3 + target_spock_version: "6" required: + - target_spock_version - image - ApplyUpgradeResponse: + ApplyMajorUpgradeResponse: type: object properties: database: @@ -3855,276 +4075,558 @@ components: database: created_at: "2025-06-18T16:52:05Z" id: storefront - state: modifying - updated_at: "2025-06-18T17:58:59Z" - task: - created_at: "2025-06-18T17:58:59Z" - database_id: storefront - status: pending - task_id: 01978431-b628-758a-aec6-03b331fa1a17 - type: upgrade - required: - - task - - database - ApplyUpgradeResponse2: - type: object - properties: - database: - $ref: '#/components/schemas/Database5' - task: - $ref: '#/components/schemas/Task' - example: - database: - created_at: "2025-06-18T16:52:05Z" - id: storefront - state: modifying - updated_at: "2025-06-18T17:58:59Z" - task: - created_at: "2025-06-18T17:58:59Z" - database_id: storefront - status: pending - task_id: 01978431-b628-758a-aec6-03b331fa1a17 - type: upgrade - required: - - task - - database - AvailableUpgrade: - type: object - properties: - image: - type: string - description: Full container image reference for the upgrade candidate. - example: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1 - postgres_version: - type: string - description: Postgres version of the upgrade candidate. - example: "17.10" - spock_version: - type: string - description: Spock major version of the upgrade candidate. - example: "5" - description: A newer stable image available for the database in the same Postgres major / Spock major bucket. - example: - image: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1 - postgres_version: "17.10" - spock_version: "5" - required: - - postgres_version - - spock_version - - image - BackupConfigSpec: - type: object - properties: - repositories: - type: array - items: - $ref: '#/components/schemas/BackupRepositorySpec' - description: The repositories for this backup configuration. - example: - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: f6b84a99-5e91-4203-be1e-131fe82e5984 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - minItems: 1 - schedules: - type: array - items: - $ref: '#/components/schemas/BackupScheduleSpec' - description: The schedules for this backup configuration. - example: - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - maxItems: 32 - example: - repositories: - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: f6b84a99-5e91-4203-be1e-131fe82e5984 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: f6b84a99-5e91-4203-be1e-131fe82e5984 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - schedules: - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - required: - - repositories - BackupDatabaseNodeResponse: - type: object - properties: - task: - $ref: '#/components/schemas/Task' - example: + instances: + - connection_info: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + port: 5432 + created_at: "2025-06-18T16:52:22Z" + host_id: us-east-1 + id: storefront-n1-689qacsi + node_name: n1 + postgres: + patroni_state: running + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n1n3 + provider_node: n3 + status: replicating + - name: sub_n1n2 + provider_node: n2 + status: replicating + version: 4.0.10 + state: available + status_updated_at: "2025-06-18T17:58:56Z" + updated_at: "2025-06-18T17:54:36Z" + - connection_info: + addresses: + - 10.24.35.2 + - i-058731542fee493f.ec2.internal + port: 5432 + created_at: "2025-06-18T16:52:22Z" + host_id: ap-south-1 + id: storefront-n2-9ptayhma + node_name: n2 + postgres: + patroni_state: running + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n2n1 + provider_node: n1 + status: replicating + - name: sub_n2n3 + provider_node: n3 + status: replicating + version: 4.0.10 + state: available + status_updated_at: "2025-06-18T17:58:56Z" + updated_at: "2025-06-18T17:54:01Z" + - connection_info: + addresses: + - 10.24.36.2 + - i-494027b7b53f6a23.ec2.internal + port: 5432 + created_at: "2025-06-18T16:52:22Z" + host_id: eu-central-1 + id: storefront-n3-ant97dj4 + node_name: n3 + postgres: + patroni_state: running + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n3n1 + provider_node: n1 + status: replicating + - name: sub_n3n2 + provider_node: n2 + status: replicating + version: 4.0.10 + state: available + status_updated_at: "2025-06-18T17:58:56Z" + updated_at: "2025-06-18T17:54:01Z" + spec: + database_name: storefront + database_users: + - attributes: + - SUPERUSER + - LOGIN + db_owner: true + username: admin + nodes: + - host_ids: + - us-east-1 + name: n1 + - host_ids: + - ap-south-1 + name: n2 + - host_ids: + - eu-central-1 + name: n3 + port: 5432 + postgres_version: "17.6" + spock_version: "5" + state: restoring + updated_at: "2025-06-18T17:58:59Z" task: - created_at: "2025-06-18T17:54:28Z" + completed_at: "2025-06-18T16:52:35Z" + created_at: "2025-06-18T16:52:05Z" database_id: storefront - status: pending - task_id: 0197842d-9082-7496-b787-77bd2e11809f - type: node_backup + entity_id: storefront + scope: database + status: completed + task_id: 019783f4-75f4-71e7-85a3-c9b96b345d77 + type: create required: - task - BackupOptions: + - database + ApplyMajorUpgradeResponse2: type: object properties: - annotations: - type: object - description: Annotations for the backup. - example: - key: value - additionalProperties: - type: string - example: Natus qui veniam exercitationem placeat temporibus. - backup_options: - type: object - description: Options for the backup. - example: - archive-check: "n" - additionalProperties: - type: string - example: Facilis repudiandae ab sed exercitationem. - type: - type: string - description: The type of backup. - example: full - enum: - - full - - diff - - incr + database: + $ref: '#/components/schemas/Database6' + task: + $ref: '#/components/schemas/Task' example: - annotations: - initiated-by: backup-cron-job - backup_options: - archive-check: "n" - type: full + database: + created_at: "2025-06-18T16:52:05Z" + id: storefront + instances: + - connection_info: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + port: 5432 + created_at: "2025-06-18T16:52:22Z" + host_id: us-east-1 + id: storefront-n1-689qacsi + node_name: n1 + postgres: + patroni_state: running + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n1n3 + provider_node: n3 + status: replicating + - name: sub_n1n2 + provider_node: n2 + status: replicating + version: 4.0.10 + state: available + status_updated_at: "2025-06-18T17:58:56Z" + updated_at: "2025-06-18T17:54:36Z" + - connection_info: + addresses: + - 10.24.35.2 + - i-058731542fee493f.ec2.internal + port: 5432 + created_at: "2025-06-18T16:52:22Z" + host_id: ap-south-1 + id: storefront-n2-9ptayhma + node_name: n2 + postgres: + patroni_state: running + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n2n1 + provider_node: n1 + status: replicating + - name: sub_n2n3 + provider_node: n3 + status: replicating + version: 4.0.10 + state: available + status_updated_at: "2025-06-18T17:58:56Z" + updated_at: "2025-06-18T17:54:01Z" + - connection_info: + addresses: + - 10.24.36.2 + - i-494027b7b53f6a23.ec2.internal + port: 5432 + created_at: "2025-06-18T16:52:22Z" + host_id: eu-central-1 + id: storefront-n3-ant97dj4 + node_name: n3 + postgres: + patroni_state: running + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n3n1 + provider_node: n1 + status: replicating + - name: sub_n3n2 + provider_node: n2 + status: replicating + version: 4.0.10 + state: available + status_updated_at: "2025-06-18T17:58:56Z" + updated_at: "2025-06-18T17:54:01Z" + spec: + database_name: storefront + database_users: + - attributes: + - SUPERUSER + - LOGIN + db_owner: true + username: admin + nodes: + - host_ids: + - us-east-1 + name: n1 + - host_ids: + - ap-south-1 + name: n2 + - host_ids: + - eu-central-1 + name: n3 + port: 5432 + postgres_version: "17.6" + spock_version: "5" + state: restoring + updated_at: "2025-06-18T17:58:59Z" + task: + completed_at: "2025-06-18T16:52:35Z" + created_at: "2025-06-18T16:52:05Z" + database_id: storefront + entity_id: storefront + scope: database + status: completed + task_id: 019783f4-75f4-71e7-85a3-c9b96b345d77 + type: create required: - - type - BackupRepositorySpec: + - task + - database + ApplyUpgradeRequest: type: object properties: - azure_account: - type: string - description: The Azure account name for this repository. Only applies when type = 'azure'. - example: pgedge-backups - minLength: 3 - maxLength: 24 - azure_container: + image: type: string - description: The Azure container name for this repository. Only applies when type = 'azure'. - example: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - minLength: 3 - maxLength: 63 - azure_endpoint: + description: Full container image reference of the upgrade target. Must match the image field of a stable manifest entry in the same Postgres major / Spock major bucket as the current version and be strictly newer. + example: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.8-standard-1 + minLength: 1 + example: + image: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.8-standard-1 + required: + - image + ApplyUpgradeResponse: + type: object + properties: + database: + $ref: '#/components/schemas/Database' + task: + $ref: '#/components/schemas/Task' + example: + database: + created_at: "2025-06-18T16:52:05Z" + id: storefront + state: modifying + updated_at: "2025-06-18T17:58:59Z" + task: + created_at: "2025-06-18T17:58:59Z" + database_id: storefront + status: pending + task_id: 01978431-b628-758a-aec6-03b331fa1a17 + type: upgrade + required: + - task + - database + ApplyUpgradeResponse2: + type: object + properties: + database: + $ref: '#/components/schemas/Database5' + task: + $ref: '#/components/schemas/Task' + example: + database: + created_at: "2025-06-18T16:52:05Z" + id: storefront + state: modifying + updated_at: "2025-06-18T17:58:59Z" + task: + created_at: "2025-06-18T17:58:59Z" + database_id: storefront + status: pending + task_id: 01978431-b628-758a-aec6-03b331fa1a17 + type: upgrade + required: + - task + - database + AvailableUpgrade: + type: object + properties: + image: type: string - description: The optional Azure endpoint for this repository. Only applies when type = 'azure'. - example: blob.core.usgovcloudapi.net - minLength: 3 - maxLength: 128 - azure_key: + description: Full container image reference for the upgrade candidate. + example: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1 + postgres_version: type: string - description: The Azure storage account access key to use for this repository. This field will be excluded from the response of all endpoints. It can also be omitted from update requests to keep the current value. - example: YXpLZXk= - maxLength: 128 - base_path: + description: Postgres version of the upgrade candidate. + example: "17.10" + spock_version: type: string - description: The base path within the repository to store backups. Required for type = 'posix' and 'cifs'. - example: /backups - maxLength: 256 - custom_options: - type: object - description: Additional options to apply to this repository. + description: Spock major version of the upgrade candidate. + example: "5" + description: A newer stable image available for the database in the same Postgres major / Spock major bucket. + example: + image: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1 + postgres_version: "17.10" + spock_version: "5" + required: + - postgres_version + - spock_version + - image + BackupConfigSpec: + type: object + properties: + repositories: + type: array + items: + $ref: '#/components/schemas/BackupRepositorySpec' + description: The repositories for this backup configuration. example: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - additionalProperties: - type: string - example: Aut doloribus rem culpa ullam minus dolore. - gcs_bucket: - type: string - description: The GCS bucket name for this repository. Only applies when type = 'gcs'. - example: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - minLength: 3 - maxLength: 63 - gcs_endpoint: - type: string - description: The optional GCS endpoint for this repository. Only applies when type = 'gcs'. - example: localhost - minLength: 3 - maxLength: 128 - gcs_key: - type: string - description: Optional base64-encoded private key data. If omitted, pgbackrest will use the service account attached to the instance profile. This field will be excluded from the response of all endpoints. It can also be omitted from update requests to keep the current value. - example: ZXhhbXBsZSBnY3Mga2V5Cg== - maxLength: 1024 - id: - type: string - description: A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens. - example: 76f9b8c0-4958-11f0-a489-3bb29577c696 - minLength: 1 - maxLength: 36 - retention_full: + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: f6b84a99-5e91-4203-be1e-131fe82e5984 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: f6b84a99-5e91-4203-be1e-131fe82e5984 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + minItems: 1 + schedules: + type: array + items: + $ref: '#/components/schemas/BackupScheduleSpec' + description: The schedules for this backup configuration. + example: + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + maxItems: 32 + example: + repositories: + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: f6b84a99-5e91-4203-be1e-131fe82e5984 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: f6b84a99-5e91-4203-be1e-131fe82e5984 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + schedules: + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + required: + - repositories + BackupDatabaseNodeResponse: + type: object + properties: + task: + $ref: '#/components/schemas/Task' + example: + task: + created_at: "2025-06-18T17:54:28Z" + database_id: storefront + status: pending + task_id: 0197842d-9082-7496-b787-77bd2e11809f + type: node_backup + required: + - task + BackupOptions: + type: object + properties: + annotations: + type: object + description: Annotations for the backup. + example: + key: value + additionalProperties: + type: string + example: Temporibus aut. + backup_options: + type: object + description: Options for the backup. + example: + archive-check: "n" + additionalProperties: + type: string + example: Repudiandae ab sed. + type: + type: string + description: The type of backup. + example: full + enum: + - full + - diff + - incr + example: + annotations: + initiated-by: backup-cron-job + backup_options: + archive-check: "n" + type: full + required: + - type + BackupRepositorySpec: + type: object + properties: + azure_account: + type: string + description: The Azure account name for this repository. Only applies when type = 'azure'. + example: pgedge-backups + minLength: 3 + maxLength: 24 + azure_container: + type: string + description: The Azure container name for this repository. Only applies when type = 'azure'. + example: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + minLength: 3 + maxLength: 63 + azure_endpoint: + type: string + description: The optional Azure endpoint for this repository. Only applies when type = 'azure'. + example: blob.core.usgovcloudapi.net + minLength: 3 + maxLength: 128 + azure_key: + type: string + description: The Azure storage account access key to use for this repository. This field will be excluded from the response of all endpoints. It can also be omitted from update requests to keep the current value. + example: YXpLZXk= + maxLength: 128 + base_path: + type: string + description: The base path within the repository to store backups. Required for type = 'posix' and 'cifs'. + example: /backups + maxLength: 256 + custom_options: + type: object + description: Additional options to apply to this repository. + example: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + additionalProperties: + type: string + example: Accusamus alias ipsa qui. + gcs_bucket: + type: string + description: The GCS bucket name for this repository. Only applies when type = 'gcs'. + example: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + minLength: 3 + maxLength: 63 + gcs_endpoint: + type: string + description: The optional GCS endpoint for this repository. Only applies when type = 'gcs'. + example: localhost + minLength: 3 + maxLength: 128 + gcs_key: + type: string + description: Optional base64-encoded private key data. If omitted, pgbackrest will use the service account attached to the instance profile. This field will be excluded from the response of all endpoints. It can also be omitted from update requests to keep the current value. + example: ZXhhbXBsZSBnY3Mga2V5Cg== + maxLength: 1024 + id: + type: string + description: A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens. + example: 76f9b8c0-4958-11f0-a489-3bb29577c696 + minLength: 1 + maxLength: 36 + retention_full: type: integer description: The count of full backups to retain or the time to retain full backups. example: 2 @@ -4539,7 +5041,7 @@ components: type: array items: type: string - example: o47 + example: "477" minLength: 3 maxLength: 128 description: The peer addresses of the host that's joining the cluster. @@ -4580,7 +5082,7 @@ components: type: array items: type: string - example: Itaque placeat. + example: Et itaque placeat placeat a enim sit. description: Existing server to join example: - http://192.168.1.1:3000 @@ -4844,15 +5346,15 @@ components: - 10.24.34.2 - i-0123456789abcdef.ec2.internal port: 5432 - created_at: "1984-01-30T10:40:13Z" + created_at: "2011-12-03T04:20:14Z" error: 'failed to get patroni status: connection refused' host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d node_name: n1 postgres: - patroni_paused: true + patroni_paused: false patroni_state: unknown - pending_restart: true + pending_restart: false role: primary version: "18.1" spock: @@ -4867,24 +5369,27 @@ components: - name: sub_n1n2 provider_node: n2 status: down + - name: sub_n1n2 + provider_node: n2 + status: down version: 4.10.0 - state: modifying - status_updated_at: "1976-03-01T20:13:25Z" - updated_at: "1996-05-27T17:04:41Z" + state: stopped + status_updated_at: "1998-03-14T08:14:25Z" + updated_at: "1978-12-17T01:14:06Z" - connection_info: addresses: - 10.24.34.2 - i-0123456789abcdef.ec2.internal port: 5432 - created_at: "1984-01-30T10:40:13Z" + created_at: "2011-12-03T04:20:14Z" error: 'failed to get patroni status: connection refused' host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d node_name: n1 postgres: - patroni_paused: true + patroni_paused: false patroni_state: unknown - pending_restart: true + pending_restart: false role: primary version: "18.1" spock: @@ -4899,38 +5404,108 @@ components: - name: sub_n1n2 provider_node: n2 status: down + - name: sub_n1n2 + provider_node: n2 + status: down version: 4.10.0 - state: modifying - status_updated_at: "1976-03-01T20:13:25Z" - updated_at: "1996-05-27T17:04:41Z" - service_instances: - type: array - items: - $ref: '#/components/schemas/ServiceInstance' - description: Service instances running alongside this database. - example: - - created_at: "2025-01-28T10:00:00Z" - database_id: production - error: 'failed to start container: image not found' - host_id: host-1 - service_id: mcp-server - service_instance_id: mcp-server-host-1 - state: running - status: + state: stopped + status_updated_at: "1998-03-14T08:14:25Z" + updated_at: "1978-12-17T01:14:06Z" + - connection_info: addresses: - 10.24.34.2 - i-0123456789abcdef.ec2.internal - container_id: a1b2c3d4e5f6 - health_check: - checked_at: "2025-01-28T10:00:00Z" - message: Connection refused - status: healthy - image_version: 1.0.0 - last_health_at: "2025-01-28T10:00:00Z" - ports: - - container_port: 8080 - host_port: 8080 - name: web-client + port: 5432 + created_at: "2011-12-03T04:20:14Z" + error: 'failed to get patroni status: connection refused' + host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec + id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d + node_name: n1 + postgres: + patroni_paused: false + patroni_state: unknown + pending_restart: false + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + version: 4.10.0 + state: stopped + status_updated_at: "1998-03-14T08:14:25Z" + updated_at: "1978-12-17T01:14:06Z" + - connection_info: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + port: 5432 + created_at: "2011-12-03T04:20:14Z" + error: 'failed to get patroni status: connection refused' + host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec + id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d + node_name: n1 + postgres: + patroni_paused: false + patroni_state: unknown + pending_restart: false + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + version: 4.10.0 + state: stopped + status_updated_at: "1998-03-14T08:14:25Z" + updated_at: "1978-12-17T01:14:06Z" + service_instances: + type: array + items: + $ref: '#/components/schemas/ServiceInstance' + description: Service instances running alongside this database. + example: + - created_at: "2025-01-28T10:00:00Z" + database_id: production + error: 'failed to start container: image not found' + host_id: host-1 + service_id: mcp-server + service_instance_id: mcp-server-host-1 + state: running + status: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + container_id: a1b2c3d4e5f6 + health_check: + checked_at: "2025-01-28T10:00:00Z" + message: Connection refused + status: healthy + image_version: 1.0.0 + last_health_at: "2025-01-28T10:00:00Z" + ports: - container_port: 8080 host_port: 8080 name: web-client @@ -4964,9 +5539,6 @@ components: - container_port: 8080 host_port: 8080 name: web-client - - container_port: 8080 - host_port: 8080 - name: web-client service_ready: true updated_at: "2025-01-28T10:05:00Z" - created_at: "2025-01-28T10:00:00Z" @@ -4994,9 +5566,6 @@ components: - container_port: 8080 host_port: 8080 name: web-client - - container_port: 8080 - host_port: 8080 - name: web-client service_ready: true updated_at: "2025-01-28T10:05:00Z" - created_at: "2025-01-28T10:00:00Z" @@ -5024,9 +5593,6 @@ components: - container_port: 8080 host_port: 8080 name: web-client - - container_port: 8080 - host_port: 8080 - name: web-client service_ready: true updated_at: "2025-01-28T10:05:00Z" spec: @@ -5034,7 +5600,7 @@ components: state: type: string description: Current state of the database. - example: degraded + example: available enum: - creating - modifying @@ -5261,6 +5827,70 @@ components: state: available status_updated_at: "1993-04-25T23:06:28Z" updated_at: "1981-08-22T23:20:01Z" + - connection_info: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + port: 5432 + created_at: "2011-03-15T17:48:48Z" + error: 'failed to get patroni status: connection refused' + host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec + id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d + node_name: n1 + postgres: + patroni_paused: false + patroni_state: unknown + pending_restart: true + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + version: 4.10.0 + state: available + status_updated_at: "1993-04-25T23:06:28Z" + updated_at: "1981-08-22T23:20:01Z" + - connection_info: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + port: 5432 + created_at: "2011-03-15T17:48:48Z" + error: 'failed to get patroni status: connection refused' + host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec + id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d + node_name: n1 + postgres: + patroni_paused: false + patroni_state: unknown + pending_restart: true + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + version: 4.10.0 + state: available + status_updated_at: "1993-04-25T23:06:28Z" + updated_at: "1981-08-22T23:20:01Z" service_instances: type: array items: @@ -5357,12 +5987,42 @@ components: name: web-client service_ready: true updated_at: "2025-01-28T10:05:00Z" + - created_at: "2025-01-28T10:00:00Z" + database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + error: 'failed to start container: image not found' + host_id: host-1 + service_id: mcp-server + service_instance_id: mcp-server-host-1 + state: running + status: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + container_id: a1b2c3d4e5f6 + health_check: + checked_at: "2025-01-28T10:00:00Z" + message: Connection refused + status: healthy + image_version: 1.0.0 + last_health_at: "2025-01-28T10:00:00Z" + ports: + - container_port: 8080 + host_port: 8080 + name: web-client + - container_port: 8080 + host_port: 8080 + name: web-client + - container_port: 8080 + host_port: 8080 + name: web-client + service_ready: true + updated_at: "2025-01-28T10:05:00Z" spec: $ref: '#/components/schemas/DatabaseSpec3' state: type: string description: Current state of the database. - example: degraded + example: deleting enum: - creating - modifying @@ -5511,9 +6171,6 @@ components: - image: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1 postgres_version: "17.10" spock_version: "5" - - image: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1 - postgres_version: "17.10" - spock_version: "5" created_at: type: string description: The time that the database was created. @@ -5595,38 +6252,6 @@ components: state: available status_updated_at: "1993-04-25T23:06:28Z" updated_at: "1981-08-22T23:20:01Z" - - connection_info: - addresses: - - 10.24.34.2 - - i-0123456789abcdef.ec2.internal - port: 5432 - created_at: "2011-03-15T17:48:48Z" - error: 'failed to get patroni status: connection refused' - host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec - id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d - node_name: n1 - postgres: - patroni_paused: false - patroni_state: unknown - pending_restart: true - role: primary - version: "18.1" - spock: - read_only: "off" - subscriptions: - - name: sub_n1n2 - provider_node: n2 - status: down - - name: sub_n1n2 - provider_node: n2 - status: down - - name: sub_n1n2 - provider_node: n2 - status: down - version: 4.10.0 - state: available - status_updated_at: "1993-04-25T23:06:28Z" - updated_at: "1981-08-22T23:20:01Z" service_instances: type: array items: @@ -5723,42 +6348,12 @@ components: name: web-client service_ready: true updated_at: "2025-01-28T10:05:00Z" - - created_at: "2025-01-28T10:00:00Z" - database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - error: 'failed to start container: image not found' - host_id: host-1 - service_id: mcp-server - service_instance_id: mcp-server-host-1 - state: running - status: - addresses: - - 10.24.34.2 - - i-0123456789abcdef.ec2.internal - container_id: a1b2c3d4e5f6 - health_check: - checked_at: "2025-01-28T10:00:00Z" - message: Connection refused - status: healthy - image_version: 1.0.0 - last_health_at: "2025-01-28T10:00:00Z" - ports: - - container_port: 8080 - host_port: 8080 - name: web-client - - container_port: 8080 - host_port: 8080 - name: web-client - - container_port: 8080 - host_port: 8080 - name: web-client - service_ready: true - updated_at: "2025-01-28T10:05:00Z" spec: $ref: '#/components/schemas/DatabaseSpec4' state: type: string description: Current state of the database. - example: unknown + example: deleting enum: - creating - modifying @@ -5991,10 +6586,42 @@ components: state: available status_updated_at: "1993-04-25T23:06:28Z" updated_at: "1981-08-22T23:20:01Z" - service_instances: - type: array - items: - $ref: '#/components/schemas/ServiceInstance' + - connection_info: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + port: 5432 + created_at: "2011-03-15T17:48:48Z" + error: 'failed to get patroni status: connection refused' + host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec + id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d + node_name: n1 + postgres: + patroni_paused: false + patroni_state: unknown + pending_restart: true + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + version: 4.10.0 + state: available + status_updated_at: "1993-04-25T23:06:28Z" + updated_at: "1981-08-22T23:20:01Z" + service_instances: + type: array + items: + $ref: '#/components/schemas/ServiceInstance' description: Service instances running alongside this database. example: - created_at: "2025-01-28T10:00:00Z" @@ -6057,12 +6684,42 @@ components: name: web-client service_ready: true updated_at: "2025-01-28T10:05:00Z" + - created_at: "2025-01-28T10:00:00Z" + database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + error: 'failed to start container: image not found' + host_id: host-1 + service_id: mcp-server + service_instance_id: mcp-server-host-1 + state: running + status: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + container_id: a1b2c3d4e5f6 + health_check: + checked_at: "2025-01-28T10:00:00Z" + message: Connection refused + status: healthy + image_version: 1.0.0 + last_health_at: "2025-01-28T10:00:00Z" + ports: + - container_port: 8080 + host_port: 8080 + name: web-client + - container_port: 8080 + host_port: 8080 + name: web-client + - container_port: 8080 + host_port: 8080 + name: web-client + service_ready: true + updated_at: "2025-01-28T10:05:00Z" spec: $ref: '#/components/schemas/DatabaseSpec6' state: type: string description: Current state of the database. - example: available + example: unknown enum: - creating - modifying @@ -6208,6 +6865,9 @@ components: - image: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1 postgres_version: "17.10" spock_version: "5" + - image: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1 + postgres_version: "17.10" + spock_version: "5" created_at: type: string description: The time that the database was created. @@ -6289,6 +6949,38 @@ components: state: available status_updated_at: "1993-04-25T23:06:28Z" updated_at: "1981-08-22T23:20:01Z" + - connection_info: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + port: 5432 + created_at: "2011-03-15T17:48:48Z" + error: 'failed to get patroni status: connection refused' + host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec + id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d + node_name: n1 + postgres: + patroni_paused: false + patroni_state: unknown + pending_restart: true + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + version: 4.10.0 + state: available + status_updated_at: "1993-04-25T23:06:28Z" + updated_at: "1981-08-22T23:20:01Z" service_instances: type: array items: @@ -6360,7 +7052,7 @@ components: state: type: string description: Current state of the database. - example: restoring + example: available enum: - creating - modifying @@ -6688,6 +7380,66 @@ components: name: web-client service_ready: true updated_at: "2025-01-28T10:05:00Z" + - created_at: "2025-01-28T10:00:00Z" + database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + error: 'failed to start container: image not found' + host_id: host-1 + service_id: mcp-server + service_instance_id: mcp-server-host-1 + state: running + status: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + container_id: a1b2c3d4e5f6 + health_check: + checked_at: "2025-01-28T10:00:00Z" + message: Connection refused + status: healthy + image_version: 1.0.0 + last_health_at: "2025-01-28T10:00:00Z" + ports: + - container_port: 8080 + host_port: 8080 + name: web-client + - container_port: 8080 + host_port: 8080 + name: web-client + - container_port: 8080 + host_port: 8080 + name: web-client + service_ready: true + updated_at: "2025-01-28T10:05:00Z" + - created_at: "2025-01-28T10:00:00Z" + database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + error: 'failed to start container: image not found' + host_id: host-1 + service_id: mcp-server + service_instance_id: mcp-server-host-1 + state: running + status: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + container_id: a1b2c3d4e5f6 + health_check: + checked_at: "2025-01-28T10:00:00Z" + message: Connection refused + status: healthy + image_version: 1.0.0 + last_health_at: "2025-01-28T10:00:00Z" + ports: + - container_port: 8080 + host_port: 8080 + name: web-client + - container_port: 8080 + host_port: 8080 + name: web-client + - container_port: 8080 + host_port: 8080 + name: web-client + service_ready: true + updated_at: "2025-01-28T10:05:00Z" spec: $ref: '#/components/schemas/DatabaseSpec8' state: @@ -6824,117 +7576,513 @@ components: - created_at - updated_at - state - DatabaseConnection: - type: object - properties: - target_nodes: - type: array - items: - type: string - example: Qui ut et. - description: Optional ordered list of database node names. When set, the service's database connection includes only the listed nodes in the specified order. - example: - - n1 - - n2 - target_session_attrs: - type: string - description: 'Optional libpq target_session_attrs value. When set, overrides the default derived from the service config. Valid values: primary, prefer-standby, standby, read-write, any.' - example: primary - enum: - - primary - - prefer-standby - - standby - - read-write - - any - description: Controls how the service connects to the database. When omitted, all nodes are included with the local node first and target_session_attrs is derived from the service config. - example: - target_nodes: - - n1 - - n2 - target_session_attrs: primary - DatabaseNodeSpec: + Database7: type: object properties: - backup_config: - $ref: '#/components/schemas/BackupConfigSpec' - cpus: - type: string - description: The number of CPUs to allocate for the database on this node and to use for tuning Postgres. It can include the SI suffix 'm', e.g. '500m' for 500 millicpus. Cannot allocate units smaller than 1m. Defaults to the number of available CPUs on the host if 0 or unspecified. Cannot allocate more CPUs than are available on the host. Whether this limit is enforced depends on the orchestrator. - example: 500m - pattern: ^[0-9]+(\.[0-9]{1,3}|m)?$ - host_ids: + available_upgrades: type: array items: - type: string - description: A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens. - example: 76f9b8c0-4958-11f0-a489-3bb29577c696 - minLength: 1 - maxLength: 36 - description: The IDs of the hosts that should run this node. When multiple hosts are specified, one host will chosen as a primary, and the others will be read replicas. + $ref: '#/components/schemas/AvailableUpgrade' + description: Newer stable image versions available in the same Postgres major / Spock major bucket. Present only when ?include=available_upgrades is set. example: - - de3b1388-1f0c-42f1-a86c-59ab72f255ec - - de3b1388-1f0c-42f1-a86c-59ab72f255ec - - de3b1388-1f0c-42f1-a86c-59ab72f255ec - minItems: 1 - memory: + - image: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1 + postgres_version: "17.10" + spock_version: "5" + - image: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1 + postgres_version: "17.10" + spock_version: "5" + - image: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1 + postgres_version: "17.10" + spock_version: "5" + created_at: type: string - description: The amount of memory in SI or IEC notation to allocate for the database on this node and to use for tuning Postgres. Defaults to the total available memory on the host. Whether this limit is enforced depends on the orchestrator. - example: 500M - maxLength: 16 - name: + description: The time that the database was created. + example: "2025-01-01T01:30:00Z" + format: date-time + id: type: string - description: The name of the database node. - example: n1 - pattern: n[0-9]+ - orchestrator_opts: - $ref: '#/components/schemas/OrchestratorOpts' - patroni_port: - type: integer - description: 'The port used by Patroni for this node. Overrides the Patroni port set in the DatabaseSpec. NOTE: This field is not currently supported for Docker Swarm.' - example: 8888 - format: int64 - minimum: 0 - maximum: 65535 - pg_hba_conf: + description: Unique identifier for the database. + example: 76f9b8c0-4958-11f0-a489-3bb29577c696 + minLength: 1 + maxLength: 36 + instances: type: array items: - type: string - example: Non quae. - description: Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity. + $ref: '#/components/schemas/Instance' + description: All of the instances in the database. example: - - host example myapp_user 10.0.0.0/8 scram-sha-256 - pg_ident_conf: + - connection_info: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + port: 5432 + created_at: "2011-03-15T17:48:48Z" + error: 'failed to get patroni status: connection refused' + host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec + id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d + node_name: n1 + postgres: + patroni_paused: false + patroni_state: unknown + pending_restart: true + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + version: 4.10.0 + state: available + status_updated_at: "1993-04-25T23:06:28Z" + updated_at: "1981-08-22T23:20:01Z" + - connection_info: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + port: 5432 + created_at: "2011-03-15T17:48:48Z" + error: 'failed to get patroni status: connection refused' + host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec + id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d + node_name: n1 + postgres: + patroni_paused: false + patroni_state: unknown + pending_restart: true + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + version: 4.10.0 + state: available + status_updated_at: "1993-04-25T23:06:28Z" + updated_at: "1981-08-22T23:20:01Z" + - connection_info: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + port: 5432 + created_at: "2011-03-15T17:48:48Z" + error: 'failed to get patroni status: connection refused' + host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec + id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d + node_name: n1 + postgres: + patroni_paused: false + patroni_state: unknown + pending_restart: true + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + version: 4.10.0 + state: available + status_updated_at: "1993-04-25T23:06:28Z" + updated_at: "1981-08-22T23:20:01Z" + service_instances: type: array items: - type: string - example: Ea omnis ut dolor dolorem impedit laudantium. - description: Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries. + $ref: '#/components/schemas/ServiceInstance' + description: Service instances running alongside this database. example: - - ssl_users CN=alice,O=example alice - port: - type: integer - description: The port used by the Postgres database for this node. Overrides the Postgres port set in the DatabaseSpec. - example: 5432 - format: int64 - minimum: 0 - maximum: 65535 - postgres_version: + - created_at: "2025-01-28T10:00:00Z" + database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + error: 'failed to start container: image not found' + host_id: host-1 + service_id: mcp-server + service_instance_id: mcp-server-host-1 + state: running + status: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + container_id: a1b2c3d4e5f6 + health_check: + checked_at: "2025-01-28T10:00:00Z" + message: Connection refused + status: healthy + image_version: 1.0.0 + last_health_at: "2025-01-28T10:00:00Z" + ports: + - container_port: 8080 + host_port: 8080 + name: web-client + - container_port: 8080 + host_port: 8080 + name: web-client + - container_port: 8080 + host_port: 8080 + name: web-client + service_ready: true + updated_at: "2025-01-28T10:05:00Z" + - created_at: "2025-01-28T10:00:00Z" + database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + error: 'failed to start container: image not found' + host_id: host-1 + service_id: mcp-server + service_instance_id: mcp-server-host-1 + state: running + status: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + container_id: a1b2c3d4e5f6 + health_check: + checked_at: "2025-01-28T10:00:00Z" + message: Connection refused + status: healthy + image_version: 1.0.0 + last_health_at: "2025-01-28T10:00:00Z" + ports: + - container_port: 8080 + host_port: 8080 + name: web-client + - container_port: 8080 + host_port: 8080 + name: web-client + - container_port: 8080 + host_port: 8080 + name: web-client + service_ready: true + updated_at: "2025-01-28T10:05:00Z" + - created_at: "2025-01-28T10:00:00Z" + database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + error: 'failed to start container: image not found' + host_id: host-1 + service_id: mcp-server + service_instance_id: mcp-server-host-1 + state: running + status: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + container_id: a1b2c3d4e5f6 + health_check: + checked_at: "2025-01-28T10:00:00Z" + message: Connection refused + status: healthy + image_version: 1.0.0 + last_health_at: "2025-01-28T10:00:00Z" + ports: + - container_port: 8080 + host_port: 8080 + name: web-client + - container_port: 8080 + host_port: 8080 + name: web-client + - container_port: 8080 + host_port: 8080 + name: web-client + service_ready: true + updated_at: "2025-01-28T10:05:00Z" + - created_at: "2025-01-28T10:00:00Z" + database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + error: 'failed to start container: image not found' + host_id: host-1 + service_id: mcp-server + service_instance_id: mcp-server-host-1 + state: running + status: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + container_id: a1b2c3d4e5f6 + health_check: + checked_at: "2025-01-28T10:00:00Z" + message: Connection refused + status: healthy + image_version: 1.0.0 + last_health_at: "2025-01-28T10:00:00Z" + ports: + - container_port: 8080 + host_port: 8080 + name: web-client + - container_port: 8080 + host_port: 8080 + name: web-client + - container_port: 8080 + host_port: 8080 + name: web-client + service_ready: true + updated_at: "2025-01-28T10:05:00Z" + spec: + $ref: '#/components/schemas/DatabaseSpec9' + state: type: string - description: The Postgres version for this node in 'major.minor' format. Overrides the Postgres version set in the DatabaseSpec. - example: "17.6" - pattern: ^\d{2}\.\d{1,2}$ - postgresql_conf: - type: object - description: Additional postgresql.conf settings for this particular node. Will be merged with the settings provided by control-plane. - example: - max_connections: 1000 - additionalProperties: true - restore_config: - $ref: '#/components/schemas/RestoreConfigSpec' - source_node: + description: Current state of the database. + example: unknown + enum: + - creating + - modifying + - available + - deleting + - degraded + - failed + - restoring + - unknown + tenant_id: + type: string + description: Unique identifier for the database's owner. + example: 76f9b8c0-4958-11f0-a489-3bb29577c696 + minLength: 1 + maxLength: 36 + updated_at: + type: string + description: The time that the database was last updated. + example: "2025-01-01T02:30:00Z" + format: date-time + example: + created_at: "2025-06-18T16:52:05Z" + id: storefront + instances: + - connection_info: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + port: 5432 + created_at: "2025-06-18T16:52:22Z" + host_id: us-east-1 + id: storefront-n1-689qacsi + node_name: n1 + postgres: + patroni_state: running + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n1n3 + provider_node: n3 + status: replicating + - name: sub_n1n2 + provider_node: n2 + status: replicating + version: 4.0.10 + state: available + status_updated_at: "2025-06-18T17:58:56Z" + updated_at: "2025-06-18T17:54:36Z" + - connection_info: + addresses: + - 10.24.35.2 + - i-058731542fee493f.ec2.internal + port: 5432 + created_at: "2025-06-18T16:52:22Z" + host_id: ap-south-1 + id: storefront-n2-9ptayhma + node_name: n2 + postgres: + patroni_state: running + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n2n1 + provider_node: n1 + status: replicating + - name: sub_n2n3 + provider_node: n3 + status: replicating + version: 4.0.10 + state: available + status_updated_at: "2025-06-18T17:58:56Z" + updated_at: "2025-06-18T17:54:01Z" + - connection_info: + addresses: + - 10.24.36.2 + - i-494027b7b53f6a23.ec2.internal + port: 5432 + created_at: "2025-06-18T16:52:22Z" + host_id: eu-central-1 + id: storefront-n3-ant97dj4 + node_name: n3 + postgres: + patroni_state: running + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n3n1 + provider_node: n1 + status: replicating + - name: sub_n3n2 + provider_node: n2 + status: replicating + version: 4.0.10 + state: available + status_updated_at: "2025-06-18T17:58:56Z" + updated_at: "2025-06-18T17:54:01Z" + spec: + database_name: storefront + database_users: + - attributes: + - SUPERUSER + - LOGIN + db_owner: true + username: admin + nodes: + - host_ids: + - us-east-1 + name: n1 + - host_ids: + - ap-south-1 + name: n2 + - host_ids: + - eu-central-1 + name: n3 + port: 5432 + postgres_version: "17.6" + spock_version: "5" + state: restoring + updated_at: "2025-06-18T17:58:59Z" + required: + - id + - created_at + - updated_at + - state + DatabaseConnection: + type: object + properties: + target_nodes: + type: array + items: + type: string + example: Illo dolore. + description: Optional ordered list of database node names. When set, the service's database connection includes only the listed nodes in the specified order. + example: + - n1 + - n2 + target_session_attrs: + type: string + description: 'Optional libpq target_session_attrs value. When set, overrides the default derived from the service config. Valid values: primary, prefer-standby, standby, read-write, any.' + example: primary + enum: + - primary + - prefer-standby + - standby + - read-write + - any + description: Controls how the service connects to the database. When omitted, all nodes are included with the local node first and target_session_attrs is derived from the service config. + example: + target_nodes: + - n1 + - n2 + target_session_attrs: primary + DatabaseNodeSpec: + type: object + properties: + backup_config: + $ref: '#/components/schemas/BackupConfigSpec' + cpus: + type: string + description: The number of CPUs to allocate for the database on this node and to use for tuning Postgres. It can include the SI suffix 'm', e.g. '500m' for 500 millicpus. Cannot allocate units smaller than 1m. Defaults to the number of available CPUs on the host if 0 or unspecified. Cannot allocate more CPUs than are available on the host. Whether this limit is enforced depends on the orchestrator. + example: 500m + pattern: ^[0-9]+(\.[0-9]{1,3}|m)?$ + host_ids: + type: array + items: + type: string + description: A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens. + example: 76f9b8c0-4958-11f0-a489-3bb29577c696 + minLength: 1 + maxLength: 36 + description: The IDs of the hosts that should run this node. When multiple hosts are specified, one host will chosen as a primary, and the others will be read replicas. + example: + - de3b1388-1f0c-42f1-a86c-59ab72f255ec + minItems: 1 + memory: + type: string + description: The amount of memory in SI or IEC notation to allocate for the database on this node and to use for tuning Postgres. Defaults to the total available memory on the host. Whether this limit is enforced depends on the orchestrator. + example: 500M + maxLength: 16 + name: + type: string + description: The name of the database node. + example: n1 + pattern: n[0-9]+ + orchestrator_opts: + $ref: '#/components/schemas/OrchestratorOpts' + patroni_port: + type: integer + description: 'The port used by Patroni for this node. Overrides the Patroni port set in the DatabaseSpec. NOTE: This field is not currently supported for Docker Swarm.' + example: 8888 + format: int64 + minimum: 0 + maximum: 65535 + pg_hba_conf: + type: array + items: + type: string + example: Sint iure eum ducimus quia deserunt animi. + description: Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity. + example: + - host example myapp_user 10.0.0.0/8 scram-sha-256 + pg_ident_conf: + type: array + items: + type: string + example: Nihil qui non quae sint ea. + description: Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries. + example: + - ssl_users CN=alice,O=example alice + port: + type: integer + description: The port used by the Postgres database for this node. Overrides the Postgres port set in the DatabaseSpec. + example: 5432 + format: int64 + minimum: 0 + maximum: 65535 + postgres_version: + type: string + description: The Postgres version for this node in 'major.minor' format. Overrides the Postgres version set in the DatabaseSpec. + example: "17.6" + pattern: ^\d{2}\.\d{1,2}$ + postgresql_conf: + type: object + description: Additional postgresql.conf settings for this particular node. Will be merged with the settings provided by control-plane. + example: + max_connections: 1000 + additionalProperties: true + restore_config: + $ref: '#/components/schemas/RestoreConfigSpec' + source_node: type: string description: The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node. example: n1 + spock_version: + type: string + description: The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice. + example: "6" + pattern: ^\d{1}$ example: backup_config: repositories: @@ -7026,7 +8174,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Animi recusandae. + image: Sapiente qui ullam. patroni_port: 8888 pg_hba_conf: - host example myapp_user 10.0.0.0/8 scram-sha-256 @@ -7063,6 +8211,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" required: - name - host_ids @@ -7086,6 +8235,8 @@ components: description: The IDs of the hosts that should run this node. When multiple hosts are specified, one host will chosen as a primary, and the others will be read replicas. example: - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 minItems: 1 memory: type: string @@ -7110,7 +8261,7 @@ components: type: array items: type: string - example: Sapiente neque doloribus consequatur voluptatibus sed. + example: Laboriosam placeat distinctio atque dolor autem. description: Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity. example: - host example myapp_user 10.0.0.0/8 scram-sha-256 @@ -7118,7 +8269,7 @@ components: type: array items: type: string - example: Nisi nihil corporis perspiciatis et. + example: Et excepturi sapiente. description: Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries. example: - ssl_users CN=alice,O=example alice @@ -7146,6 +8297,11 @@ components: type: string description: The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node. example: n1 + spock_version: + type: string + description: The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice. + example: "6" + pattern: ^\d{1}$ example: backup_config: repositories: @@ -7222,7 +8378,6 @@ components: cpus: 500m host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 memory: 500M name: n1 orchestrator_opts: @@ -7293,6 +8448,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" required: - name - host_ids @@ -7340,7 +8496,7 @@ components: type: array items: type: string - example: Distinctio sed amet rem voluptas qui. + example: Est temporibus molestias officiis sint. description: Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity. example: - host example myapp_user 10.0.0.0/8 scram-sha-256 @@ -7348,7 +8504,7 @@ components: type: array items: type: string - example: Voluptatem nesciunt dignissimos voluptas vel earum. + example: Ad aut velit distinctio sed. description: Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries. example: - ssl_users CN=alice,O=example alice @@ -7376,6 +8532,11 @@ components: type: string description: The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node. example: n1 + spock_version: + type: string + description: The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice. + example: "6" + pattern: ^\d{1}$ example: backup_config: repositories: @@ -7432,8 +8593,6 @@ components: cpus: 500m host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 memory: 500M name: n1 orchestrator_opts: @@ -7504,6 +8663,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" required: - name - host_ids @@ -7528,7 +8688,6 @@ components: example: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 minItems: 1 memory: type: string @@ -7553,7 +8712,7 @@ components: type: array items: type: string - example: Harum iste dignissimos. + example: Numquam incidunt eaque totam at culpa ut. description: Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity. example: - host example myapp_user 10.0.0.0/8 scram-sha-256 @@ -7561,7 +8720,7 @@ components: type: array items: type: string - example: Beatae nobis quam sequi quasi aliquid. + example: Iste dignissimos exercitationem. description: Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries. example: - ssl_users CN=alice,O=example alice @@ -7589,6 +8748,11 @@ components: type: string description: The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node. example: n1 + spock_version: + type: string + description: The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice. + example: "6" + pattern: ^\d{1}$ example: backup_config: repositories: @@ -7645,6 +8809,8 @@ components: cpus: 500m host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 memory: 500M name: n1 orchestrator_opts: @@ -7715,6 +8881,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" required: - name - host_ids @@ -7764,7 +8931,7 @@ components: type: array items: type: string - example: Dolor sit quae et tempore et aut. + example: Et qui et. description: Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity. example: - host example myapp_user 10.0.0.0/8 scram-sha-256 @@ -7772,7 +8939,7 @@ components: type: array items: type: string - example: Nisi eveniet sit dignissimos ducimus. + example: Omnis nobis. description: Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries. example: - ssl_users CN=alice,O=example alice @@ -7800,6 +8967,11 @@ components: type: string description: The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node. example: n1 + spock_version: + type: string + description: The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice. + example: "6" + pattern: ^\d{1}$ example: backup_config: repositories: @@ -7946,6 +9118,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" required: - name - host_ids @@ -7969,7 +9142,6 @@ components: description: The IDs of the hosts that should run this node. When multiple hosts are specified, one host will chosen as a primary, and the others will be read replicas. example: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 minItems: 1 memory: type: string @@ -7994,7 +9166,7 @@ components: type: array items: type: string - example: Laudantium molestiae error quas iste. + example: Quia quis. description: Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity. example: - host example myapp_user 10.0.0.0/8 scram-sha-256 @@ -8002,7 +9174,7 @@ components: type: array items: type: string - example: Assumenda et. + example: Ducimus deserunt quis commodi officiis libero mollitia. description: Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries. example: - ssl_users CN=alice,O=example alice @@ -8030,6 +9202,11 @@ components: type: string description: The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node. example: n1 + spock_version: + type: string + description: The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice. + example: "6" + pattern: ^\d{1}$ example: backup_config: repositories: @@ -8156,6 +9333,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" required: - name - host_ids @@ -8204,7 +9382,7 @@ components: type: array items: type: string - example: Alias est mollitia. + example: Excepturi debitis aperiam. description: Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity. example: - host example myapp_user 10.0.0.0/8 scram-sha-256 @@ -8212,7 +9390,7 @@ components: type: array items: type: string - example: Possimus id laudantium sed delectus. + example: At eveniet consectetur. description: Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries. example: - ssl_users CN=alice,O=example alice @@ -8240,6 +9418,11 @@ components: type: string description: The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node. example: n1 + spock_version: + type: string + description: The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice. + example: "6" + pattern: ^\d{1}$ example: backup_config: repositories: @@ -8366,6 +9549,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" required: - name - host_ids @@ -8389,8 +9573,6 @@ components: description: The IDs of the hosts that should run this node. When multiple hosts are specified, one host will chosen as a primary, and the others will be read replicas. example: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 minItems: 1 memory: type: string @@ -8415,7 +9597,7 @@ components: type: array items: type: string - example: Id natus aut. + example: Quod facere possimus sit commodi. description: Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity. example: - host example myapp_user 10.0.0.0/8 scram-sha-256 @@ -8423,7 +9605,7 @@ components: type: array items: type: string - example: Minus sint totam et et. + example: Dolor unde optio illo ut sint cumque. description: Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries. example: - ssl_users CN=alice,O=example alice @@ -8451,6 +9633,11 @@ components: type: string description: The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node. example: n1 + spock_version: + type: string + description: The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice. + example: "6" + pattern: ^\d{1}$ example: backup_config: repositories: @@ -8507,7 +9694,220 @@ components: cpus: 500m host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 500M + name: n1 + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Incidunt in quas totam. + patroni_port: 8888 + pg_hba_conf: + - host example myapp_user 10.0.0.0/8 scram-sha-256 + pg_ident_conf: + - ssl_users CN=alice,O=example alice + port: 5432 + postgres_version: "17.6" + postgresql_conf: + max_connections: 1000 + restore_config: + repository: + azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + restore_options: + set: 20250505-153628F + target: "123456" + type: xid + source_database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + source_database_name: northwind + source_node_name: n1 + source_node: n1 + spock_version: "6" + required: + - name + - host_ids + DatabaseNodeSpec9: + type: object + properties: + backup_config: + $ref: '#/components/schemas/BackupConfigSpec' + cpus: + type: string + description: The number of CPUs to allocate for the database on this node and to use for tuning Postgres. It can include the SI suffix 'm', e.g. '500m' for 500 millicpus. Cannot allocate units smaller than 1m. Defaults to the number of available CPUs on the host if 0 or unspecified. Cannot allocate more CPUs than are available on the host. Whether this limit is enforced depends on the orchestrator. + example: 500m + pattern: ^[0-9]+(\.[0-9]{1,3}|m)?$ + host_ids: + type: array + items: + type: string + example: 76f9b8c0-4958-11f0-a489-3bb29577c696 + minLength: 1 + maxLength: 36 + description: The IDs of the hosts that should run this node. When multiple hosts are specified, one host will chosen as a primary, and the others will be read replicas. + example: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + minItems: 1 + memory: + type: string + description: The amount of memory in SI or IEC notation to allocate for the database on this node and to use for tuning Postgres. Defaults to the total available memory on the host. Whether this limit is enforced depends on the orchestrator. + example: 500M + maxLength: 16 + name: + type: string + description: The name of the database node. + example: n1 + pattern: n[0-9]+ + orchestrator_opts: + $ref: '#/components/schemas/OrchestratorOpts' + patroni_port: + type: integer + description: 'The port used by Patroni for this node. Overrides the Patroni port set in the DatabaseSpec. NOTE: This field is not currently supported for Docker Swarm.' + example: 8888 + format: int64 + minimum: 0 + maximum: 65535 + pg_hba_conf: + type: array + items: + type: string + example: Et exercitationem sequi saepe velit. + description: Additional pg_hba.conf entries for this particular node, one rule per array element. Prepended to the database-level pg_hba_conf entries, so node entries take first-match priority. Entries are inserted between control-plane's system-user rules and its catch-all, and cannot affect control-plane-internal connectivity. + example: + - host example myapp_user 10.0.0.0/8 scram-sha-256 + pg_ident_conf: + type: array + items: + type: string + example: Ex sint dolorum vel. + description: Additional pg_ident.conf entries for this particular node, one mapping per array element. Prepended to the database-level pg_ident_conf entries. + example: + - ssl_users CN=alice,O=example alice + port: + type: integer + description: The port used by the Postgres database for this node. Overrides the Postgres port set in the DatabaseSpec. + example: 5432 + format: int64 + minimum: 0 + maximum: 65535 + postgres_version: + type: string + description: The Postgres version for this node in 'major.minor' format. Overrides the Postgres version set in the DatabaseSpec. + example: "17.6" + pattern: ^\d{2}\.\d{1,2}$ + postgresql_conf: + type: object + description: Additional postgresql.conf settings for this particular node. Will be merged with the settings provided by control-plane. + example: + max_connections: 1000 + additionalProperties: true + restore_config: + $ref: '#/components/schemas/RestoreConfigSpec' + source_node: + type: string + description: The name of the source node to use for sync. This is typically the node (like 'n1') from which the data will be copied to initialize this new node. + example: n1 + spock_version: + type: string + description: The major version of the Spock extension for this node. Overrides the Spock version set in the DatabaseSpec. Only settable through the dedicated major-version upgrade action — rejected on create-database and on the general update-database path, since a per-node major mismatch is only ever a deliberate, transient state during a rolling major-version upgrade, never a steady-state topology choice. + example: "6" + pattern: ^\d{1}$ + example: + backup_config: + repositories: + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + schedules: + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + cpus: 500m + host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 memory: 500M name: n1 @@ -8579,6 +9979,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" required: - name - host_ids @@ -8747,7 +10148,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Animi recusandae. + image: Sapiente qui ullam. patroni_port: 8888 pg_hba_conf: - host example myapp_user 10.0.0.0/8 scram-sha-256 @@ -8784,6 +10185,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" - backup_config: repositories: - azure_account: pgedge-backups @@ -8874,7 +10276,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Animi recusandae. + image: Sapiente qui ullam. patroni_port: 8888 pg_hba_conf: - host example myapp_user 10.0.0.0/8 scram-sha-256 @@ -8911,77 +10313,66 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 - minItems: 1 - maxItems: 9 - orchestrator_opts: - $ref: '#/components/schemas/OrchestratorOpts' - patroni_port: - type: integer - description: 'The port used by Patroni for this database. If the port is 0, each instance will be assigned a random port. NOTE: This field is not currently supported for Docker Swarm.' - example: 8888 - format: int64 - minimum: 0 - maximum: 65535 - pg_hba_conf: - type: array - items: - type: string - example: Velit et labore in dolor quisquam placeat. - description: Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these. - example: - - hostssl all myapp_user 203.0.113.0/24 scram-sha-256 - - hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users - pg_ident_conf: - type: array - items: - type: string - example: Eos molestiae voluptates laborum. - description: Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames. - example: - - ssl_users CN=alice,O=example alice - port: - type: integer - description: The port used by the Postgres database. If the port is 0, each instance will be assigned a random port. If the port is unspecified, the database will not be exposed on any port, dependent on orchestrator support for that feature. - example: 5432 - format: int64 - minimum: 0 - maximum: 65535 - postgres_version: - type: string - description: The Postgres version in 'major.minor' format. - example: "17.6" - pattern: ^\d{2}\.\d{1,2}$ - postgresql_conf: - type: object - description: Additional postgresql.conf settings. Will be merged with the settings provided by control-plane. - example: - max_connections: 1000 - maxLength: 64 - additionalProperties: true - restore_config: - $ref: '#/components/schemas/RestoreConfigSpec' - scripts: - $ref: '#/components/schemas/DatabaseScripts' - services: - type: array - items: - $ref: '#/components/schemas/ServiceSpec' - description: Service instances to run alongside the database (e.g., MCP servers). - example: - - config: - llm_model: gpt-4 - llm_provider: openai - openai_api_key: sk-... - connect_as: app + spock_version: "6" + - backup_config: + repositories: + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: f6b84a99-5e91-4203-be1e-131fe82e5984 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: f6b84a99-5e91-4203-be1e-131fe82e5984 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + schedules: + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full cpus: 500m - database_connection: - target_nodes: - - n1 - - n2 - target_session_attrs: primary host_ids: - de3b1388-1f0c-42f1-a86c-59ab72f255ec - memory: 512M + - de3b1388-1f0c-42f1-a86c-59ab72f255ec + - de3b1388-1f0c-42f1-a86c-59ab72f255ec + memory: 500M + name: n1 orchestrator_opts: swarm: extra_labels: @@ -9013,11 +10404,101 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Animi recusandae. - port: 0 - service_id: analytics-service - service_type: rag - version: latest + image: Sapiente qui ullam. + patroni_port: 8888 + pg_hba_conf: + - host example myapp_user 10.0.0.0/8 scram-sha-256 + pg_ident_conf: + - ssl_users CN=alice,O=example alice + port: 5432 + postgres_version: "17.6" + postgresql_conf: + max_connections: 1000 + restore_config: + repository: + azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: f6b84a99-5e91-4203-be1e-131fe82e5984 + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + restore_options: + set: 20250505-153628F + target: "123456" + type: xid + source_database_id: 02f1a7db-fca8-4521-b57a-2a375c1ced51 + source_database_name: northwind + source_node_name: n1 + source_node: n1 + spock_version: "6" + minItems: 1 + maxItems: 9 + orchestrator_opts: + $ref: '#/components/schemas/OrchestratorOpts' + patroni_port: + type: integer + description: 'The port used by Patroni for this database. If the port is 0, each instance will be assigned a random port. NOTE: This field is not currently supported for Docker Swarm.' + example: 8888 + format: int64 + minimum: 0 + maximum: 65535 + pg_hba_conf: + type: array + items: + type: string + example: Magni quaerat qui quam id aut velit. + description: Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these. + example: + - hostssl all myapp_user 203.0.113.0/24 scram-sha-256 + - hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users + pg_ident_conf: + type: array + items: + type: string + example: Labore in. + description: Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames. + example: + - ssl_users CN=alice,O=example alice + port: + type: integer + description: The port used by the Postgres database. If the port is 0, each instance will be assigned a random port. If the port is unspecified, the database will not be exposed on any port, dependent on orchestrator support for that feature. + example: 5432 + format: int64 + minimum: 0 + maximum: 65535 + postgres_version: + type: string + description: The Postgres version in 'major.minor' format. + example: "17.6" + pattern: ^\d{2}\.\d{1,2}$ + postgresql_conf: + type: object + description: Additional postgresql.conf settings. Will be merged with the settings provided by control-plane. + example: + max_connections: 1000 + maxLength: 64 + additionalProperties: true + restore_config: + $ref: '#/components/schemas/RestoreConfigSpec' + scripts: + $ref: '#/components/schemas/DatabaseScripts' + services: + type: array + items: + $ref: '#/components/schemas/ServiceSpec' + description: Service instances to run alongside the database (e.g., MCP servers). + example: - config: llm_model: gpt-4 llm_provider: openai @@ -9031,6 +10512,7 @@ components: target_session_attrs: primary host_ids: - de3b1388-1f0c-42f1-a86c-59ab72f255ec + - de3b1388-1f0c-42f1-a86c-59ab72f255ec memory: 512M orchestrator_opts: swarm: @@ -9063,7 +10545,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Animi recusandae. + image: Sapiente qui ullam. port: 0 service_id: analytics-service service_type: rag @@ -9081,6 +10563,7 @@ components: target_session_attrs: primary host_ids: - de3b1388-1f0c-42f1-a86c-59ab72f255ec + - de3b1388-1f0c-42f1-a86c-59ab72f255ec memory: 512M orchestrator_opts: swarm: @@ -9113,7 +10596,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Animi recusandae. + image: Sapiente qui ullam. port: 0 service_id: analytics-service service_type: rag @@ -9298,134 +10781,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Animi recusandae. - patroni_port: 8888 - pg_hba_conf: - - host example myapp_user 10.0.0.0/8 scram-sha-256 - pg_ident_conf: - - ssl_users CN=alice,O=example alice - port: 5432 - postgres_version: "17.6" - postgresql_conf: - max_connections: 1000 - restore_config: - repository: - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: f6b84a99-5e91-4203-be1e-131fe82e5984 - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - restore_options: - set: 20250505-153628F - target: "123456" - type: xid - source_database_id: 02f1a7db-fca8-4521-b57a-2a375c1ced51 - source_database_name: northwind - source_node_name: n1 - source_node: n1 - - backup_config: - repositories: - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: f6b84a99-5e91-4203-be1e-131fe82e5984 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: f6b84a99-5e91-4203-be1e-131fe82e5984 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - schedules: - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - cpus: 500m - host_ids: - - de3b1388-1f0c-42f1-a86c-59ab72f255ec - - de3b1388-1f0c-42f1-a86c-59ab72f255ec - - de3b1388-1f0c-42f1-a86c-59ab72f255ec - memory: 500M - name: n1 - orchestrator_opts: - swarm: - extra_labels: - traefik.enable: "true" - traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) - extra_networks: - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - extra_volumes: - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - image: Animi recusandae. + image: Sapiente qui ullam. patroni_port: 8888 pg_hba_conf: - host example myapp_user 10.0.0.0/8 scram-sha-256 @@ -9462,6 +10818,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" orchestrator_opts: swarm: extra_labels: @@ -9493,7 +10850,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Animi recusandae. + image: Sapiente qui ullam. patroni_port: 8888 pg_hba_conf: - hostssl all myapp_user 203.0.113.0/24 scram-sha-256 @@ -9551,55 +10908,6 @@ components: target_session_attrs: primary host_ids: - de3b1388-1f0c-42f1-a86c-59ab72f255ec - memory: 512M - orchestrator_opts: - swarm: - extra_labels: - traefik.enable: "true" - traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) - extra_networks: - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - extra_volumes: - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - image: Animi recusandae. - port: 0 - service_id: analytics-service - service_type: rag - version: latest - - config: - llm_model: gpt-4 - llm_provider: openai - openai_api_key: sk-... - connect_as: app - cpus: 500m - database_connection: - target_nodes: - - n1 - - n2 - target_session_attrs: primary - host_ids: - de3b1388-1f0c-42f1-a86c-59ab72f255ec memory: 512M orchestrator_opts: @@ -9633,7 +10941,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Animi recusandae. + image: Sapiente qui ullam. port: 0 service_id: analytics-service service_type: rag @@ -9651,55 +10959,6 @@ components: target_session_attrs: primary host_ids: - de3b1388-1f0c-42f1-a86c-59ab72f255ec - memory: 512M - orchestrator_opts: - swarm: - extra_labels: - traefik.enable: "true" - traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) - extra_networks: - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - extra_volumes: - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - image: Animi recusandae. - port: 0 - service_id: analytics-service - service_type: rag - version: latest - - config: - llm_model: gpt-4 - llm_provider: openai - openai_api_key: sk-... - connect_as: app - cpus: 500m - database_connection: - target_nodes: - - n1 - - n2 - target_session_attrs: primary - host_ids: - de3b1388-1f0c-42f1-a86c-59ab72f255ec memory: 512M orchestrator_opts: @@ -9733,7 +10992,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Animi recusandae. + image: Sapiente qui ullam. port: 0 service_id: analytics-service service_type: rag @@ -9950,127 +11209,86 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 - minItems: 1 - maxItems: 9 - orchestrator_opts: - $ref: '#/components/schemas/OrchestratorOpts' - patroni_port: - type: integer - description: 'The port used by Patroni for this database. If the port is 0, each instance will be assigned a random port. NOTE: This field is not currently supported for Docker Swarm.' - example: 8888 - format: int64 - minimum: 0 - maximum: 65535 - pg_hba_conf: - type: array - items: - type: string - example: Optio accusantium. - description: Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these. - example: - - hostssl all myapp_user 203.0.113.0/24 scram-sha-256 - - hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users - pg_ident_conf: - type: array - items: - type: string - example: Voluptatibus sunt deserunt sapiente doloribus est. - description: Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames. - example: - - ssl_users CN=alice,O=example alice - port: - type: integer - description: The port used by the Postgres database. If the port is 0, each instance will be assigned a random port. If the port is unspecified, the database will not be exposed on any port, dependent on orchestrator support for that feature. - example: 5432 - format: int64 - minimum: 0 - maximum: 65535 - postgres_version: - type: string - description: The Postgres version in 'major.minor' format. - example: "17.6" - pattern: ^\d{2}\.\d{1,2}$ - postgresql_conf: - type: object - description: Additional postgresql.conf settings. Will be merged with the settings provided by control-plane. - example: - max_connections: 1000 - maxLength: 64 - additionalProperties: true - restore_config: - $ref: '#/components/schemas/RestoreConfigSpec' - scripts: - $ref: '#/components/schemas/DatabaseScripts' - services: - type: array - items: - $ref: '#/components/schemas/ServiceSpec2' - description: Service instances to run alongside the database (e.g., MCP servers). - example: - - config: - llm_model: gpt-4 - llm_provider: openai - openai_api_key: sk-... - connect_as: app - cpus: 500m - database_connection: - target_nodes: - - n1 - - n2 - target_session_attrs: primary - host_ids: - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - memory: 512M - orchestrator_opts: - swarm: - extra_labels: - traefik.enable: "true" - traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) - extra_networks: - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - extra_volumes: - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - image: Reprehenderit atque aliquid. - port: 0 - service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - service_type: rag - version: latest - - config: - llm_model: gpt-4 - llm_provider: openai - openai_api_key: sk-... - connect_as: app - cpus: 500m - database_connection: - target_nodes: - - n1 - - n2 - target_session_attrs: primary + spock_version: "6" + - backup_config: + repositories: + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + schedules: + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + cpus: 500m host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - memory: 512M + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 500M + name: n1 orchestrator_opts: swarm: extra_labels: @@ -10103,24 +11321,122 @@ components: - destination_path: /backups/container host_path: /Users/user/backups/host image: Reprehenderit atque aliquid. - port: 0 - service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - service_type: rag - version: latest - - config: - llm_model: gpt-4 - llm_provider: openai - openai_api_key: sk-... - connect_as: app + patroni_port: 8888 + pg_hba_conf: + - host example myapp_user 10.0.0.0/8 scram-sha-256 + pg_ident_conf: + - ssl_users CN=alice,O=example alice + port: 5432 + postgres_version: "17.6" + postgresql_conf: + max_connections: 1000 + restore_config: + repository: + azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + restore_options: + set: 20250505-153628F + target: "123456" + type: xid + source_database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + source_database_name: northwind + source_node_name: n1 + source_node: n1 + spock_version: "6" + - backup_config: + repositories: + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + schedules: + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full cpus: 500m - database_connection: - target_nodes: - - n1 - - n2 - target_session_attrs: primary host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - memory: 512M + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 500M + name: n1 orchestrator_opts: swarm: extra_labels: @@ -10153,58 +11469,258 @@ components: - destination_path: /backups/container host_path: /Users/user/backups/host image: Reprehenderit atque aliquid. - port: 0 - service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - service_type: rag - version: latest - spock_version: - type: string - description: The major version of the Spock extension. - example: "5" - pattern: ^\d{1}$ - example: - backup_config: - repositories: - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 + patroni_port: 8888 + pg_hba_conf: + - host example myapp_user 10.0.0.0/8 scram-sha-256 + pg_ident_conf: + - ssl_users CN=alice,O=example alice + port: 5432 + postgres_version: "17.6" + postgresql_conf: + max_connections: 1000 + restore_config: + repository: + azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + restore_options: + set: 20250505-153628F + target: "123456" + type: xid + source_database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + source_database_name: northwind + source_node_name: n1 + source_node: n1 + spock_version: "6" + minItems: 1 + maxItems: 9 + orchestrator_opts: + $ref: '#/components/schemas/OrchestratorOpts' + patroni_port: + type: integer + description: 'The port used by Patroni for this database. If the port is 0, each instance will be assigned a random port. NOTE: This field is not currently supported for Docker Swarm.' + example: 8888 + format: int64 + minimum: 0 + maximum: 65535 + pg_hba_conf: + type: array + items: + type: string + example: Nihil corporis perspiciatis et veniam blanditiis. + description: Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these. + example: + - hostssl all myapp_user 203.0.113.0/24 scram-sha-256 + - hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users + pg_ident_conf: + type: array + items: + type: string + example: Accusamus repellat fuga occaecati. + description: Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames. + example: + - ssl_users CN=alice,O=example alice + port: + type: integer + description: The port used by the Postgres database. If the port is 0, each instance will be assigned a random port. If the port is unspecified, the database will not be exposed on any port, dependent on orchestrator support for that feature. + example: 5432 + format: int64 + minimum: 0 + maximum: 65535 + postgres_version: + type: string + description: The Postgres version in 'major.minor' format. + example: "17.6" + pattern: ^\d{2}\.\d{1,2}$ + postgresql_conf: + type: object + description: Additional postgresql.conf settings. Will be merged with the settings provided by control-plane. + example: + max_connections: 1000 + maxLength: 64 + additionalProperties: true + restore_config: + $ref: '#/components/schemas/RestoreConfigSpec' + scripts: + $ref: '#/components/schemas/DatabaseScripts' + services: + type: array + items: + $ref: '#/components/schemas/ServiceSpec2' + description: Service instances to run alongside the database (e.g., MCP servers). + example: + - config: + llm_model: gpt-4 + llm_provider: openai + openai_api_key: sk-... + connect_as: app + cpus: 500m + database_connection: + target_nodes: + - n1 + - n2 + target_session_attrs: primary + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 512M + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Reprehenderit atque aliquid. + port: 0 + service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + service_type: rag + version: latest + - config: + llm_model: gpt-4 + llm_provider: openai + openai_api_key: sk-... + connect_as: app + cpus: 500m + database_connection: + target_nodes: + - n1 + - n2 + target_session_attrs: primary + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 512M + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Reprehenderit atque aliquid. + port: 0 + service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + service_type: rag + version: latest + - config: + llm_model: gpt-4 + llm_provider: openai + openai_api_key: sk-... + connect_as: app + cpus: 500m + database_connection: + target_nodes: + - n1 + - n2 + target_session_attrs: primary + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 512M + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Reprehenderit atque aliquid. + port: 0 + service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + service_type: rag + version: latest + spock_version: + type: string + description: The major version of the Spock extension. + example: "5" + pattern: ^\d{1}$ + example: + backup_config: + repositories: - azure_account: pgedge-backups azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 azure_endpoint: blob.core.usgovcloudapi.net @@ -10225,9 +11741,49 @@ components: s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY s3_region: us-east-1 type: s3 - schedules: - - cron_expression: 0 6 * * ? - id: daily-full-backup + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + schedules: + - cron_expression: 0 6 * * ? + id: daily-full-backup type: full - cron_expression: 0 6 * * ? id: daily-full-backup @@ -10414,6 +11970,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" - backup_config: repositories: - azure_account: pgedge-backups @@ -10561,153 +12118,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 - - backup_config: - repositories: - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - schedules: - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - cpus: 500m - host_ids: - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - memory: 500M - name: n1 - orchestrator_opts: - swarm: - extra_labels: - traefik.enable: "true" - traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) - extra_networks: - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - extra_volumes: - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - image: Reprehenderit atque aliquid. - patroni_port: 8888 - pg_hba_conf: - - host example myapp_user 10.0.0.0/8 scram-sha-256 - pg_ident_conf: - - ssl_users CN=alice,O=example alice - port: 5432 - postgres_version: "17.6" - postgresql_conf: - max_connections: 1000 - restore_config: - repository: - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - restore_options: - set: 20250505-153628F - target: "123456" - type: xid - source_database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - source_database_name: northwind - source_node_name: n1 - source_node: n1 + spock_version: "6" orchestrator_opts: swarm: extra_labels: @@ -11078,133 +12489,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 - - backup_config: - repositories: - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - schedules: - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - cpus: 500m - host_ids: - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - memory: 500M - name: n1 - orchestrator_opts: - swarm: - extra_labels: - traefik.enable: "true" - traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) - extra_networks: - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - extra_volumes: - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - image: Incidunt in quas totam. - patroni_port: 8888 - pg_hba_conf: - - host example myapp_user 10.0.0.0/8 scram-sha-256 - pg_ident_conf: - - ssl_users CN=alice,O=example alice - port: 5432 - postgres_version: "17.6" - postgresql_conf: - max_connections: 1000 - restore_config: - repository: - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - restore_options: - set: 20250505-153628F - target: "123456" - type: xid - source_database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - source_database_name: northwind - source_node_name: n1 - source_node: n1 + spock_version: "6" minItems: 1 maxItems: 9 orchestrator_opts: @@ -11220,7 +12505,7 @@ components: type: array items: type: string - example: Quo perferendis et qui. + example: Dignissimos voluptas vel earum eaque. description: Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these. example: - hostssl all myapp_user 203.0.113.0/24 scram-sha-256 @@ -11229,7 +12514,7 @@ components: type: array items: type: string - example: Quaerat rem. + example: Et minima ipsum ut impedit. description: Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames. example: - ssl_users CN=alice,O=example alice @@ -11683,6 +12968,135 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" + - backup_config: + repositories: + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + schedules: + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + cpus: 500m + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 500M + name: n1 + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Incidunt in quas totam. + patroni_port: 8888 + pg_hba_conf: + - host example myapp_user 10.0.0.0/8 scram-sha-256 + pg_ident_conf: + - ssl_users CN=alice,O=example alice + port: 5432 + postgres_version: "17.6" + postgresql_conf: + max_connections: 1000 + restore_config: + repository: + azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + restore_options: + set: 20250505-153628F + target: "123456" + type: xid + source_database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + source_database_name: northwind + source_node_name: n1 + source_node: n1 + spock_version: "6" - backup_config: repositories: - azure_account: pgedge-backups @@ -11810,6 +13224,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" orchestrator_opts: swarm: extra_labels: @@ -12284,6 +13699,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" - backup_config: repositories: - azure_account: pgedge-backups @@ -12411,6 +13827,987 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" + minItems: 1 + maxItems: 9 + orchestrator_opts: + $ref: '#/components/schemas/OrchestratorOpts' + patroni_port: + type: integer + description: 'The port used by Patroni for this database. If the port is 0, each instance will be assigned a random port. NOTE: This field is not currently supported for Docker Swarm.' + example: 8888 + format: int64 + minimum: 0 + maximum: 65535 + pg_hba_conf: + type: array + items: + type: string + example: Dolorum natus sunt harum magnam sunt. + description: Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these. + example: + - hostssl all myapp_user 203.0.113.0/24 scram-sha-256 + - hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users + pg_ident_conf: + type: array + items: + type: string + example: In veniam officia ratione. + description: Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames. + example: + - ssl_users CN=alice,O=example alice + port: + type: integer + description: The port used by the Postgres database. If the port is 0, each instance will be assigned a random port. If the port is unspecified, the database will not be exposed on any port, dependent on orchestrator support for that feature. + example: 5432 + format: int64 + minimum: 0 + maximum: 65535 + postgres_version: + type: string + description: The Postgres version in 'major.minor' format. + example: "17.6" + pattern: ^\d{2}\.\d{1,2}$ + postgresql_conf: + type: object + description: Additional postgresql.conf settings. Will be merged with the settings provided by control-plane. + example: + max_connections: 1000 + maxLength: 64 + additionalProperties: true + restore_config: + $ref: '#/components/schemas/RestoreConfigSpec' + scripts: + $ref: '#/components/schemas/DatabaseScripts' + services: + type: array + items: + $ref: '#/components/schemas/ServiceSpec4' + description: Service instances to run alongside the database (e.g., MCP servers). + example: + - config: + llm_model: gpt-4 + llm_provider: openai + openai_api_key: sk-... + connect_as: app + cpus: 500m + database_connection: + target_nodes: + - n1 + - n2 + target_session_attrs: primary + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 512M + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Incidunt in quas totam. + port: 0 + service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + service_type: rag + version: latest + - config: + llm_model: gpt-4 + llm_provider: openai + openai_api_key: sk-... + connect_as: app + cpus: 500m + database_connection: + target_nodes: + - n1 + - n2 + target_session_attrs: primary + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 512M + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Incidunt in quas totam. + port: 0 + service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + service_type: rag + version: latest + spock_version: + type: string + description: The major version of the Spock extension. + example: "5" + pattern: ^\d{1}$ + example: + backup_config: + repositories: + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + schedules: + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + cpus: 500m + database_name: northwind + database_users: + - attributes: + - LOGIN + - CREATEDB + - CREATEROLE + db_owner: false + password: secret + roles: + - pgedge_superuser + username: admin + - attributes: + - LOGIN + - CREATEDB + - CREATEROLE + db_owner: false + password: secret + roles: + - pgedge_superuser + username: admin + - attributes: + - LOGIN + - CREATEDB + - CREATEROLE + db_owner: false + password: secret + roles: + - pgedge_superuser + username: admin + memory: 500M + nodes: + - backup_config: + repositories: + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + schedules: + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + cpus: 500m + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 500M + name: n1 + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Incidunt in quas totam. + patroni_port: 8888 + pg_hba_conf: + - host example myapp_user 10.0.0.0/8 scram-sha-256 + pg_ident_conf: + - ssl_users CN=alice,O=example alice + port: 5432 + postgres_version: "17.6" + postgresql_conf: + max_connections: 1000 + restore_config: + repository: + azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + restore_options: + set: 20250505-153628F + target: "123456" + type: xid + source_database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + source_database_name: northwind + source_node_name: n1 + source_node: n1 + spock_version: "6" + - backup_config: + repositories: + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + schedules: + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + cpus: 500m + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 500M + name: n1 + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Incidunt in quas totam. + patroni_port: 8888 + pg_hba_conf: + - host example myapp_user 10.0.0.0/8 scram-sha-256 + pg_ident_conf: + - ssl_users CN=alice,O=example alice + port: 5432 + postgres_version: "17.6" + postgresql_conf: + max_connections: 1000 + restore_config: + repository: + azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + restore_options: + set: 20250505-153628F + target: "123456" + type: xid + source_database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + source_database_name: northwind + source_node_name: n1 + source_node: n1 + spock_version: "6" + - backup_config: + repositories: + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + schedules: + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + cpus: 500m + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 500M + name: n1 + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Incidunt in quas totam. + patroni_port: 8888 + pg_hba_conf: + - host example myapp_user 10.0.0.0/8 scram-sha-256 + pg_ident_conf: + - ssl_users CN=alice,O=example alice + port: 5432 + postgres_version: "17.6" + postgresql_conf: + max_connections: 1000 + restore_config: + repository: + azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + restore_options: + set: 20250505-153628F + target: "123456" + type: xid + source_database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + source_database_name: northwind + source_node_name: n1 + source_node: n1 + spock_version: "6" + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Incidunt in quas totam. + patroni_port: 8888 + pg_hba_conf: + - hostssl all myapp_user 203.0.113.0/24 scram-sha-256 + - hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users + pg_ident_conf: + - ssl_users CN=alice,O=example alice + port: 5432 + postgres_version: "17.6" + postgresql_conf: + max_connections: 1000 + restore_config: + repository: + azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + restore_options: + set: 20250505-153628F + target: "123456" + type: xid + source_database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + source_database_name: northwind + source_node_name: n1 + scripts: + post_database_create: + - ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app + - ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app + - ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app + post_init: + - ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT USAGE ON SCHEMAS TO app + - ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON TABLES TO app + - ALTER DEFAULT PRIVILEGES FOR ROLE admin GRANT ALL PRIVILEGES ON SEQUENCES TO app + services: + - config: + llm_model: gpt-4 + llm_provider: openai + openai_api_key: sk-... + connect_as: app + cpus: 500m + database_connection: + target_nodes: + - n1 + - n2 + target_session_attrs: primary + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 512M + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Incidunt in quas totam. + port: 0 + service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + service_type: rag + version: latest + - config: + llm_model: gpt-4 + llm_provider: openai + openai_api_key: sk-... + connect_as: app + cpus: 500m + database_connection: + target_nodes: + - n1 + - n2 + target_session_attrs: primary + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 512M + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Incidunt in quas totam. + port: 0 + service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + service_type: rag + version: latest + - config: + llm_model: gpt-4 + llm_provider: openai + openai_api_key: sk-... + connect_as: app + cpus: 500m + database_connection: + target_nodes: + - n1 + - n2 + target_session_attrs: primary + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 512M + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Incidunt in quas totam. + port: 0 + service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + service_type: rag + version: latest + - config: + llm_model: gpt-4 + llm_provider: openai + openai_api_key: sk-... + connect_as: app + cpus: 500m + database_connection: + target_nodes: + - n1 + - n2 + target_session_attrs: primary + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 512M + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Incidunt in quas totam. + port: 0 + service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + service_type: rag + version: latest + spock_version: "5" + required: + - database_name + - nodes + DatabaseSpec5: + type: object + properties: + backup_config: + $ref: '#/components/schemas/BackupConfigSpec' + cpus: + type: string + description: The number of CPUs to allocate for the database and to use for tuning Postgres. Defaults to the number of available CPUs on the host. Can include an SI suffix, e.g. '500m' for 500 millicpus. Whether this limit is enforced depends on the orchestrator. + example: 500m + pattern: ^[0-9]+(\.[0-9]{1,3}|m)?$ + database_name: + type: string + description: The name of the Postgres database. + example: northwind + minLength: 1 + maxLength: 31 + database_users: + type: array + items: + $ref: '#/components/schemas/DatabaseUserSpec' + description: The users to create for this database. + example: + - attributes: + - LOGIN + - CREATEDB + - CREATEROLE + db_owner: true + password: secret + roles: + - pgedge_superuser + username: admin + - attributes: + - LOGIN + - CREATEDB + - CREATEROLE + db_owner: true + password: secret + roles: + - pgedge_superuser + username: admin + - attributes: + - LOGIN + - CREATEDB + - CREATEROLE + db_owner: true + password: secret + roles: + - pgedge_superuser + username: admin + maxItems: 16 + memory: + type: string + description: The amount of memory in SI or IEC notation to allocate for the database and to use for tuning Postgres. Defaults to the total available memory on the host. Whether this limit is enforced depends on the orchestrator. + example: 500M + maxLength: 16 + nodes: + type: array + items: + $ref: '#/components/schemas/DatabaseNodeSpec5' + description: The Spock nodes for this database. + example: - backup_config: repositories: - azure_account: pgedge-backups @@ -12453,6 +14850,26 @@ components: s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY s3_region: us-east-1 type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 schedules: - cron_expression: 0 6 * * ? id: daily-full-backup @@ -12467,7 +14884,6 @@ components: host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 memory: 500M name: n1 orchestrator_opts: @@ -12501,7 +14917,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Incidunt in quas totam. + image: Et odio. patroni_port: 8888 pg_hba_conf: - host example myapp_user 10.0.0.0/8 scram-sha-256 @@ -12538,6 +14954,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" minItems: 1 maxItems: 9 orchestrator_opts: @@ -12553,7 +14970,7 @@ components: type: array items: type: string - example: Tempora in veniam officia ratione minus. + example: Est nisi. description: Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these. example: - hostssl all myapp_user 203.0.113.0/24 scram-sha-256 @@ -12562,7 +14979,7 @@ components: type: array items: type: string - example: Occaecati et et consequuntur. + example: Sit dignissimos ducimus reiciendis asperiores explicabo. description: Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames. example: - ssl_users CN=alice,O=example alice @@ -12592,7 +15009,7 @@ components: services: type: array items: - $ref: '#/components/schemas/ServiceSpec4' + $ref: '#/components/schemas/ServiceSpec5' description: Service instances to run alongside the database (e.g., MCP servers). example: - config: @@ -12641,7 +15058,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Incidunt in quas totam. + image: Et odio. port: 0 service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 service_type: rag @@ -12692,7 +15109,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Incidunt in quas totam. + image: Et odio. port: 0 service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 service_type: rag @@ -12743,7 +15160,58 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Incidunt in quas totam. + image: Et odio. + port: 0 + service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + service_type: rag + version: latest + - config: + llm_model: gpt-4 + llm_provider: openai + openai_api_key: sk-... + connect_as: app + cpus: 500m + database_connection: + target_nodes: + - n1 + - n2 + target_session_attrs: primary + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 512M + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Et odio. port: 0 service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 service_type: rag @@ -12796,6 +15264,26 @@ components: s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY s3_region: us-east-1 type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 schedules: - cron_expression: 0 6 * * ? id: daily-full-backup @@ -12813,7 +15301,7 @@ components: - LOGIN - CREATEDB - CREATEROLE - db_owner: false + db_owner: true password: secret roles: - pgedge_superuser @@ -12822,7 +15310,7 @@ components: - LOGIN - CREATEDB - CREATEROLE - db_owner: false + db_owner: true password: secret roles: - pgedge_superuser @@ -12831,7 +15319,7 @@ components: - LOGIN - CREATEDB - CREATEROLE - db_owner: false + db_owner: true password: secret roles: - pgedge_superuser @@ -12880,113 +15368,6 @@ components: s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY s3_region: us-east-1 type: s3 - schedules: - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - cpus: 500m - host_ids: - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - memory: 500M - name: n1 - orchestrator_opts: - swarm: - extra_labels: - traefik.enable: "true" - traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) - extra_networks: - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - extra_volumes: - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - image: Incidunt in quas totam. - patroni_port: 8888 - pg_hba_conf: - - host example myapp_user 10.0.0.0/8 scram-sha-256 - pg_ident_conf: - - ssl_users CN=alice,O=example alice - port: 5432 - postgres_version: "17.6" - postgresql_conf: - max_connections: 1000 - restore_config: - repository: - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - restore_options: - set: 20250505-153628F - target: "123456" - type: xid - source_database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - source_database_name: northwind - source_node_name: n1 - source_node: n1 - - backup_config: - repositories: - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - azure_account: pgedge-backups azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 azure_endpoint: blob.core.usgovcloudapi.net @@ -13021,7 +15402,6 @@ components: host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 memory: 500M name: n1 orchestrator_opts: @@ -13055,7 +15435,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Incidunt in quas totam. + image: Et odio. patroni_port: 8888 pg_hba_conf: - host example myapp_user 10.0.0.0/8 scram-sha-256 @@ -13092,6 +15472,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" - backup_config: repositories: - azure_account: pgedge-backups @@ -13134,6 +15515,26 @@ components: s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY s3_region: us-east-1 type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 schedules: - cron_expression: 0 6 * * ? id: daily-full-backup @@ -13148,7 +15549,6 @@ components: host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 memory: 500M name: n1 orchestrator_opts: @@ -13182,7 +15582,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Incidunt in quas totam. + image: Et odio. patroni_port: 8888 pg_hba_conf: - host example myapp_user 10.0.0.0/8 scram-sha-256 @@ -13219,6 +15619,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" orchestrator_opts: swarm: extra_labels: @@ -13250,7 +15651,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Incidunt in quas totam. + image: Et odio. patroni_port: 8888 pg_hba_conf: - hostssl all myapp_user 203.0.113.0/24 scram-sha-256 @@ -13343,58 +15744,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Incidunt in quas totam. - port: 0 - service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - service_type: rag - version: latest - - config: - llm_model: gpt-4 - llm_provider: openai - openai_api_key: sk-... - connect_as: app - cpus: 500m - database_connection: - target_nodes: - - n1 - - n2 - target_session_attrs: primary - host_ids: - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - memory: 512M - orchestrator_opts: - swarm: - extra_labels: - traefik.enable: "true" - traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) - extra_networks: - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - extra_volumes: - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - image: Incidunt in quas totam. + image: Et odio. port: 0 service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 service_type: rag @@ -13445,7 +15795,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Incidunt in quas totam. + image: Et odio. port: 0 service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 service_type: rag @@ -13496,7 +15846,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Incidunt in quas totam. + image: Et odio. port: 0 service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 service_type: rag @@ -13505,7 +15855,7 @@ components: required: - database_name - nodes - DatabaseSpec5: + DatabaseSpec6: type: object properties: backup_config: @@ -13531,7 +15881,7 @@ components: - LOGIN - CREATEDB - CREATEROLE - db_owner: true + db_owner: false password: secret roles: - pgedge_superuser @@ -13540,7 +15890,7 @@ components: - LOGIN - CREATEDB - CREATEROLE - db_owner: true + db_owner: false password: secret roles: - pgedge_superuser @@ -13549,7 +15899,7 @@ components: - LOGIN - CREATEDB - CREATEROLE - db_owner: true + db_owner: false password: secret roles: - pgedge_superuser @@ -13563,7 +15913,7 @@ components: nodes: type: array items: - $ref: '#/components/schemas/DatabaseNodeSpec5' + $ref: '#/components/schemas/DatabaseNodeSpec6' description: The Spock nodes for this database. example: - backup_config: @@ -13608,26 +15958,6 @@ components: s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY s3_region: us-east-1 type: s3 - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 schedules: - cron_expression: 0 6 * * ? id: daily-full-backup @@ -13642,6 +15972,7 @@ components: host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 memory: 500M name: n1 orchestrator_opts: @@ -13675,7 +16006,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Et odio. + image: Incidunt in quas totam. patroni_port: 8888 pg_hba_conf: - host example myapp_user 10.0.0.0/8 scram-sha-256 @@ -13712,6 +16043,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" - backup_config: repositories: - azure_account: pgedge-backups @@ -13754,26 +16086,6 @@ components: s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY s3_region: us-east-1 type: s3 - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 schedules: - cron_expression: 0 6 * * ? id: daily-full-backup @@ -13788,6 +16100,7 @@ components: host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 memory: 500M name: n1 orchestrator_opts: @@ -13821,7 +16134,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Et odio. + image: Incidunt in quas totam. patroni_port: 8888 pg_hba_conf: - host example myapp_user 10.0.0.0/8 scram-sha-256 @@ -13858,6 +16171,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" minItems: 1 maxItems: 9 orchestrator_opts: @@ -13873,7 +16187,7 @@ components: type: array items: type: string - example: Iure molestiae. + example: Iste dicta assumenda et. description: Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these. example: - hostssl all myapp_user 203.0.113.0/24 scram-sha-256 @@ -13882,7 +16196,7 @@ components: type: array items: type: string - example: Nesciunt quia quis aut ducimus deserunt. + example: Dolorem aut. description: Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames. example: - ssl_users CN=alice,O=example alice @@ -13912,7 +16226,7 @@ components: services: type: array items: - $ref: '#/components/schemas/ServiceSpec5' + $ref: '#/components/schemas/ServiceSpec6' description: Service instances to run alongside the database (e.g., MCP servers). example: - config: @@ -13961,58 +16275,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Et odio. - port: 0 - service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - service_type: rag - version: latest - - config: - llm_model: gpt-4 - llm_provider: openai - openai_api_key: sk-... - connect_as: app - cpus: 500m - database_connection: - target_nodes: - - n1 - - n2 - target_session_attrs: primary - host_ids: - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - memory: 512M - orchestrator_opts: - swarm: - extra_labels: - traefik.enable: "true" - traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) - extra_networks: - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - extra_volumes: - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - image: Et odio. + image: Incidunt in quas totam. port: 0 service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 service_type: rag @@ -14063,7 +16326,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Et odio. + image: Incidunt in quas totam. port: 0 service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 service_type: rag @@ -14116,26 +16379,6 @@ components: s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY s3_region: us-east-1 type: s3 - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 schedules: - cron_expression: 0 6 * * ? id: daily-full-backup @@ -14153,16 +16396,7 @@ components: - LOGIN - CREATEDB - CREATEROLE - db_owner: true - password: secret - roles: - - pgedge_superuser - username: admin - - attributes: - - LOGIN - - CREATEDB - - CREATEROLE - db_owner: true + db_owner: false password: secret roles: - pgedge_superuser @@ -14171,35 +16405,24 @@ components: - LOGIN - CREATEDB - CREATEROLE - db_owner: true - password: secret - roles: - - pgedge_superuser - username: admin - memory: 500M - nodes: - - backup_config: - repositories: - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 + db_owner: false + password: secret + roles: + - pgedge_superuser + username: admin + - attributes: + - LOGIN + - CREATEDB + - CREATEROLE + db_owner: false + password: secret + roles: + - pgedge_superuser + username: admin + memory: 500M + nodes: + - backup_config: + repositories: - azure_account: pgedge-backups azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 azure_endpoint: blob.core.usgovcloudapi.net @@ -14254,6 +16477,7 @@ components: host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 memory: 500M name: n1 orchestrator_opts: @@ -14287,7 +16511,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Et odio. + image: Incidunt in quas totam. patroni_port: 8888 pg_hba_conf: - host example myapp_user 10.0.0.0/8 scram-sha-256 @@ -14324,6 +16548,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" - backup_config: repositories: - azure_account: pgedge-backups @@ -14366,26 +16591,6 @@ components: s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY s3_region: us-east-1 type: s3 - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 schedules: - cron_expression: 0 6 * * ? id: daily-full-backup @@ -14400,6 +16605,7 @@ components: host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 memory: 500M name: n1 orchestrator_opts: @@ -14433,7 +16639,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Et odio. + image: Incidunt in quas totam. patroni_port: 8888 pg_hba_conf: - host example myapp_user 10.0.0.0/8 scram-sha-256 @@ -14470,6 +16676,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" orchestrator_opts: swarm: extra_labels: @@ -14501,7 +16708,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Et odio. + image: Incidunt in quas totam. patroni_port: 8888 pg_hba_conf: - hostssl all myapp_user 203.0.113.0/24 scram-sha-256 @@ -14594,7 +16801,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Et odio. + image: Incidunt in quas totam. port: 0 service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 service_type: rag @@ -14645,7 +16852,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Et odio. + image: Incidunt in quas totam. port: 0 service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 service_type: rag @@ -14696,7 +16903,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Et odio. + image: Incidunt in quas totam. port: 0 service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 service_type: rag @@ -14739,211 +16946,84 @@ components: - db-alias driver_opts: com.docker.network.endpoint.expose: "true" - id: traefik-public - extra_volumes: - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - image: Et odio. - port: 0 - service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - service_type: rag - version: latest - spock_version: "5" - required: - - database_name - - nodes - DatabaseSpec6: - type: object - properties: - backup_config: - $ref: '#/components/schemas/BackupConfigSpec' - cpus: - type: string - description: The number of CPUs to allocate for the database and to use for tuning Postgres. Defaults to the number of available CPUs on the host. Can include an SI suffix, e.g. '500m' for 500 millicpus. Whether this limit is enforced depends on the orchestrator. - example: 500m - pattern: ^[0-9]+(\.[0-9]{1,3}|m)?$ - database_name: - type: string - description: The name of the Postgres database. - example: northwind - minLength: 1 - maxLength: 31 - database_users: - type: array - items: - $ref: '#/components/schemas/DatabaseUserSpec' - description: The users to create for this database. - example: - - attributes: - - LOGIN - - CREATEDB - - CREATEROLE - db_owner: false - password: secret - roles: - - pgedge_superuser - username: admin - - attributes: - - LOGIN - - CREATEDB - - CREATEROLE - db_owner: false - password: secret - roles: - - pgedge_superuser - username: admin - - attributes: - - LOGIN - - CREATEDB - - CREATEROLE - db_owner: false - password: secret - roles: - - pgedge_superuser - username: admin - maxItems: 16 - memory: - type: string - description: The amount of memory in SI or IEC notation to allocate for the database and to use for tuning Postgres. Defaults to the total available memory on the host. Whether this limit is enforced depends on the orchestrator. - example: 500M - maxLength: 16 - nodes: - type: array - items: - $ref: '#/components/schemas/DatabaseNodeSpec6' - description: The Spock nodes for this database. - example: - - backup_config: - repositories: - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - schedules: - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - cpus: 500m - host_ids: - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - memory: 500M - name: n1 - orchestrator_opts: - swarm: - extra_labels: - traefik.enable: "true" - traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) - extra_networks: - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - extra_volumes: - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - image: Incidunt in quas totam. - patroni_port: 8888 - pg_hba_conf: - - host example myapp_user 10.0.0.0/8 scram-sha-256 - pg_ident_conf: - - ssl_users CN=alice,O=example alice - port: 5432 - postgres_version: "17.6" - postgresql_conf: - max_connections: 1000 - restore_config: - repository: - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - restore_options: - set: 20250505-153628F - target: "123456" - type: xid - source_database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - source_database_name: northwind - source_node_name: n1 - source_node: n1 + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Incidunt in quas totam. + port: 0 + service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + service_type: rag + version: latest + spock_version: "5" + required: + - database_name + - nodes + DatabaseSpec7: + type: object + properties: + backup_config: + $ref: '#/components/schemas/BackupConfigSpec' + cpus: + type: string + description: The number of CPUs to allocate for the database and to use for tuning Postgres. Defaults to the number of available CPUs on the host. Can include an SI suffix, e.g. '500m' for 500 millicpus. Whether this limit is enforced depends on the orchestrator. + example: 500m + pattern: ^[0-9]+(\.[0-9]{1,3}|m)?$ + database_name: + type: string + description: The name of the Postgres database. + example: northwind + minLength: 1 + maxLength: 31 + database_users: + type: array + items: + $ref: '#/components/schemas/DatabaseUserSpec' + description: The users to create for this database. + example: + - attributes: + - LOGIN + - CREATEDB + - CREATEROLE + db_owner: false + password: secret + roles: + - pgedge_superuser + username: admin + - attributes: + - LOGIN + - CREATEDB + - CREATEROLE + db_owner: false + password: secret + roles: + - pgedge_superuser + username: admin + - attributes: + - LOGIN + - CREATEDB + - CREATEROLE + db_owner: false + password: secret + roles: + - pgedge_superuser + username: admin + maxItems: 16 + memory: + type: string + description: The amount of memory in SI or IEC notation to allocate for the database and to use for tuning Postgres. Defaults to the total available memory on the host. Whether this limit is enforced depends on the orchestrator. + example: 500M + maxLength: 16 + nodes: + type: array + items: + $ref: '#/components/schemas/DatabaseNodeSpec7' + description: The Spock nodes for this database. + example: - backup_config: repositories: - azure_account: pgedge-backups @@ -14953,247 +17033,56 @@ components: base_path: /backups custom_options: s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - schedules: - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - cpus: 500m - host_ids: - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - memory: 500M - name: n1 - orchestrator_opts: - swarm: - extra_labels: - traefik.enable: "true" - traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) - extra_networks: - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - extra_volumes: - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - image: Incidunt in quas totam. - patroni_port: 8888 - pg_hba_conf: - - host example myapp_user 10.0.0.0/8 scram-sha-256 - pg_ident_conf: - - ssl_users CN=alice,O=example alice - port: 5432 - postgres_version: "17.6" - postgresql_conf: - max_connections: 1000 - restore_config: - repository: - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - restore_options: - set: 20250505-153628F - target: "123456" - type: xid - source_database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - source_database_name: northwind - source_node_name: n1 - source_node: n1 - minItems: 1 - maxItems: 9 - orchestrator_opts: - $ref: '#/components/schemas/OrchestratorOpts' - patroni_port: - type: integer - description: 'The port used by Patroni for this database. If the port is 0, each instance will be assigned a random port. NOTE: This field is not currently supported for Docker Swarm.' - example: 8888 - format: int64 - minimum: 0 - maximum: 65535 - pg_hba_conf: - type: array - items: - type: string - example: Modi facere est. - description: Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these. - example: - - hostssl all myapp_user 203.0.113.0/24 scram-sha-256 - - hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users - pg_ident_conf: - type: array - items: - type: string - example: Qui excepturi debitis aperiam rerum at. - description: Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames. - example: - - ssl_users CN=alice,O=example alice - port: - type: integer - description: The port used by the Postgres database. If the port is 0, each instance will be assigned a random port. If the port is unspecified, the database will not be exposed on any port, dependent on orchestrator support for that feature. - example: 5432 - format: int64 - minimum: 0 - maximum: 65535 - postgres_version: - type: string - description: The Postgres version in 'major.minor' format. - example: "17.6" - pattern: ^\d{2}\.\d{1,2}$ - postgresql_conf: - type: object - description: Additional postgresql.conf settings. Will be merged with the settings provided by control-plane. - example: - max_connections: 1000 - maxLength: 64 - additionalProperties: true - restore_config: - $ref: '#/components/schemas/RestoreConfigSpec' - scripts: - $ref: '#/components/schemas/DatabaseScripts' - services: - type: array - items: - $ref: '#/components/schemas/ServiceSpec6' - description: Service instances to run alongside the database (e.g., MCP servers). - example: - - config: - llm_model: gpt-4 - llm_provider: openai - openai_api_key: sk-... - connect_as: app + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + schedules: + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full cpus: 500m - database_connection: - target_nodes: - - n1 - - n2 - target_session_attrs: primary host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - 76f9b8c0-4958-11f0-a489-3bb29577c696 - memory: 512M - orchestrator_opts: - swarm: - extra_labels: - traefik.enable: "true" - traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) - extra_networks: - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - extra_volumes: - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - image: Incidunt in quas totam. - port: 0 - service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - service_type: rag - version: latest - - config: - llm_model: gpt-4 - llm_provider: openai - openai_api_key: sk-... - connect_as: app - cpus: 500m - database_connection: - target_nodes: - - n1 - - n2 - target_session_attrs: primary - host_ids: - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - 76f9b8c0-4958-11f0-a489-3bb29577c696 - memory: 512M + memory: 500M + name: n1 orchestrator_opts: swarm: extra_labels: @@ -15226,76 +17115,102 @@ components: - destination_path: /backups/container host_path: /Users/user/backups/host image: Incidunt in quas totam. - port: 0 - service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - service_type: rag - version: latest - - config: - llm_model: gpt-4 - llm_provider: openai - openai_api_key: sk-... - connect_as: app + patroni_port: 8888 + pg_hba_conf: + - host example myapp_user 10.0.0.0/8 scram-sha-256 + pg_ident_conf: + - ssl_users CN=alice,O=example alice + port: 5432 + postgres_version: "17.6" + postgresql_conf: + max_connections: 1000 + restore_config: + repository: + azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + restore_options: + set: 20250505-153628F + target: "123456" + type: xid + source_database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + source_database_name: northwind + source_node_name: n1 + source_node: n1 + spock_version: "6" + - backup_config: + repositories: + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + schedules: + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full cpus: 500m - database_connection: - target_nodes: - - n1 - - n2 - target_session_attrs: primary host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - 76f9b8c0-4958-11f0-a489-3bb29577c696 - memory: 512M - orchestrator_opts: - swarm: - extra_labels: - traefik.enable: "true" - traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) - extra_networks: - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - extra_volumes: - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - image: Incidunt in quas totam. - port: 0 - service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - service_type: rag - version: latest - - config: - llm_model: gpt-4 - llm_provider: openai - openai_api_key: sk-... - connect_as: app - cpus: 500m - database_connection: - target_nodes: - - n1 - - n2 - target_session_attrs: primary - host_ids: - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - 76f9b8c0-4958-11f0-a489-3bb29577c696 - memory: 512M + memory: 500M + name: n1 orchestrator_opts: swarm: extra_labels: @@ -15328,354 +17243,471 @@ components: - destination_path: /backups/container host_path: /Users/user/backups/host image: Incidunt in quas totam. - port: 0 - service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - service_type: rag - version: latest - spock_version: - type: string - description: The major version of the Spock extension. - example: "5" - pattern: ^\d{1}$ - example: - backup_config: - repositories: - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - schedules: - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - cpus: 500m - database_name: northwind - database_users: - - attributes: - - LOGIN - - CREATEDB - - CREATEROLE - db_owner: false - password: secret - roles: - - pgedge_superuser - username: admin - - attributes: - - LOGIN - - CREATEDB - - CREATEROLE - db_owner: false - password: secret - roles: - - pgedge_superuser - username: admin - - attributes: - - LOGIN - - CREATEDB - - CREATEROLE - db_owner: false - password: secret - roles: - - pgedge_superuser - username: admin - memory: 500M - nodes: - - backup_config: - repositories: - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - schedules: - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - cpus: 500m - host_ids: - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - memory: 500M - name: n1 - orchestrator_opts: - swarm: - extra_labels: - traefik.enable: "true" - traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) - extra_networks: - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - extra_volumes: - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - image: Incidunt in quas totam. - patroni_port: 8888 - pg_hba_conf: - - host example myapp_user 10.0.0.0/8 scram-sha-256 - pg_ident_conf: - - ssl_users CN=alice,O=example alice - port: 5432 - postgres_version: "17.6" - postgresql_conf: - max_connections: 1000 - restore_config: - repository: - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - restore_options: - set: 20250505-153628F - target: "123456" - type: xid - source_database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - source_database_name: northwind - source_node_name: n1 - source_node: n1 - - backup_config: - repositories: - - azure_account: pgedge-backups + patroni_port: 8888 + pg_hba_conf: + - host example myapp_user 10.0.0.0/8 scram-sha-256 + pg_ident_conf: + - ssl_users CN=alice,O=example alice + port: 5432 + postgres_version: "17.6" + postgresql_conf: + max_connections: 1000 + restore_config: + repository: + azure_account: pgedge-backups azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 azure_endpoint: blob.core.usgovcloudapi.net azure_key: YXpLZXk= base_path: /backups custom_options: s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 gcs_endpoint: localhost gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 s3_endpoint: s3.us-east-1.amazonaws.com s3_key: AKIAIOSFODNN7EXAMPLE s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY s3_region: us-east-1 type: s3 - - azure_account: pgedge-backups + restore_options: + set: 20250505-153628F + target: "123456" + type: xid + source_database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + source_database_name: northwind + source_node_name: n1 + source_node: n1 + spock_version: "6" + - backup_config: + repositories: + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + schedules: + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + cpus: 500m + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 500M + name: n1 + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Incidunt in quas totam. + patroni_port: 8888 + pg_hba_conf: + - host example myapp_user 10.0.0.0/8 scram-sha-256 + pg_ident_conf: + - ssl_users CN=alice,O=example alice + port: 5432 + postgres_version: "17.6" + postgresql_conf: + max_connections: 1000 + restore_config: + repository: + azure_account: pgedge-backups azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 azure_endpoint: blob.core.usgovcloudapi.net azure_key: YXpLZXk= base_path: /backups custom_options: s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - storage-upload-chunk-size: 5MiB gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 gcs_endpoint: localhost gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - retention_full: 2 - retention_full_type: count s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 s3_endpoint: s3.us-east-1.amazonaws.com s3_key: AKIAIOSFODNN7EXAMPLE s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY s3_region: us-east-1 type: s3 - schedules: - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - - cron_expression: 0 6 * * ? - id: daily-full-backup - type: full - cpus: 500m - host_ids: - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - memory: 500M - name: n1 - orchestrator_opts: - swarm: - extra_labels: - traefik.enable: "true" - traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) - extra_networks: - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - extra_volumes: - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - image: Incidunt in quas totam. - patroni_port: 8888 - pg_hba_conf: - - host example myapp_user 10.0.0.0/8 scram-sha-256 - pg_ident_conf: - - ssl_users CN=alice,O=example alice - port: 5432 - postgres_version: "17.6" - postgresql_conf: - max_connections: 1000 - restore_config: - repository: - azure_account: pgedge-backups - azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - azure_endpoint: blob.core.usgovcloudapi.net - azure_key: YXpLZXk= - base_path: /backups - custom_options: - s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab - gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - gcs_endpoint: localhost - gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== - id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 - s3_endpoint: s3.us-east-1.amazonaws.com - s3_key: AKIAIOSFODNN7EXAMPLE - s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - s3_region: us-east-1 - type: s3 - restore_options: - set: 20250505-153628F - target: "123456" - type: xid - source_database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - source_database_name: northwind - source_node_name: n1 - source_node: n1 + restore_options: + set: 20250505-153628F + target: "123456" + type: xid + source_database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + source_database_name: northwind + source_node_name: n1 + source_node: n1 + spock_version: "6" + minItems: 1 + maxItems: 9 + orchestrator_opts: + $ref: '#/components/schemas/OrchestratorOpts' + patroni_port: + type: integer + description: 'The port used by Patroni for this database. If the port is 0, each instance will be assigned a random port. NOTE: This field is not currently supported for Docker Swarm.' + example: 8888 + format: int64 + minimum: 0 + maximum: 65535 + pg_hba_conf: + type: array + items: + type: string + example: Alias est mollitia. + description: Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these. + example: + - hostssl all myapp_user 203.0.113.0/24 scram-sha-256 + - hostssl all alice 0.0.0.0/0 cert clientcert=verify-full map=ssl_users + pg_ident_conf: + type: array + items: + type: string + example: Possimus id laudantium sed delectus. + description: Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames. + example: + - ssl_users CN=alice,O=example alice + port: + type: integer + description: The port used by the Postgres database. If the port is 0, each instance will be assigned a random port. If the port is unspecified, the database will not be exposed on any port, dependent on orchestrator support for that feature. + example: 5432 + format: int64 + minimum: 0 + maximum: 65535 + postgres_version: + type: string + description: The Postgres version in 'major.minor' format. + example: "17.6" + pattern: ^\d{2}\.\d{1,2}$ + postgresql_conf: + type: object + description: Additional postgresql.conf settings. Will be merged with the settings provided by control-plane. + example: + max_connections: 1000 + maxLength: 64 + additionalProperties: true + restore_config: + $ref: '#/components/schemas/RestoreConfigSpec' + scripts: + $ref: '#/components/schemas/DatabaseScripts' + services: + type: array + items: + $ref: '#/components/schemas/ServiceSpec7' + description: Service instances to run alongside the database (e.g., MCP servers). + example: + - config: + llm_model: gpt-4 + llm_provider: openai + openai_api_key: sk-... + connect_as: app + cpus: 500m + database_connection: + target_nodes: + - n1 + - n2 + target_session_attrs: primary + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 512M + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Incidunt in quas totam. + port: 0 + service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + service_type: rag + version: latest + - config: + llm_model: gpt-4 + llm_provider: openai + openai_api_key: sk-... + connect_as: app + cpus: 500m + database_connection: + target_nodes: + - n1 + - n2 + target_session_attrs: primary + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 512M + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Incidunt in quas totam. + port: 0 + service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + service_type: rag + version: latest + - config: + llm_model: gpt-4 + llm_provider: openai + openai_api_key: sk-... + connect_as: app + cpus: 500m + database_connection: + target_nodes: + - n1 + - n2 + target_session_attrs: primary + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 512M + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Incidunt in quas totam. + port: 0 + service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + service_type: rag + version: latest + spock_version: + type: string + description: The major version of the Spock extension. + example: "5" + pattern: ^\d{1}$ + example: + backup_config: + repositories: + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + schedules: + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + cpus: 500m + database_name: northwind + database_users: + - attributes: + - LOGIN + - CREATEDB + - CREATEROLE + db_owner: false + password: secret + roles: + - pgedge_superuser + username: admin + - attributes: + - LOGIN + - CREATEDB + - CREATEROLE + db_owner: false + password: secret + roles: + - pgedge_superuser + username: admin + - attributes: + - LOGIN + - CREATEDB + - CREATEROLE + db_owner: false + password: secret + roles: + - pgedge_superuser + username: admin + memory: 500M + nodes: - backup_config: repositories: - azure_account: pgedge-backups @@ -15803,6 +17835,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" orchestrator_opts: swarm: extra_labels: @@ -15983,11 +18016,62 @@ components: service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 service_type: rag version: latest + - config: + llm_model: gpt-4 + llm_provider: openai + openai_api_key: sk-... + connect_as: app + cpus: 500m + database_connection: + target_nodes: + - n1 + - n2 + target_session_attrs: primary + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 512M + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Incidunt in quas totam. + port: 0 + service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + service_type: rag + version: latest spock_version: "5" required: - database_name - nodes - DatabaseSpec7: + DatabaseSpec8: type: object properties: backup_config: @@ -16045,7 +18129,7 @@ components: nodes: type: array items: - $ref: '#/components/schemas/DatabaseNodeSpec7' + $ref: '#/components/schemas/DatabaseNodeSpec8' description: The Spock nodes for this database. example: - backup_config: @@ -16175,6 +18259,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" - backup_config: repositories: - azure_account: pgedge-backups @@ -16302,6 +18387,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" - backup_config: repositories: - azure_account: pgedge-backups @@ -16429,6 +18515,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" minItems: 1 maxItems: 9 orchestrator_opts: @@ -16444,7 +18531,7 @@ components: type: array items: type: string - example: Odit placeat quod facere possimus sit. + example: Sed esse id natus aut. description: Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these. example: - hostssl all myapp_user 203.0.113.0/24 scram-sha-256 @@ -16453,7 +18540,7 @@ components: type: array items: type: string - example: In dolor unde optio illo. + example: Minus sint totam et et. description: Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames. example: - ssl_users CN=alice,O=example alice @@ -16483,7 +18570,7 @@ components: services: type: array items: - $ref: '#/components/schemas/ServiceSpec7' + $ref: '#/components/schemas/ServiceSpec8' description: Service instances to run alongside the database (e.g., MCP servers). example: - config: @@ -16856,6 +18943,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" - backup_config: repositories: - azure_account: pgedge-backups @@ -16983,6 +19071,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" - backup_config: repositories: - azure_account: pgedge-backups @@ -17110,6 +19199,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" orchestrator_opts: swarm: extra_labels: @@ -17290,113 +19380,11 @@ components: service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 service_type: rag version: latest - - config: - llm_model: gpt-4 - llm_provider: openai - openai_api_key: sk-... - connect_as: app - cpus: 500m - database_connection: - target_nodes: - - n1 - - n2 - target_session_attrs: primary - host_ids: - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - memory: 512M - orchestrator_opts: - swarm: - extra_labels: - traefik.enable: "true" - traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) - extra_networks: - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - extra_volumes: - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - image: Incidunt in quas totam. - port: 0 - service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - service_type: rag - version: latest - - config: - llm_model: gpt-4 - llm_provider: openai - openai_api_key: sk-... - connect_as: app - cpus: 500m - database_connection: - target_nodes: - - n1 - - n2 - target_session_attrs: primary - host_ids: - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - memory: 512M - orchestrator_opts: - swarm: - extra_labels: - traefik.enable: "true" - traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) - extra_networks: - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - extra_volumes: - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - image: Incidunt in quas totam. - port: 0 - service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - service_type: rag - version: latest spock_version: "5" required: - database_name - nodes - DatabaseSpec8: + DatabaseSpec9: type: object properties: backup_config: @@ -17454,7 +19442,7 @@ components: nodes: type: array items: - $ref: '#/components/schemas/DatabaseNodeSpec8' + $ref: '#/components/schemas/DatabaseNodeSpec9' description: The Spock nodes for this database. example: - backup_config: @@ -17584,6 +19572,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" minItems: 1 maxItems: 9 orchestrator_opts: @@ -17599,7 +19588,7 @@ components: type: array items: type: string - example: Dignissimos voluptates est numquam perspiciatis et. + example: Mollitia illo delectus. description: Additional pg_hba.conf entries, one rule per array element. Inserted between control-plane's system-user rules and its catch-all, so they cannot affect control-plane-internal connectivity (Patroni, replication, health checks). Node-level pg_hba_conf entries are prepended to these. example: - hostssl all myapp_user 203.0.113.0/24 scram-sha-256 @@ -17608,7 +19597,7 @@ components: type: array items: type: string - example: Sequi saepe velit. + example: Aut ducimus aut aut veritatis ut. description: Additional pg_ident.conf entries, one mapping per array element. Purely additive; control-plane writes no pg_ident entries of its own. The primary use case is cert auth with map= translating certificate CNs to PostgreSQL usernames. example: - ssl_users CN=alice,O=example alice @@ -17638,7 +19627,7 @@ components: services: type: array items: - $ref: '#/components/schemas/ServiceSpec8' + $ref: '#/components/schemas/ServiceSpec9' description: Service instances to run alongside the database (e.g., MCP servers). example: - config: @@ -17743,108 +19732,6 @@ components: service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 service_type: rag version: latest - - config: - llm_model: gpt-4 - llm_provider: openai - openai_api_key: sk-... - connect_as: app - cpus: 500m - database_connection: - target_nodes: - - n1 - - n2 - target_session_attrs: primary - host_ids: - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - memory: 512M - orchestrator_opts: - swarm: - extra_labels: - traefik.enable: "true" - traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) - extra_networks: - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - extra_volumes: - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - image: Incidunt in quas totam. - port: 0 - service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - service_type: rag - version: latest - - config: - llm_model: gpt-4 - llm_provider: openai - openai_api_key: sk-... - connect_as: app - cpus: 500m - database_connection: - target_nodes: - - n1 - - n2 - target_session_attrs: primary - host_ids: - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 - memory: 512M - orchestrator_opts: - swarm: - extra_labels: - traefik.enable: "true" - traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) - extra_networks: - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - - aliases: - - pg-db - - db-alias - driver_opts: - com.docker.network.endpoint.expose: "true" - id: traefik-public - extra_volumes: - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - - destination_path: /backups/container - host_path: /Users/user/backups/host - image: Incidunt in quas totam. - port: 0 - service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 - service_type: rag - version: latest spock_version: type: string description: The major version of the Spock extension. @@ -18062,6 +19949,135 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" + - backup_config: + repositories: + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + - azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + storage-upload-chunk-size: 5MiB + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + retention_full: 2 + retention_full_type: count + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + schedules: + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + - cron_expression: 0 6 * * ? + id: daily-full-backup + type: full + cpus: 500m + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 500M + name: n1 + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Incidunt in quas totam. + patroni_port: 8888 + pg_hba_conf: + - host example myapp_user 10.0.0.0/8 scram-sha-256 + pg_ident_conf: + - ssl_users CN=alice,O=example alice + port: 5432 + postgres_version: "17.6" + postgresql_conf: + max_connections: 1000 + restore_config: + repository: + azure_account: pgedge-backups + azure_container: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + azure_endpoint: blob.core.usgovcloudapi.net + azure_key: YXpLZXk= + base_path: /backups + custom_options: + s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab + gcs_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + gcs_endpoint: localhost + gcs_key: ZXhhbXBsZSBnY3Mga2V5Cg== + id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + s3_bucket: pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1 + s3_endpoint: s3.us-east-1.amazonaws.com + s3_key: AKIAIOSFODNN7EXAMPLE + s3_key_secret: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY + s3_region: us-east-1 + type: s3 + restore_options: + set: 20250505-153628F + target: "123456" + type: xid + source_database_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + source_database_name: northwind + source_node_name: n1 + source_node: n1 + spock_version: "6" - backup_config: repositories: - azure_account: pgedge-backups @@ -18189,6 +20205,7 @@ components: source_database_name: northwind source_node_name: n1 source_node: n1 + spock_version: "6" orchestrator_opts: swarm: extra_labels: @@ -18442,6 +20459,9 @@ components: - image: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1 postgres_version: "17.10" spock_version: "5" + - image: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1 + postgres_version: "17.10" + spock_version: "5" created_at: type: string description: The time that the database was created. @@ -18464,15 +20484,15 @@ components: - 10.24.34.2 - i-0123456789abcdef.ec2.internal port: 5432 - created_at: "1984-01-30T10:40:13Z" + created_at: "2011-12-03T04:20:14Z" error: 'failed to get patroni status: connection refused' host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d node_name: n1 postgres: - patroni_paused: true + patroni_paused: false patroni_state: unknown - pending_restart: true + pending_restart: false role: primary version: "18.1" spock: @@ -18487,24 +20507,62 @@ components: - name: sub_n1n2 provider_node: n2 status: down + - name: sub_n1n2 + provider_node: n2 + status: down version: 4.10.0 - state: modifying - status_updated_at: "1976-03-01T20:13:25Z" - updated_at: "1996-05-27T17:04:41Z" + state: stopped + status_updated_at: "1998-03-14T08:14:25Z" + updated_at: "1978-12-17T01:14:06Z" - connection_info: addresses: - 10.24.34.2 - i-0123456789abcdef.ec2.internal port: 5432 - created_at: "1984-01-30T10:40:13Z" + created_at: "2011-12-03T04:20:14Z" error: 'failed to get patroni status: connection refused' host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d node_name: n1 postgres: - patroni_paused: true + patroni_paused: false patroni_state: unknown - pending_restart: true + pending_restart: false + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + version: 4.10.0 + state: stopped + status_updated_at: "1998-03-14T08:14:25Z" + updated_at: "1978-12-17T01:14:06Z" + - connection_info: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + port: 5432 + created_at: "2011-12-03T04:20:14Z" + error: 'failed to get patroni status: connection refused' + host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec + id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d + node_name: n1 + postgres: + patroni_paused: false + patroni_state: unknown + pending_restart: false role: primary version: "18.1" spock: @@ -18519,14 +20577,17 @@ components: - name: sub_n1n2 provider_node: n2 status: down + - name: sub_n1n2 + provider_node: n2 + status: down version: 4.10.0 - state: modifying - status_updated_at: "1976-03-01T20:13:25Z" - updated_at: "1996-05-27T17:04:41Z" + state: stopped + status_updated_at: "1998-03-14T08:14:25Z" + updated_at: "1978-12-17T01:14:06Z" state: type: string description: Current state of the database. - example: creating + example: modifying enum: - creating - modifying @@ -18567,15 +20628,15 @@ components: - 10.24.34.2 - i-0123456789abcdef.ec2.internal port: 5432 - created_at: "1984-01-30T10:40:13Z" + created_at: "2011-12-03T04:20:14Z" error: 'failed to get patroni status: connection refused' host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d node_name: n1 postgres: - patroni_paused: true + patroni_paused: false patroni_state: unknown - pending_restart: true + pending_restart: false role: primary version: "18.1" spock: @@ -18590,24 +20651,27 @@ components: - name: sub_n1n2 provider_node: n2 status: down + - name: sub_n1n2 + provider_node: n2 + status: down version: 4.10.0 - state: modifying - status_updated_at: "1976-03-01T20:13:25Z" - updated_at: "1996-05-27T17:04:41Z" + state: stopped + status_updated_at: "1998-03-14T08:14:25Z" + updated_at: "1978-12-17T01:14:06Z" - connection_info: addresses: - 10.24.34.2 - i-0123456789abcdef.ec2.internal port: 5432 - created_at: "1984-01-30T10:40:13Z" + created_at: "2011-12-03T04:20:14Z" error: 'failed to get patroni status: connection refused' host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d node_name: n1 postgres: - patroni_paused: true + patroni_paused: false patroni_state: unknown - pending_restart: true + pending_restart: false role: primary version: "18.1" spock: @@ -18622,24 +20686,27 @@ components: - name: sub_n1n2 provider_node: n2 status: down + - name: sub_n1n2 + provider_node: n2 + status: down version: 4.10.0 - state: modifying - status_updated_at: "1976-03-01T20:13:25Z" - updated_at: "1996-05-27T17:04:41Z" + state: stopped + status_updated_at: "1998-03-14T08:14:25Z" + updated_at: "1978-12-17T01:14:06Z" - connection_info: addresses: - 10.24.34.2 - i-0123456789abcdef.ec2.internal port: 5432 - created_at: "1984-01-30T10:40:13Z" + created_at: "2011-12-03T04:20:14Z" error: 'failed to get patroni status: connection refused' host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d node_name: n1 postgres: - patroni_paused: true + patroni_paused: false patroni_state: unknown - pending_restart: true + pending_restart: false role: primary version: "18.1" spock: @@ -18654,24 +20721,27 @@ components: - name: sub_n1n2 provider_node: n2 status: down + - name: sub_n1n2 + provider_node: n2 + status: down version: 4.10.0 - state: modifying - status_updated_at: "1976-03-01T20:13:25Z" - updated_at: "1996-05-27T17:04:41Z" + state: stopped + status_updated_at: "1998-03-14T08:14:25Z" + updated_at: "1978-12-17T01:14:06Z" - connection_info: addresses: - 10.24.34.2 - i-0123456789abcdef.ec2.internal port: 5432 - created_at: "1984-01-30T10:40:13Z" + created_at: "2011-12-03T04:20:14Z" error: 'failed to get patroni status: connection refused' host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d node_name: n1 postgres: - patroni_paused: true + patroni_paused: false patroni_state: unknown - pending_restart: true + pending_restart: false role: primary version: "18.1" spock: @@ -18686,11 +20756,14 @@ components: - name: sub_n1n2 provider_node: n2 status: down + - name: sub_n1n2 + provider_node: n2 + status: down version: 4.10.0 - state: modifying - status_updated_at: "1976-03-01T20:13:25Z" - updated_at: "1996-05-27T17:04:41Z" - state: available + state: stopped + status_updated_at: "1998-03-14T08:14:25Z" + updated_at: "1978-12-17T01:14:06Z" + state: unknown tenant_id: 8210ec10-2dca-406c-ac4a-0661d2189954 updated_at: "2025-01-01T02:30:00Z" required: @@ -18705,7 +20778,7 @@ components: type: array items: type: string - example: Autem eum et et eius at praesentium. + example: Eum et et eius at. description: The attributes to assign to this database user. example: - LOGIN @@ -18715,7 +20788,7 @@ components: db_owner: type: boolean description: If true, this user will be granted database ownership. - example: false + example: true password: type: string description: The password for this database user. This field will be excluded from the response of all endpoints. It can also be omitted from update requests to keep the current value. @@ -18725,7 +20798,7 @@ components: type: array items: type: string - example: Dolorem sapiente placeat illo dolore totam accusamus. + example: Ut dolorem. description: The roles to assign to this database user. example: - pgedge_superuser @@ -18768,7 +20841,7 @@ components: type: array items: type: string - example: Voluptates maxime hic aut omnis magnam. + example: Magnam aspernatur. description: The Etcd client endpoint for this cluster member. example: - http://192.168.1.1:2379 @@ -18780,7 +20853,7 @@ components: type: array items: type: string - example: A enim. + example: Maxime hic aut. description: The Etcd peer endpoint for this cluster member. example: - http://192.168.1.1:2380 @@ -18801,7 +20874,7 @@ components: type: array items: type: string - example: Quia non atque facilis non modi. + example: Ut possimus error. description: Optional network-scoped aliases for the container. example: - pg-db @@ -18814,7 +20887,7 @@ components: com.docker.network.endpoint.expose: "true" additionalProperties: type: string - example: Illum alias qui et. + example: Recusandae similique sed neque eos rerum. id: type: string description: The name or ID of the network to connect to. @@ -18876,7 +20949,7 @@ components: candidate_instance_id: 68f50878-44d2-4524-a823-e31bd478706d-n1-689qacsi database_id: my-app node_name: n1 - skip_validation: false + skip_validation: true required: - database_id - node_name @@ -18944,7 +21017,7 @@ components: type: array items: type: string - example: Consequuntur reprehenderit esse id labore. + example: Iure quisquam. description: The addresses that this host advertises to client applications. example: - 10.24.34.2 @@ -18987,7 +21060,7 @@ components: type: array items: type: string - example: Veritatis et omnis non. + example: Quibusdam quis ipsa nihil facere ad. description: The addresses that this host advertises to other hosts. example: - 10.24.34.2 @@ -19004,8 +21077,6 @@ components: spock_version: "5" - postgres_version: "17.6" spock_version: "5" - - postgres_version: "17.6" - spock_version: "5" example: client_addresses: - 10.24.34.2 @@ -19088,7 +21159,13 @@ components: type: object description: The status of each component of the host. example: - Harum voluptatum nulla commodi quo.: + Illo aut et corporis harum.: + details: + alarms: + - '3: NOSPACE' + error: failed to connect to etcd + healthy: false + Molestiae voluptates laborum.: details: alarms: - '3: NOSPACE' @@ -19111,19 +21188,19 @@ components: format: date-time example: components: - Eius totam dolorem itaque aut aut.: + Commodi quo.: details: alarms: - '3: NOSPACE' error: failed to connect to etcd healthy: false - Nihil facere ad tenetur iure quisquam.: + Facere eius totam.: details: alarms: - '3: NOSPACE' error: failed to connect to etcd healthy: false - Sunt quibusdam quis.: + Itaque aut aut cupiditate.: details: alarms: - '3: NOSPACE' @@ -19155,7 +21232,7 @@ components: created_at: type: string description: The time that the instance was created. - example: "1994-08-08T11:48:05Z" + example: "1994-11-10T04:44:10Z" format: date-time error: type: string @@ -19193,12 +21270,12 @@ components: status_updated_at: type: string description: The time that the instance status information was last updated. - example: "2006-09-13T00:37:13Z" + example: "1994-07-03T05:16:56Z" format: date-time updated_at: type: string description: The time that the instance was last modified. - example: "1970-10-18T00:04:10Z" + example: "2008-07-07T16:22:31Z" format: date-time description: An instance of pgEdge Postgres running on a host. example: @@ -19207,15 +21284,15 @@ components: - 10.24.34.2 - i-0123456789abcdef.ec2.internal port: 5432 - created_at: "1972-11-23T09:23:25Z" + created_at: "2014-04-20T04:34:11Z" error: 'failed to get patroni status: connection refused' host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d node_name: n1 postgres: - patroni_paused: true + patroni_paused: false patroni_state: unknown - pending_restart: true + pending_restart: false role: primary version: "18.1" spock: @@ -19230,10 +21307,13 @@ components: - name: sub_n1n2 provider_node: n2 status: down + - name: sub_n1n2 + provider_node: n2 + status: down version: 4.10.0 - state: creating - status_updated_at: "2005-07-17T23:25:59Z" - updated_at: "1997-05-17T16:59:26Z" + state: backing_up + status_updated_at: "2011-10-12T20:33:23Z" + updated_at: "1994-09-09T06:25:01Z" required: - id - host_id @@ -19248,7 +21328,7 @@ components: type: array items: type: string - example: Eaque eos quos autem perspiciatis. + example: Nesciunt consequuntur reprehenderit esse id. description: The addresses of the host that's running this instance. example: - 10.24.34.2 @@ -19287,9 +21367,9 @@ components: example: "18.1" description: Postgres status information for a pgEdge instance. example: - patroni_paused: true + patroni_paused: false patroni_state: unknown - pending_restart: false + pending_restart: true role: primary version: "18.1" InstanceSpockStatus: @@ -19311,9 +21391,6 @@ components: - name: sub_n1n2 provider_node: n2 status: down - - name: sub_n1n2 - provider_node: n2 - status: down version: type: string description: The version of Spock for this instance. @@ -19382,6 +21459,14 @@ components: status: completed task_id: 019783f4-75f4-71e7-85a3-c9b96b345d77 type: create + - completed_at: "2025-06-18T16:52:35Z" + created_at: "2025-06-18T16:52:05Z" + database_id: storefront + entity_id: storefront + scope: database + status: completed + task_id: 019783f4-75f4-71e7-85a3-c9b96b345d77 + type: create example: tasks: - completed_at: "2025-06-18T17:54:36Z" @@ -19449,15 +21534,85 @@ components: - 10.24.34.2 - i-0123456789abcdef.ec2.internal port: 5432 - created_at: "1984-01-30T10:40:13Z" + created_at: "2011-12-03T04:20:14Z" + error: 'failed to get patroni status: connection refused' + host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec + id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d + node_name: n1 + postgres: + patroni_paused: false + patroni_state: unknown + pending_restart: false + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + version: 4.10.0 + state: stopped + status_updated_at: "1998-03-14T08:14:25Z" + updated_at: "1978-12-17T01:14:06Z" + - connection_info: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + port: 5432 + created_at: "2011-12-03T04:20:14Z" + error: 'failed to get patroni status: connection refused' + host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec + id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d + node_name: n1 + postgres: + patroni_paused: false + patroni_state: unknown + pending_restart: false + role: primary + version: "18.1" + spock: + read_only: "off" + subscriptions: + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + - name: sub_n1n2 + provider_node: n2 + status: down + version: 4.10.0 + state: stopped + status_updated_at: "1998-03-14T08:14:25Z" + updated_at: "1978-12-17T01:14:06Z" + - connection_info: + addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + port: 5432 + created_at: "2011-12-03T04:20:14Z" error: 'failed to get patroni status: connection refused' host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d node_name: n1 postgres: - patroni_paused: true + patroni_paused: false patroni_state: unknown - pending_restart: true + pending_restart: false role: primary version: "18.1" spock: @@ -19472,24 +21627,27 @@ components: - name: sub_n1n2 provider_node: n2 status: down + - name: sub_n1n2 + provider_node: n2 + status: down version: 4.10.0 - state: modifying - status_updated_at: "1976-03-01T20:13:25Z" - updated_at: "1996-05-27T17:04:41Z" + state: stopped + status_updated_at: "1998-03-14T08:14:25Z" + updated_at: "1978-12-17T01:14:06Z" - connection_info: addresses: - 10.24.34.2 - i-0123456789abcdef.ec2.internal port: 5432 - created_at: "1984-01-30T10:40:13Z" + created_at: "2011-12-03T04:20:14Z" error: 'failed to get patroni status: connection refused' host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d node_name: n1 postgres: - patroni_paused: true + patroni_paused: false patroni_state: unknown - pending_restart: true + pending_restart: false role: primary version: "18.1" spock: @@ -19504,11 +21662,14 @@ components: - name: sub_n1n2 provider_node: n2 status: down + - name: sub_n1n2 + provider_node: n2 + status: down version: 4.10.0 - state: modifying - status_updated_at: "1976-03-01T20:13:25Z" - updated_at: "1996-05-27T17:04:41Z" - state: backing_up + state: stopped + status_updated_at: "1998-03-14T08:14:25Z" + updated_at: "1978-12-17T01:14:06Z" + state: degraded tenant_id: 8210ec10-2dca-406c-ac4a-0661d2189954 updated_at: "2025-01-01T02:30:00Z" - available_upgrades: @@ -19532,15 +21693,15 @@ components: - 10.24.34.2 - i-0123456789abcdef.ec2.internal port: 5432 - created_at: "1984-01-30T10:40:13Z" + created_at: "2011-12-03T04:20:14Z" error: 'failed to get patroni status: connection refused' host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d node_name: n1 postgres: - patroni_paused: true + patroni_paused: false patroni_state: unknown - pending_restart: true + pending_restart: false role: primary version: "18.1" spock: @@ -19555,24 +21716,27 @@ components: - name: sub_n1n2 provider_node: n2 status: down + - name: sub_n1n2 + provider_node: n2 + status: down version: 4.10.0 - state: modifying - status_updated_at: "1976-03-01T20:13:25Z" - updated_at: "1996-05-27T17:04:41Z" + state: stopped + status_updated_at: "1998-03-14T08:14:25Z" + updated_at: "1978-12-17T01:14:06Z" - connection_info: addresses: - 10.24.34.2 - i-0123456789abcdef.ec2.internal port: 5432 - created_at: "1984-01-30T10:40:13Z" + created_at: "2011-12-03T04:20:14Z" error: 'failed to get patroni status: connection refused' host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d node_name: n1 postgres: - patroni_paused: true + patroni_paused: false patroni_state: unknown - pending_restart: true + pending_restart: false role: primary version: "18.1" spock: @@ -19587,43 +21751,27 @@ components: - name: sub_n1n2 provider_node: n2 status: down + - name: sub_n1n2 + provider_node: n2 + status: down version: 4.10.0 - state: modifying - status_updated_at: "1976-03-01T20:13:25Z" - updated_at: "1996-05-27T17:04:41Z" - state: backing_up - tenant_id: 8210ec10-2dca-406c-ac4a-0661d2189954 - updated_at: "2025-01-01T02:30:00Z" - - available_upgrades: - - image: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1 - postgres_version: "17.10" - spock_version: "5" - - image: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1 - postgres_version: "17.10" - spock_version: "5" - - image: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1 - postgres_version: "17.10" - spock_version: "5" - - image: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.9-standard-1 - postgres_version: "17.10" - spock_version: "5" - created_at: "2025-01-01T01:30:00Z" - id: 02f1a7db-fca8-4521-b57a-2a375c1ced51 - instances: + state: stopped + status_updated_at: "1998-03-14T08:14:25Z" + updated_at: "1978-12-17T01:14:06Z" - connection_info: addresses: - 10.24.34.2 - i-0123456789abcdef.ec2.internal port: 5432 - created_at: "1984-01-30T10:40:13Z" + created_at: "2011-12-03T04:20:14Z" error: 'failed to get patroni status: connection refused' host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d node_name: n1 postgres: - patroni_paused: true + patroni_paused: false patroni_state: unknown - pending_restart: true + pending_restart: false role: primary version: "18.1" spock: @@ -19638,24 +21786,27 @@ components: - name: sub_n1n2 provider_node: n2 status: down + - name: sub_n1n2 + provider_node: n2 + status: down version: 4.10.0 - state: modifying - status_updated_at: "1976-03-01T20:13:25Z" - updated_at: "1996-05-27T17:04:41Z" + state: stopped + status_updated_at: "1998-03-14T08:14:25Z" + updated_at: "1978-12-17T01:14:06Z" - connection_info: addresses: - 10.24.34.2 - i-0123456789abcdef.ec2.internal port: 5432 - created_at: "1984-01-30T10:40:13Z" + created_at: "2011-12-03T04:20:14Z" error: 'failed to get patroni status: connection refused' host_id: de3b1388-1f0c-42f1-a86c-59ab72f255ec id: a67cbb36-c3c3-49c9-8aac-f4a0438a883d node_name: n1 postgres: - patroni_paused: true + patroni_paused: false patroni_state: unknown - pending_restart: true + pending_restart: false role: primary version: "18.1" spock: @@ -19670,11 +21821,14 @@ components: - name: sub_n1n2 provider_node: n2 status: down + - name: sub_n1n2 + provider_node: n2 + status: down version: 4.10.0 - state: modifying - status_updated_at: "1976-03-01T20:13:25Z" - updated_at: "1996-05-27T17:04:41Z" - state: backing_up + state: stopped + status_updated_at: "1998-03-14T08:14:25Z" + updated_at: "1978-12-17T01:14:06Z" + state: degraded tenant_id: 8210ec10-2dca-406c-ac4a-0661d2189954 updated_at: "2025-01-01T02:30:00Z" example: @@ -19872,6 +22026,22 @@ components: status: completed task_id: 019783f4-75f4-71e7-85a3-c9b96b345d77 type: create + - completed_at: "2025-06-18T16:52:35Z" + created_at: "2025-06-18T16:52:05Z" + database_id: storefront + entity_id: storefront + scope: database + status: completed + task_id: 019783f4-75f4-71e7-85a3-c9b96b345d77 + type: create + - completed_at: "2025-06-18T16:52:35Z" + created_at: "2025-06-18T16:52:05Z" + database_id: storefront + entity_id: storefront + scope: database + status: completed + task_id: 019783f4-75f4-71e7-85a3-c9b96b345d77 + type: create example: tasks: - completed_at: "2025-06-18T17:54:36Z" @@ -20019,6 +22189,48 @@ components: spock_version: "5" - postgres_version: "17.6" spock_version: "5" + - client_addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + cohort: + control_available: true + member_id: lah4bsznw6kc0hp7biylmmmll + type: swarm + cpus: 4 + data_dir: /data + default_pgedge_version: + postgres_version: "17.6" + spock_version: "5" + etcd_mode: server + id: de3b1388-1f0c-42f1-a86c-59ab72f255ec + memory: 16GiB + orchestrator: swarm + peer_addresses: + - 10.24.34.2 + - i-0123456789abcdef.ec2.internal + status: + components: + Enim et voluptatum ex ea dolore.: + details: + alarms: + - '3: NOSPACE' + error: failed to connect to etcd + healthy: false + Tenetur nostrum repellendus sint qui.: + details: + alarms: + - '3: NOSPACE' + error: failed to connect to etcd + healthy: false + state: available + updated_at: "2021-07-01T12:34:56Z" + supported_pgedge_versions: + - postgres_version: "17.6" + spock_version: "5" + - postgres_version: "17.6" + spock_version: "5" + - postgres_version: "17.6" + spock_version: "5" description: Response containing the list of hosts example: hosts: @@ -20191,7 +22403,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Animi recusandae. + image: Sapiente qui ullam. PgEdgeVersion: type: object properties: @@ -20307,6 +22519,14 @@ components: status: completed task_id: 019783f4-75f4-71e7-85a3-c9b96b345d77 type: create + - completed_at: "2025-06-18T16:52:35Z" + created_at: "2025-06-18T16:52:05Z" + database_id: storefront + entity_id: storefront + scope: database + status: completed + task_id: 019783f4-75f4-71e7-85a3-c9b96b345d77 + type: create required: - task - update_database_tasks @@ -20343,7 +22563,7 @@ components: maxLength: 32 additionalProperties: type: string - example: Eos aut dignissimos cum voluptate modi consequatur. + example: Minus dolore eos et sunt culpa animi. source_database_id: type: string description: A user-specified identifier. Must be 1-36 characters, contain only lower-cased letters and hyphens, start and end with a letter or number, and not contain consecutive hyphens. @@ -20401,7 +22621,7 @@ components: type: array items: type: string - example: Error eligendi recusandae similique sed neque eos. + example: Modi consequatur non at. description: The nodes to restore. Defaults to all nodes if empty or unspecified. example: - n1 @@ -20589,7 +22809,7 @@ components: type: object properties: database: - $ref: '#/components/schemas/Database6' + $ref: '#/components/schemas/Database7' node_tasks: type: array items: @@ -20806,7 +23026,7 @@ components: s3-kms-key-id: 1234abcd-12ab-34cd-56ef-1234567890ab additionalProperties: type: string - example: Dolor quam aliquid cupiditate. + example: Rem culpa. gcs_bucket: type: string description: The GCS bucket name for this repository. Only applies when type = 'gcs'. @@ -20892,7 +23112,7 @@ components: type: array items: type: string - example: "n" + example: ol minLength: 1 maxLength: 1024 description: Each element of this array is an individual SQL statement. @@ -20975,9 +23195,6 @@ components: - container_port: 8080 host_port: 8080 name: web-client - - container_port: 8080 - host_port: 8080 - name: web-client service_ready: true updated_at: "2025-01-28T10:05:00Z" required: @@ -20995,7 +23212,7 @@ components: type: array items: type: string - example: Dignissimos occaecati cupiditate. + example: Quia laborum tenetur nesciunt et quas. description: The addresses of the host that's running this service instance. example: - 10.24.34.2 @@ -21030,9 +23247,6 @@ components: - container_port: 8080 host_port: 8080 name: web-client - - container_port: 8080 - host_port: 8080 - name: web-client service_ready: type: boolean description: Whether the service is ready to accept requests. @@ -21056,6 +23270,9 @@ components: - container_port: 8080 host_port: 8080 name: web-client + - container_port: 8080 + host_port: 8080 + name: web-client service_ready: true ServiceSpec: type: object @@ -21090,6 +23307,8 @@ components: description: The IDs of the hosts that should run this service. One service instance will be created per host. example: - de3b1388-1f0c-42f1-a86c-59ab72f255ec + - de3b1388-1f0c-42f1-a86c-59ab72f255ec + - de3b1388-1f0c-42f1-a86c-59ab72f255ec minItems: 1 memory: type: string @@ -21138,7 +23357,6 @@ components: target_session_attrs: primary host_ids: - de3b1388-1f0c-42f1-a86c-59ab72f255ec - - de3b1388-1f0c-42f1-a86c-59ab72f255ec memory: 512M orchestrator_opts: swarm: @@ -21171,7 +23389,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Animi recusandae. + image: Sapiente qui ullam. port: 0 service_id: analytics-service service_type: rag @@ -21214,6 +23432,7 @@ components: description: The IDs of the hosts that should run this service. One service instance will be created per host. example: - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 minItems: 1 memory: type: string @@ -21263,7 +23482,6 @@ components: host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 memory: 512M orchestrator_opts: swarm: @@ -21388,6 +23606,7 @@ components: host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 memory: 512M orchestrator_opts: swarm: @@ -21589,6 +23808,7 @@ components: example: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 minItems: 1 memory: type: string @@ -21713,7 +23933,6 @@ components: description: The IDs of the hosts that should run this service. One service instance will be created per host. example: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 minItems: 1 memory: type: string @@ -21839,6 +24058,130 @@ components: description: The IDs of the hosts that should run this service. One service instance will be created per host. example: - 76f9b8c0-4958-11f0-a489-3bb29577c696 + minItems: 1 + memory: + type: string + description: The amount of memory in SI or IEC notation to allocate for this service. Defaults to container defaults if unspecified. + example: 512M + maxLength: 16 + orchestrator_opts: + $ref: '#/components/schemas/OrchestratorOpts' + port: + type: integer + description: The port to publish the service on the host. If 0, Docker assigns a random port. If unspecified, no port is published and the service is not accessible from outside the Docker network. + example: 0 + format: int64 + minimum: 0 + maximum: 65535 + service_id: + type: string + description: The unique identifier for this service. + example: 76f9b8c0-4958-11f0-a489-3bb29577c696 + minLength: 1 + maxLength: 36 + service_type: + type: string + description: The type of service to run. + example: rag + enum: + - mcp + - postgrest + - rag + version: + type: string + description: The version of the service (e.g., '1.0.0', '14.5') or the literal 'latest'. + example: latest + pattern: ^(\d+\.\d+(\.\d+)?|latest)$ + example: + config: + llm_model: gpt-4 + llm_provider: openai + openai_api_key: sk-... + connect_as: app + cpus: 500m + database_connection: + target_nodes: + - n1 + - n2 + target_session_attrs: primary + host_ids: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + memory: 512M + orchestrator_opts: + swarm: + extra_labels: + traefik.enable: "true" + traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) + extra_networks: + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + - aliases: + - pg-db + - db-alias + driver_opts: + com.docker.network.endpoint.expose: "true" + id: traefik-public + extra_volumes: + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + - destination_path: /backups/container + host_path: /Users/user/backups/host + image: Incidunt in quas totam. + port: 0 + service_id: 76f9b8c0-4958-11f0-a489-3bb29577c696 + service_type: rag + version: latest + required: + - service_id + - service_type + - version + - host_ids + - connect_as + ServiceSpec8: + type: object + properties: + config: + type: object + description: Service-specific configuration. For MCP services, this includes llm_provider, llm_model, and provider-specific API keys. + example: + llm_model: gpt-4 + llm_provider: openai + openai_api_key: sk-... + additionalProperties: true + connect_as: + type: string + description: Username of the database_users entry this service connects as. The user must exist in database_users and have appropriate roles for the service's needs. + example: app + cpus: + type: string + description: The number of CPUs to allocate for this service. It can include the SI suffix 'm', e.g. '500m' for 500 millicpus. Defaults to container defaults if unspecified. + example: 500m + pattern: ^[0-9]+(\.[0-9]{1,3}|m)?$ + database_connection: + $ref: '#/components/schemas/DatabaseConnection' + host_ids: + type: array + items: + type: string + example: 76f9b8c0-4958-11f0-a489-3bb29577c696 + minLength: 1 + maxLength: 36 + description: The IDs of the hosts that should run this service. One service instance will be created per host. + example: + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 - 76f9b8c0-4958-11f0-a489-3bb29577c696 minItems: 1 memory: @@ -21933,7 +24276,7 @@ components: - version - host_ids - connect_as - ServiceSpec8: + ServiceSpec9: type: object properties: config: @@ -21966,6 +24309,7 @@ components: example: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 minItems: 1 memory: type: string @@ -22015,7 +24359,6 @@ components: host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 - 76f9b8c0-4958-11f0-a489-3bb29577c696 - - 76f9b8c0-4958-11f0-a489-3bb29577c696 memory: 512M orchestrator_opts: swarm: @@ -22106,7 +24449,7 @@ components: traefik.tcp.routers.mydb.rule: HostSNI(`mydb.example.com`) additionalProperties: type: string - example: Veritatis quo recusandae quibusdam fuga. + example: Facilis non modi explicabo illum. extra_networks: type: array items: @@ -22148,7 +24491,7 @@ components: image: type: string description: User-specified container image override. Bypasses manifest version constraints entirely — the CP will deploy this image without validating it against the version manifest. The CP verifies the image exists in its registry before accepting the spec. Clearing this field causes the CP to fall back to the manifest-resolved image on the next reconcile. - example: Repellat quas nostrum eos. + example: Qui et eius reiciendis accusamus. description: Docker Swarm-specific options. example: extra_labels: @@ -22180,7 +24523,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Qui ullam qui quam sint iure eum. + image: Quibusdam fuga molestiae repellat quas nostrum. SwitchoverDatabaseNodeRequest: type: object properties: @@ -22356,11 +24699,6 @@ components: status: creating message: task started timestamp: "2025-05-29T15:43:13Z" - - fields: - option.enabled: true - status: creating - message: task started - timestamp: "2025-05-29T15:43:13Z" last_entry_id: type: string description: The ID of the last entry in the task log. diff --git a/changes/unreleased/Added-20260817-090759.yaml b/changes/unreleased/Added-20260817-090759.yaml new file mode 100644 index 00000000..292225ab --- /dev/null +++ b/changes/unreleased/Added-20260817-090759.yaml @@ -0,0 +1,3 @@ +kind: Added +body: Add a dedicated major-version upgrade workflow for rolling a database from Spock 5.x to Spock 6.x one node at a time, independent of the existing patch/minor upgrade path +time: 2026-08-17T09:07:59.436316+05:00 diff --git a/docs/using/upgrade-db.md b/docs/using/upgrade-db.md index d416de1e..c6932b41 100644 --- a/docs/using/upgrade-db.md +++ b/docs/using/upgrade-db.md @@ -238,7 +238,88 @@ asynchronously. and Spock major bucket as the database’s current version, and must be strictly newer than the currently running image. Same-version or downgrade requests are rejected. To upgrade to a different Postgres major version, - see [Major Version Upgrades](#major-version-upgrades). + see [Major Version Upgrades](#major-version-upgrades). To upgrade to a + different Spock major version, see + [Spock Major-Version Upgrades](#spock-major-version-upgrades). + +## Spock Major-Version Upgrades + +The Control Plane supports upgrading a database's Spock extension across a +major version boundary (for example, Spock 5.x to 6.x) through a dedicated +action, separate from both the minor/patch upgrade path above and the +Postgres major-version approach. A Spock major-version change affects the +replication protocol itself, so it's rolled out one node at a time rather +than applied uniformly the way a build-number bump is. + +!!! note "systemd clusters" + + API-driven Spock major-version upgrades are not supported on systemd + clusters. + +To start the upgrade, submit a `POST` request to the +`/v1/databases/{database_id}/upgrade-major` endpoint with the target Spock +version and the image to upgrade to: + +=== "curl" + + ```sh + curl -X POST http://host-3:3000/v1/databases/example/upgrade-major \ + -H 'Content-Type:application/json' \ + --data '{ + "target_spock_version": "6", + "image": "ghcr.io/pgedge/pgedge-postgres:18.4-spock6.0.0-standard-1" + }' + ``` + +The response contains a `task` object (type `major_upgrade`) and the updated +`database` object. Use `task.task_id` to track progress as described in +[Tasks and Logs](./tasks-logs.md). + +By default, nodes are upgraded in the order they appear in the database +spec. To control the order explicitly, include `node_order`, naming every +node in the database exactly once: + +=== "curl" + + ```sh + curl -X POST http://host-3:3000/v1/databases/example/upgrade-major \ + -H 'Content-Type:application/json' \ + --data '{ + "target_spock_version": "6", + "image": "ghcr.io/pgedge/pgedge-postgres:18.4-spock6.0.0-standard-1", + "node_order": ["n3", "n1", "n2"] + }' + ``` + +### How the Upgrade Works + +The Control Plane upgrades one node at a time: it swaps that node's image, +waits for Spock's own extension-update mechanism to bring it onto the new +major version, and confirms the node has actually resumed replicating with +its peers before moving on to the next node. Every node except the one +currently being upgraded remains fully readable and writable throughout — +Spock supports replication between mixed major versions during this +transition window. + +Once every node is on the target version, the database's spec is normalized +back to a single `spock_version` field at the database level. + +!!! note + + The target image must be present in the version manifest at the + requested Spock major version and the same Postgres version as the + database's current version — a Spock major-version upgrade changes + Spock only, not Postgres. Requests to move to the same major version or + to an older one are rejected: Spock cannot be downgraded in place. To + apply a Postgres version change instead, see + [Minor Version Upgrades](#minor-version-upgrades) or + [Major Version Upgrades](#major-version-upgrades) above. + +!!! warning + + As with any major-version upgrade, test this against a non-production + database first, and take a fresh backup before upgrading your production + database. See [Backup and Restore](./backup-restore.md). ## Which Versions Are Available diff --git a/server/internal/api/apiv1/convert.go b/server/internal/api/apiv1/convert.go index 5127fb97..1eb4a367 100644 --- a/server/internal/api/apiv1/convert.go +++ b/server/internal/api/apiv1/convert.go @@ -140,6 +140,7 @@ func databaseNodesToAPI(nodes []*database.Node) []*api.DatabaseNodeSpec { Name: node.Name, HostIds: hostIDs, PostgresVersion: utils.NillablePointerTo(node.PostgresVersion), + SpockVersion: utils.NillablePointerTo(node.SpockVersion), Port: node.Port, PatroniPort: node.PatroniPort, Cpus: utils.NillablePointerTo(humanizeCPUs(node.CPUs)), @@ -564,6 +565,7 @@ func apiToDatabaseNodes(apiNodes []*api.DatabaseNodeSpec) ([]*database.Node, err Name: apiNode.Name, HostIDs: hostIDs, PostgresVersion: utils.FromPointer(apiNode.PostgresVersion), + SpockVersion: utils.FromPointer(apiNode.SpockVersion), Port: apiNode.Port, PatroniPort: apiNode.PatroniPort, CPUs: cpus, diff --git a/server/internal/api/apiv1/post_init_handlers.go b/server/internal/api/apiv1/post_init_handlers.go index 59d01858..20fc342f 100644 --- a/server/internal/api/apiv1/post_init_handlers.go +++ b/server/internal/api/apiv1/post_init_handlers.go @@ -461,6 +461,31 @@ func (s *PostInitHandlers) ApplyUpgrade(ctx context.Context, req *api.ApplyUpgra }, nil } +func (s *PostInitHandlers) ApplyMajorUpgrade(ctx context.Context, req *api.ApplyMajorUpgradePayload) (*api.ApplyMajorUpgradeResponse, error) { + databaseID, err := dbIdentToString(req.DatabaseID) + if err != nil { + return nil, err + } + + result, err := s.dbSvc.ApplyMajorUpgrade(ctx, databaseID, req.Request.TargetSpockVersion, req.Request.Image, req.Request.NodeOrder) + if err != nil { + return nil, apiErr(err) + } + + t, err := s.workflowSvc.UpgradeDatabaseMajorVersion(ctx, result) + if err != nil { + if rollbackErr := s.dbSvc.RollbackApplyMajorUpgrade(ctx, result); rollbackErr != nil { + s.logger.Err(rollbackErr).Msg("failed to roll back major-version upgrade after workflow trigger failure") + } + return nil, apiErr(err) + } + + return &api.ApplyMajorUpgradeResponse{ + Database: databaseToAPI(result.Database), + Task: taskToAPI(t), + }, nil +} + func (s *PostInitHandlers) DeleteDatabase(ctx context.Context, req *api.DeleteDatabasePayload) (*api.DeleteDatabaseResponse, error) { databaseID, err := dbIdentToString(req.DatabaseID) if err != nil { diff --git a/server/internal/api/apiv1/pre_init_handlers.go b/server/internal/api/apiv1/pre_init_handlers.go index 4698c43a..3deb0116 100644 --- a/server/internal/api/apiv1/pre_init_handlers.go +++ b/server/internal/api/apiv1/pre_init_handlers.go @@ -257,6 +257,10 @@ func (s *PreInitHandlers) ApplyUpgrade(ctx context.Context, req *api.ApplyUpgrad return nil, ErrUninitialized } +func (s *PreInitHandlers) ApplyMajorUpgrade(ctx context.Context, req *api.ApplyMajorUpgradePayload) (*api.ApplyMajorUpgradeResponse, error) { + return nil, ErrUninitialized +} + func (s *PreInitHandlers) CancelDatabaseTask(ctx context.Context, req *api.CancelDatabaseTaskPayload) (*api.Task, error) { return nil, ErrUninitialized } diff --git a/server/internal/api/apiv1/validate.go b/server/internal/api/apiv1/validate.go index 78a040ba..78bb66db 100644 --- a/server/internal/api/apiv1/validate.go +++ b/server/internal/api/apiv1/validate.go @@ -282,6 +282,14 @@ func validateNode( memPath := path.Append("memory") errs = append(errs, validateMemory(node.Memory, memPath)...) + if utils.FromPointer(node.SpockVersion) != "" { + errs = append(errs, validation.NewError( + errors.New("spock_version cannot be set per-node through create-database or update-database; "+ + "it is only ever set internally, one node at a time, by the dedicated major-version upgrade action"), + path.Append("spock_version"), + )) + } + seenHostIDs := make(ds.Set[string], len(node.HostIds)) for i, h := range node.HostIds { hostID := string(h) diff --git a/server/internal/api/apiv1/validate_test.go b/server/internal/api/apiv1/validate_test.go index 5f86959b..f6c1c117 100644 --- a/server/internal/api/apiv1/validate_test.go +++ b/server/internal/api/apiv1/validate_test.go @@ -674,6 +674,20 @@ func TestValidateNode(t *testing.T) { `"spock" must be included in shared_preload_libraries`, }, }, + { + name: "invalid per-node spock_version", + orchestrator: config.OrchestratorSwarm, + db: &api.DatabaseSpec{}, + node: &api.DatabaseNodeSpec{ + HostIds: []api.Identifier{ + api.Identifier("host-1"), + }, + SpockVersion: utils.PointerTo("6"), + }, + expected: []string{ + "spock_version cannot be set per-node through create-database or update-database", + }, + }, } { t.Run(tc.name, func(t *testing.T) { err := errors.Join(validateNode(tc.orchestrator, tc.db, tc.node, nil)...) diff --git a/server/internal/database/apply_major_upgrade_test.go b/server/internal/database/apply_major_upgrade_test.go new file mode 100644 index 00000000..0d75a769 --- /dev/null +++ b/server/internal/database/apply_major_upgrade_test.go @@ -0,0 +1,247 @@ +package database_test + +import ( + "errors" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/pgEdge/control-plane/server/internal/database" + "github.com/pgEdge/control-plane/server/internal/ds" +) + +func TestService_ApplyMajorUpgrade(t *testing.T) { + targetImage := "ghcr.io/pgedge/pgedge-postgres:18.4-spock6.0.0-standard-1" + successfulUpgrade := &database.AvailableUpgrade{ + PostgresVersion: "18.4", + SpockVersion: "6", + Image: targetImage, + } + + t.Run("happy path: state set to modifying, spec untouched", func(t *testing.T) { + orch := &stubOrchestrator{ + findMajorUpgradeFn: func(_ *ds.PgEdgeVersion, _, _ string) (*database.AvailableUpgrade, error) { + return successfulUpgrade, nil + }, + } + svc := newTestService(t, orch) + dbID := seedDatabase(t, svc, "18.4") + + result, err := svc.ApplyMajorUpgrade(t.Context(), dbID, "6", targetImage, nil) + require.NoError(t, err) + require.NotNil(t, result) + + assert.Equal(t, database.DatabaseStateAvailable, result.PrevState) + assert.Equal(t, "6", result.TargetSpockVersion) + assert.Equal(t, targetImage, result.Image) + assert.Equal(t, []string{"n1"}, result.NodeOrder) + assert.Equal(t, database.DatabaseStateModifying, result.Database.State) + + // the spec itself must be untouched - the workflow rolls it forward + // one node at a time. + assert.Equal(t, "5", result.Database.Spec.SpockVersion) + }) + + t.Run("returns ErrDatabaseNotFound for unknown id", func(t *testing.T) { + svc := newTestService(t, &stubOrchestrator{}) + _, err := svc.ApplyMajorUpgrade(t.Context(), "no-such-db", "6", targetImage, nil) + assert.True(t, errors.Is(err, database.ErrDatabaseNotFound)) + }) + + t.Run("returns ErrDatabaseNotModifiable when not in modifiable state", func(t *testing.T) { + svc := newTestService(t, &stubOrchestrator{}) + dbID := seedDatabase(t, svc, "18.4") + require.NoError(t, svc.UpdateDatabaseState(t.Context(), dbID, database.DatabaseStateAvailable, database.DatabaseStateModifying)) + + _, err := svc.ApplyMajorUpgrade(t.Context(), dbID, "6", targetImage, nil) + assert.True(t, errors.Is(err, database.ErrDatabaseNotModifiable)) + }) + + t.Run("propagates ErrUpgradeNotAvailable from orchestrator", func(t *testing.T) { + orch := &stubOrchestrator{ + findMajorUpgradeFn: func(_ *ds.PgEdgeVersion, _, _ string) (*database.AvailableUpgrade, error) { + return nil, fmt.Errorf("%w: image not in manifest", database.ErrUpgradeNotAvailable) + }, + } + svc := newTestService(t, orch) + dbID := seedDatabase(t, svc, "18.4") + + _, err := svc.ApplyMajorUpgrade(t.Context(), dbID, "6", targetImage, nil) + assert.True(t, errors.Is(err, database.ErrUpgradeNotAvailable)) + }) + + t.Run("defaults node_order to spec order when empty", func(t *testing.T) { + orch := &stubOrchestrator{ + findMajorUpgradeFn: func(_ *ds.PgEdgeVersion, _, _ string) (*database.AvailableUpgrade, error) { + return successfulUpgrade, nil + }, + } + svc := newTestService(t, orch) + ctx := t.Context() + + db, err := svc.CreateDatabase(ctx, &database.Spec{ + DatabaseName: "test", + PostgresVersion: "18.4", + SpockVersion: "5", + Nodes: []*database.Node{ + {Name: "n1", HostIDs: []string{"host-1"}}, + {Name: "n2", HostIDs: []string{"host-2"}}, + }, + DatabaseUsers: []*database.User{ + {Username: "admin", Attributes: []string{"SUPERUSER", "LOGIN"}}, + }, + }) + require.NoError(t, err) + require.NoError(t, svc.UpdateDatabaseState(ctx, db.DatabaseID, database.DatabaseStateCreating, database.DatabaseStateAvailable)) + + result, err := svc.ApplyMajorUpgrade(ctx, db.DatabaseID, "6", targetImage, nil) + require.NoError(t, err) + assert.Equal(t, []string{"n1", "n2"}, result.NodeOrder) + }) + + t.Run("accepts a valid explicit node_order permutation", func(t *testing.T) { + orch := &stubOrchestrator{ + findMajorUpgradeFn: func(_ *ds.PgEdgeVersion, _, _ string) (*database.AvailableUpgrade, error) { + return successfulUpgrade, nil + }, + } + svc := newTestService(t, orch) + ctx := t.Context() + + db, err := svc.CreateDatabase(ctx, &database.Spec{ + DatabaseName: "test", + PostgresVersion: "18.4", + SpockVersion: "5", + Nodes: []*database.Node{ + {Name: "n1", HostIDs: []string{"host-1"}}, + {Name: "n2", HostIDs: []string{"host-2"}}, + }, + DatabaseUsers: []*database.User{ + {Username: "admin", Attributes: []string{"SUPERUSER", "LOGIN"}}, + }, + }) + require.NoError(t, err) + require.NoError(t, svc.UpdateDatabaseState(ctx, db.DatabaseID, database.DatabaseStateCreating, database.DatabaseStateAvailable)) + + result, err := svc.ApplyMajorUpgrade(ctx, db.DatabaseID, "6", targetImage, []string{"n2", "n1"}) + require.NoError(t, err) + assert.Equal(t, []string{"n2", "n1"}, result.NodeOrder) + }) + + t.Run("rejects node_order naming an unknown node", func(t *testing.T) { + orch := &stubOrchestrator{ + findMajorUpgradeFn: func(_ *ds.PgEdgeVersion, _, _ string) (*database.AvailableUpgrade, error) { + return successfulUpgrade, nil + }, + } + svc := newTestService(t, orch) + dbID := seedDatabase(t, svc, "18.4") + + _, err := svc.ApplyMajorUpgrade(t.Context(), dbID, "6", targetImage, []string{"no-such-node"}) + assert.True(t, errors.Is(err, database.ErrInvalidDatabaseUpdate)) + }) + + t.Run("rejects node_order with a duplicate node", func(t *testing.T) { + orch := &stubOrchestrator{ + findMajorUpgradeFn: func(_ *ds.PgEdgeVersion, _, _ string) (*database.AvailableUpgrade, error) { + return successfulUpgrade, nil + }, + } + svc := newTestService(t, orch) + ctx := t.Context() + + db, err := svc.CreateDatabase(ctx, &database.Spec{ + DatabaseName: "test", + PostgresVersion: "18.4", + SpockVersion: "5", + Nodes: []*database.Node{ + {Name: "n1", HostIDs: []string{"host-1"}}, + {Name: "n2", HostIDs: []string{"host-2"}}, + }, + DatabaseUsers: []*database.User{ + {Username: "admin", Attributes: []string{"SUPERUSER", "LOGIN"}}, + }, + }) + require.NoError(t, err) + require.NoError(t, svc.UpdateDatabaseState(ctx, db.DatabaseID, database.DatabaseStateCreating, database.DatabaseStateAvailable)) + + _, err = svc.ApplyMajorUpgrade(ctx, db.DatabaseID, "6", targetImage, []string{"n1", "n1"}) + assert.True(t, errors.Is(err, database.ErrInvalidDatabaseUpdate)) + }) + + t.Run("rejects node_order missing a node", func(t *testing.T) { + orch := &stubOrchestrator{ + findMajorUpgradeFn: func(_ *ds.PgEdgeVersion, _, _ string) (*database.AvailableUpgrade, error) { + return successfulUpgrade, nil + }, + } + svc := newTestService(t, orch) + ctx := t.Context() + + db, err := svc.CreateDatabase(ctx, &database.Spec{ + DatabaseName: "test", + PostgresVersion: "18.4", + SpockVersion: "5", + Nodes: []*database.Node{ + {Name: "n1", HostIDs: []string{"host-1"}}, + {Name: "n2", HostIDs: []string{"host-2"}}, + }, + DatabaseUsers: []*database.User{ + {Username: "admin", Attributes: []string{"SUPERUSER", "LOGIN"}}, + }, + }) + require.NoError(t, err) + require.NoError(t, svc.UpdateDatabaseState(ctx, db.DatabaseID, database.DatabaseStateCreating, database.DatabaseStateAvailable)) + + _, err = svc.ApplyMajorUpgrade(ctx, db.DatabaseID, "6", targetImage, []string{"n1"}) + assert.True(t, errors.Is(err, database.ErrInvalidDatabaseUpdate)) + }) +} + +func TestService_RollbackApplyMajorUpgrade(t *testing.T) { + targetImage := "ghcr.io/pgedge/pgedge-postgres:18.4-spock6.0.0-standard-1" + + t.Run("restores state", func(t *testing.T) { + orch := &stubOrchestrator{ + findMajorUpgradeFn: func(_ *ds.PgEdgeVersion, _, _ string) (*database.AvailableUpgrade, error) { + return &database.AvailableUpgrade{PostgresVersion: "18.4", SpockVersion: "6", Image: targetImage}, nil + }, + } + svc := newTestService(t, orch) + dbID := seedDatabase(t, svc, "18.4") + + result, err := svc.ApplyMajorUpgrade(t.Context(), dbID, "6", targetImage, nil) + require.NoError(t, err) + assert.Equal(t, database.DatabaseStateModifying, result.Database.State) + + require.NoError(t, svc.RollbackApplyMajorUpgrade(t.Context(), result)) + + restored, err := svc.GetDatabase(t.Context(), dbID) + require.NoError(t, err) + assert.Equal(t, database.DatabaseStateAvailable, restored.State) + // the spec was never touched by ApplyMajorUpgrade, so it should still + // reflect the original spock version. + assert.Equal(t, "5", restored.Spec.SpockVersion) + }) +} + +func TestService_ApplyMajorUpgradeSpecChange(t *testing.T) { + t.Run("persists a spock major-version change that ordinary updates reject", func(t *testing.T) { + svc := newTestService(t, &stubOrchestrator{}) + ctx := t.Context() + dbID := seedDatabase(t, svc, "18.4") + require.NoError(t, svc.UpdateDatabaseState(ctx, dbID, database.DatabaseStateAvailable, database.DatabaseStateModifying)) + + current, err := svc.GetDatabase(ctx, dbID) + require.NoError(t, err) + + newSpec := current.Spec.Clone() + newSpec.Nodes[0].SpockVersion = "6" + + updated, err := svc.ApplyMajorUpgradeSpecChange(ctx, newSpec, database.DatabaseStateModifying) + require.NoError(t, err) + assert.Equal(t, "6", updated.Spec.Nodes[0].SpockVersion) + }) +} diff --git a/server/internal/database/apply_upgrade_test.go b/server/internal/database/apply_upgrade_test.go index a08f1482..2a6ef15b 100644 --- a/server/internal/database/apply_upgrade_test.go +++ b/server/internal/database/apply_upgrade_test.go @@ -23,9 +23,11 @@ import ( ) // stubOrchestrator is a minimal Orchestrator for service-layer tests. -// Only FindUpgrade is configurable; all other methods return zero values. +// Only FindUpgrade/FindMajorUpgrade are configurable; all other methods +// return zero values. type stubOrchestrator struct { - findUpgradeFn func(*ds.PgEdgeVersion, string) (*database.AvailableUpgrade, error) + findUpgradeFn func(*ds.PgEdgeVersion, string) (*database.AvailableUpgrade, error) + findMajorUpgradeFn func(*ds.PgEdgeVersion, string, string) (*database.AvailableUpgrade, error) } func (s *stubOrchestrator) FindUpgrade(cur *ds.PgEdgeVersion, img string) (*database.AvailableUpgrade, error) { @@ -35,6 +37,13 @@ func (s *stubOrchestrator) FindUpgrade(cur *ds.PgEdgeVersion, img string) (*data return nil, database.ErrUpgradeNotAvailable } +func (s *stubOrchestrator) FindMajorUpgrade(cur *ds.PgEdgeVersion, targetSpockVersion, img string) (*database.AvailableUpgrade, error) { + if s.findMajorUpgradeFn != nil { + return s.findMajorUpgradeFn(cur, targetSpockVersion, img) + } + return nil, database.ErrUpgradeNotAvailable +} + func (s *stubOrchestrator) GenerateInstanceResources(*database.InstanceSpec, database.Scripts) (*database.InstanceResources, error) { return nil, nil } diff --git a/server/internal/database/orchestrator.go b/server/internal/database/orchestrator.go index 0fbef18b..61c92c05 100644 --- a/server/internal/database/orchestrator.go +++ b/server/internal/database/orchestrator.go @@ -202,6 +202,14 @@ type Orchestrator interface { // Returns the validated upgrade descriptor on success, or // ErrUpgradeNotAvailable (possibly wrapped) on any validation failure. FindUpgrade(current *ds.PgEdgeVersion, targetImage string) (*AvailableUpgrade, error) + // FindMajorUpgrade validates that targetImage is usable for a dedicated + // Spock major-version upgrade away from current: same postgres_version, + // a different (specifically, the requested) spock major, and present in + // the manifest at any stability level (a new Spock major is expected to + // still be "dev" stability while this action is what's used for it). + // Returns the validated upgrade descriptor on success, or + // ErrUpgradeNotAvailable (possibly wrapped) on any validation failure. + FindMajorUpgrade(current *ds.PgEdgeVersion, targetSpockVersion, targetImage string) (*AvailableUpgrade, error) } // AvailableUpgrade describes a single candidate image upgrade available for a diff --git a/server/internal/database/service.go b/server/internal/database/service.go index 29d10951..289f215c 100644 --- a/server/internal/database/service.go +++ b/server/internal/database/service.go @@ -870,6 +870,145 @@ func (s *Service) RollbackApplyUpgrade(ctx context.Context, result *ApplyUpgrade return nil } +// ApplyMajorUpgradeResult carries what ApplyMajorUpgrade validated, for the +// caller to pass into the MajorVersionUpgrade workflow, plus enough state to +// roll back if the workflow fails to even start. +type ApplyMajorUpgradeResult struct { + Database *Database + PrevState DatabaseState + TargetSpockVersion string + Image string + NodeOrder []string +} + +// ApplyMajorUpgrade validates a dedicated Spock major-version upgrade request +// and marks the database as modifying, but — unlike ApplyUpgrade — does not +// touch the spec at all. A major-version upgrade is rolled one node at a +// time by the MajorVersionUpgrade workflow, which owns mutating each node's +// spock_version override itself as it goes; mutating the whole spec upfront +// here would claim every node is upgrading at once when only the first one +// actually is yet. +func (s *Service) ApplyMajorUpgrade(ctx context.Context, databaseID, targetSpockVersion, targetImage string, nodeOrder []string) (*ApplyMajorUpgradeResult, error) { + currentSpec, err := s.store.Spec.GetByKey(databaseID).Exec(ctx) + if errors.Is(err, storage.ErrNotFound) { + return nil, ErrDatabaseNotFound + } else if err != nil { + return nil, fmt.Errorf("failed to get database spec: %w", err) + } + + currentDB, err := s.store.Database.GetByKey(databaseID).Exec(ctx) + if errors.Is(err, storage.ErrNotFound) { + return nil, ErrDatabaseNotFound + } else if err != nil { + return nil, fmt.Errorf("failed to get database: %w", err) + } + if !DatabaseStateModifiable(currentDB.State) { + return nil, ErrDatabaseNotModifiable + } + + currentVersion, err := ds.ParsePgEdgeVersion(currentSpec.PostgresVersion, currentSpec.SpockVersion) + if err != nil { + return nil, fmt.Errorf("failed to parse current version: %w", err) + } + + upgrade, err := s.orchestrator.FindMajorUpgrade(currentVersion, targetSpockVersion, targetImage) + if err != nil { + return nil, err + } + + order, err := resolveMajorUpgradeNodeOrder(currentSpec.Nodes, nodeOrder) + if err != nil { + return nil, err + } + + prevState := currentDB.State + if err := s.UpdateDatabaseState(ctx, databaseID, prevState, DatabaseStateModifying); err != nil { + return nil, fmt.Errorf("failed to mark database as modifying: %w", err) + } + + db, err := s.GetDatabase(ctx, databaseID) + if err != nil { + return nil, fmt.Errorf("failed to get database after marking modifying: %w", err) + } + + return &ApplyMajorUpgradeResult{ + Database: db, + PrevState: prevState, + TargetSpockVersion: upgrade.SpockVersion, + Image: upgrade.Image, + NodeOrder: order, + }, nil +} + +// resolveMajorUpgradeNodeOrder defaults to the spec's own node order when +// nodeOrder is empty, otherwise validates that nodeOrder is a permutation of +// exactly the database's current node names — every node must be upgraded, +// none can be named twice, and no unknown node can sneak in. +func resolveMajorUpgradeNodeOrder(nodes []*Node, nodeOrder []string) ([]string, error) { + specNodeNames := ds.NewSet[string]() + for _, n := range nodes { + specNodeNames.Add(n.Name) + } + + if len(nodeOrder) == 0 { + order := make([]string, len(nodes)) + for i, n := range nodes { + order[i] = n.Name + } + return order, nil + } + + seen := ds.NewSet[string]() + for _, name := range nodeOrder { + if !specNodeNames.Has(name) { + return nil, fmt.Errorf("%w: node_order references node %q, which does not exist in this database", ErrInvalidDatabaseUpdate, name) + } + if seen.Has(name) { + return nil, fmt.Errorf("%w: node_order lists node %q more than once", ErrInvalidDatabaseUpdate, name) + } + seen.Add(name) + } + if len(seen) != len(specNodeNames) { + return nil, fmt.Errorf("%w: node_order must include every node in the database exactly once (got %d of %d)", ErrInvalidDatabaseUpdate, len(seen), len(specNodeNames)) + } + return nodeOrder, nil +} + +// RollbackApplyMajorUpgrade restores the database's state to what it was +// before ApplyMajorUpgrade marked it modifying. It is intended to be called +// when the MajorVersionUpgrade workflow fails to even start — unlike +// RollbackApplyUpgrade there is no spec to restore, since ApplyMajorUpgrade +// never touched the spec. +func (s *Service) RollbackApplyMajorUpgrade(ctx context.Context, result *ApplyMajorUpgradeResult) error { + return s.UpdateDatabaseState(ctx, result.Database.DatabaseID, DatabaseStateModifying, result.PrevState) +} + +// ApplyMajorUpgradeSpecChange persists newSpec directly, deliberately +// bypassing ValidateChangedSpec (and so its spockMajorVersionChanged guard). +// It exists solely for the MajorVersionUpgrade workflow to call, once per +// node as it rolls a Spock major-version upgrade forward and once more at +// the end to normalize the spec — the one place in the system allowed to +// change an instance's Spock major, by design, the same way ApplyUpgrade is +// the one place allowed to change a Postgres minor/patch version outside +// the ordinary update-database validation path. +func (s *Service) ApplyMajorUpgradeSpecChange(ctx context.Context, newSpec *Spec, newState DatabaseState) (*Database, error) { + currentSpec, err := s.store.Spec.GetByKey(newSpec.DatabaseID).Exec(ctx) + if errors.Is(err, storage.ErrNotFound) { + return nil, ErrDatabaseNotFound + } else if err != nil { + return nil, fmt.Errorf("failed to get database spec: %w", err) + } + + currentDB, err := s.store.Database.GetByKey(newSpec.DatabaseID).Exec(ctx) + if errors.Is(err, storage.ErrNotFound) { + return nil, ErrDatabaseNotFound + } else if err != nil { + return nil, fmt.Errorf("failed to get database: %w", err) + } + + return s.applySpecUpdate(ctx, currentSpec, currentDB, newSpec, newState) +} + func (s *Service) ReconcileServiceInstanceSpec(ctx context.Context, spec *ServiceInstanceSpec) (*ServiceInstanceSpec, error) { if s.cfg.HostID != spec.HostID { return nil, fmt.Errorf("this service instance belongs to another host - this host='%s', service instance host='%s'", s.cfg.HostID, spec.HostID) @@ -1049,6 +1188,10 @@ func ValidateChangedSpec(current, updated *Spec) error { if err != nil { errs = append(errs, fmt.Errorf("invalid change for instance %s: %w", id, err)) } + err = spockMajorVersionChanged(oldInstance.PgEdgeVersion, newInstance.PgEdgeVersion) + if err != nil { + errs = append(errs, fmt.Errorf("invalid change for instance %s: %w", id, err)) + } } if len(errs) != 0 { @@ -1090,6 +1233,30 @@ func majorVersionChanged(old, new *ds.PgEdgeVersion) error { return nil } +// spockMajorVersionChanged rejects any ordinary spec update that would +// change an instance's Spock major version. Only the dedicated +// MajorVersionUpgrade workflow is allowed to do this — and it does, one node +// at a time, by calling applySpecUpdate directly rather than going through +// UpdateDatabase/ValidateChangedSpec, exactly the way ApplyUpgrade already +// bypasses this same validation for its own privileged, controlled mutation. +func spockMajorVersionChanged(old, new *ds.PgEdgeVersion) error { + if old == nil || new == nil { + return errors.New("expected both current and updated versions to be defined") + } + oldSpockMajor, ok := old.SpockVersion.Major() + if !ok { + return errors.New("current spock version is missing its major component") + } + newSpockMajor, ok := new.SpockVersion.Major() + if !ok { + return errors.New("updated spock version is missing its major component") + } + if oldSpockMajor != newSpockMajor { + return fmt.Errorf("spock major version changed from %d to %d; use the dedicated major-version upgrade action instead", oldSpockMajor, newSpockMajor) + } + return nil +} + func tenantIDsMatch(a, b *string) bool { switch { case a == nil && b == nil: diff --git a/server/internal/database/service_test.go b/server/internal/database/service_test.go index 3904a98a..14564c0b 100644 --- a/server/internal/database/service_test.go +++ b/server/internal/database/service_test.go @@ -192,6 +192,52 @@ func TestValidateChangedSpec(t *testing.T) { }, expectedErr: "major version changed from 17 to 18", }, + { + name: "invalid database-level spock version update", + current: &database.Spec{ + TenantID: utils.PointerTo("tenant-id"), + DatabaseName: "test", + PostgresVersion: "18.0", + SpockVersion: "5", + Nodes: []*database.Node{ + {Name: "n1", HostIDs: []string{"host-1"}}, + }, + }, + updated: &database.Spec{ + TenantID: utils.PointerTo("tenant-id"), + DatabaseName: "test", + PostgresVersion: "18.0", + SpockVersion: "6", + Nodes: []*database.Node{ + {Name: "n1", HostIDs: []string{"host-1"}}, + }, + }, + expectedErr: "spock major version changed from 5 to 6; use the dedicated major-version upgrade action instead", + }, + { + name: "invalid node-level spock version update", + current: &database.Spec{ + TenantID: utils.PointerTo("tenant-id"), + DatabaseName: "test", + PostgresVersion: "18.0", + SpockVersion: "5", + Nodes: []*database.Node{ + {Name: "n1", HostIDs: []string{"host-1"}}, + {Name: "n2", HostIDs: []string{"host-2"}}, + }, + }, + updated: &database.Spec{ + TenantID: utils.PointerTo("tenant-id"), + DatabaseName: "test", + PostgresVersion: "18.0", + SpockVersion: "5", + Nodes: []*database.Node{ + {Name: "n1", HostIDs: []string{"host-1"}, SpockVersion: "6"}, + {Name: "n2", HostIDs: []string{"host-2"}}, + }, + }, + expectedErr: "spock major version changed from 5 to 6; use the dedicated major-version upgrade action instead", + }, } { t.Run(tc.name, func(t *testing.T) { err := database.ValidateChangedSpec(tc.current, tc.updated) diff --git a/server/internal/database/spec.go b/server/internal/database/spec.go index 99b5b930..f64df5cd 100644 --- a/server/internal/database/spec.go +++ b/server/internal/database/spec.go @@ -45,6 +45,13 @@ type Node struct { Name string `json:"name"` HostIDs []string `json:"host_ids"` PostgresVersion string `json:"postgres_version"` + // SpockVersion is a per-node override of the database's Spock major + // version. Never set through create-database/update-database (rejected by + // validateNode in the api layer) — the only writer is the dedicated + // major-version-upgrade workflow, which sets it on exactly one node at a + // time as it rolls a database from one Spock major to another. Empty for + // every node outside of an in-progress major-version upgrade. + SpockVersion string `json:"spock_version,omitempty"` Port *int `json:"port"` PatroniPort *int `json:"patroni_port"` CPUs float64 `json:"cpus"` @@ -66,6 +73,7 @@ func (n *Node) Clone() *Node { Name: n.Name, HostIDs: slices.Clone(n.HostIDs), PostgresVersion: n.PostgresVersion, + SpockVersion: n.SpockVersion, Port: n.Port, PatroniPort: n.PatroniPort, CPUs: n.CPUs, @@ -86,6 +94,9 @@ func (n *Node) DefaultOptionalFieldsFrom(other *Node) { if n.PostgresVersion == "" && other.PostgresVersion != "" { n.PostgresVersion = other.PostgresVersion } + if n.SpockVersion == "" && other.SpockVersion != "" { + n.SpockVersion = other.SpockVersion + } if n.BackupConfig != nil && other.BackupConfig != nil { n.BackupConfig.DefaultOptionalFieldsFrom(other.BackupConfig) @@ -699,10 +710,22 @@ func (s *Spec) NodeInstances() ([]*NodeInstances, error) { return nil, fmt.Errorf("failed to extract ordinal from node name: %w", err) } - // Respect node-level overrides - nodeVersion := specVersion + // Respect node-level overrides. postgres_version and spock_version are + // overridden independently of each other — a node mid major-version + // upgrade may have a spock_version override with no postgres_version + // override at all, or vice versa, so this can't just re-parse both + // together only when one of them is set. + pgVersion := s.PostgresVersion if node.PostgresVersion != "" { - nodeVersion, err = ds.ParsePgEdgeVersion(node.PostgresVersion, s.SpockVersion) + pgVersion = node.PostgresVersion + } + spockVersion := s.SpockVersion + if node.SpockVersion != "" { + spockVersion = node.SpockVersion + } + nodeVersion := specVersion + if pgVersion != s.PostgresVersion || spockVersion != s.SpockVersion { + nodeVersion, err = ds.ParsePgEdgeVersion(pgVersion, spockVersion) if err != nil { return nil, fmt.Errorf("failed to parse version from node spec: %w", err) } diff --git a/server/internal/orchestrator/swarm/find_major_upgrade_test.go b/server/internal/orchestrator/swarm/find_major_upgrade_test.go new file mode 100644 index 00000000..b473b21c --- /dev/null +++ b/server/internal/orchestrator/swarm/find_major_upgrade_test.go @@ -0,0 +1,92 @@ +package swarm + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/pgEdge/control-plane/server/internal/config" + "github.com/pgEdge/control-plane/server/internal/database" + "github.com/pgEdge/control-plane/server/internal/ds" +) + +// versionsWithSpock6 builds a manifest with a spock5 stable entry and a +// spock6 dev entry at the same postgres version, mirroring the real +// version-manifest.json shape used for the Spock 6 dev-stability entries. +func versionsWithSpock6(t *testing.T) *Versions { + t.Helper() + cfg := config.Config{DockerSwarm: config.DockerSwarm{ImageRepositoryHost: "ghcr.io/pgedge"}} + v := &Versions{cfg: cfg, images: make(map[string]map[string]*Images)} + v.addImage(ds.MustParsePgEdgeVersion("18.4", "5"), &Images{ + PgEdgeImage: "ghcr.io/pgedge/pgedge-postgres:18.4-spock5.0.10-standard-1", + Stability: "stable", + }) + v.addImage(ds.MustParsePgEdgeVersion("18.4", "6"), &Images{ + PgEdgeImage: "ghcr.io/pgedge/pgedge-postgres:18.4-spock6.0.0-standard-1", + Stability: "dev", + }) + v.addImage(ds.MustParsePgEdgeVersion("17.9", "5"), &Images{ + PgEdgeImage: "ghcr.io/pgedge/pgedge-postgres:17.9-spock5.0.6-standard-2", + Stability: "stable", + }) + v.defaultVersion = ds.MustParsePgEdgeVersion("18.4", "5") + return v +} + +func TestOrchestrator_FindMajorUpgrade(t *testing.T) { + v := versionsWithSpock6(t) + o := newOrchestratorWithVersions(v) + + current := ds.MustParsePgEdgeVersion("18.4", "5") + spock6Image := "ghcr.io/pgedge/pgedge-postgres:18.4-spock6.0.0-standard-1" + spock5Image := "ghcr.io/pgedge/pgedge-postgres:18.4-spock5.0.10-standard-1" + + t.Run("happy path: finds a dev-stability cross-major target", func(t *testing.T) { + got, err := o.FindMajorUpgrade(current, "6", spock6Image) + require.NoError(t, err) + require.NotNil(t, got) + assert.Equal(t, spock6Image, got.Image) + assert.Equal(t, "6", got.SpockVersion) + }) + + t.Run("rejects a target whose spock major equals the current major", func(t *testing.T) { + _, err := o.FindMajorUpgrade(current, "5", spock5Image) + require.Error(t, err) + assert.True(t, errors.Is(err, database.ErrUpgradeNotAvailable)) + }) + + t.Run("rejects a target image whose spock major does not match target_spock_version", func(t *testing.T) { + _, err := o.FindMajorUpgrade(current, "6", spock5Image) + require.Error(t, err) + assert.True(t, errors.Is(err, database.ErrUpgradeNotAvailable)) + }) + + t.Run("rejects a target in a different postgres major bucket", func(t *testing.T) { + pg17Spock5 := "ghcr.io/pgedge/pgedge-postgres:17.9-spock5.0.6-standard-2" + _, err := o.FindMajorUpgrade(current, "6", pg17Spock5) + require.Error(t, err) + assert.True(t, errors.Is(err, database.ErrUpgradeNotAvailable)) + }) + + t.Run("rejects image not in manifest", func(t *testing.T) { + _, err := o.FindMajorUpgrade(current, "6", "ghcr.io/pgedge/pgedge-postgres:99.99-unknown") + require.Error(t, err) + assert.True(t, errors.Is(err, database.ErrUpgradeNotAvailable)) + }) + + t.Run("invalid target_spock_version is rejected", func(t *testing.T) { + _, err := o.FindMajorUpgrade(current, "not-a-version", spock6Image) + require.Error(t, err) + assert.True(t, errors.Is(err, database.ErrUpgradeNotAvailable)) + }) + + t.Run("rejects a downgrade to an older spock major", func(t *testing.T) { + currentAtSpock6 := ds.MustParsePgEdgeVersion("18.4", "6") + _, err := o.FindMajorUpgrade(currentAtSpock6, "5", spock5Image) + require.Error(t, err) + assert.True(t, errors.Is(err, database.ErrUpgradeNotAvailable)) + assert.ErrorContains(t, err, "older than current") + }) +} diff --git a/server/internal/orchestrator/swarm/orchestrator.go b/server/internal/orchestrator/swarm/orchestrator.go index 2be09fab..ed738624 100644 --- a/server/internal/orchestrator/swarm/orchestrator.go +++ b/server/internal/orchestrator/swarm/orchestrator.go @@ -366,6 +366,55 @@ func (o *Orchestrator) FindUpgrade(current *ds.PgEdgeVersion, targetImage string }, nil } +func (o *Orchestrator) FindMajorUpgrade(current *ds.PgEdgeVersion, targetSpockVersion, targetImage string) (*database.AvailableUpgrade, error) { + ver, img, ok := o.getVersions().FindByImage(targetImage) + if !ok { + return nil, fmt.Errorf("%w: image not found in manifest: %s", database.ErrUpgradeNotAvailable, targetImage) + } + // Unlike FindUpgrade, any stability level is accepted here — a Spock + // major is expected to still be behind a "dev" manifest entry (see + // item 2 of the Spock 6 support design doc) for as long as this action + // is what's used to reach it. + + currentPGMajor, ok := current.PostgresVersion.Major() + if !ok { + return nil, fmt.Errorf("%w: cannot determine current postgres major version", database.ErrUpgradeNotAvailable) + } + targetPGMajor, ok2 := ver.PostgresVersion.Major() + if !ok2 || targetPGMajor != currentPGMajor { + return nil, fmt.Errorf("%w: target postgres major %d differs from current %d; a major-version upgrade changes Spock only, not Postgres", database.ErrUpgradeNotAvailable, targetPGMajor, currentPGMajor) + } + + currentSpockMajor, ok := current.SpockVersion.Major() + if !ok { + return nil, fmt.Errorf("%w: cannot determine current spock major version", database.ErrUpgradeNotAvailable) + } + targetVersion, err := ds.ParseVersion(targetSpockVersion) + if err != nil { + return nil, fmt.Errorf("%w: invalid target spock version %q: %w", database.ErrUpgradeNotAvailable, targetSpockVersion, err) + } + targetSpockMajorRequested, ok := targetVersion.Major() + if !ok { + return nil, fmt.Errorf("%w: cannot determine requested spock major version", database.ErrUpgradeNotAvailable) + } + if targetSpockMajorRequested == currentSpockMajor { + return nil, fmt.Errorf("%w: requested spock major %d is the same as current %d; use apply-upgrade for a same-major bump", database.ErrUpgradeNotAvailable, targetSpockMajorRequested, currentSpockMajor) + } + if targetSpockMajorRequested < currentSpockMajor { + return nil, fmt.Errorf("%w: requested spock major %d is older than current %d; Spock cannot be downgraded in place", database.ErrUpgradeNotAvailable, targetSpockMajorRequested, currentSpockMajor) + } + targetSpockMajor, ok2 := ver.SpockVersion.Major() + if !ok2 || targetSpockMajor != targetSpockMajorRequested { + return nil, fmt.Errorf("%w: target image spock major %d does not match requested target_spock_version %d", database.ErrUpgradeNotAvailable, targetSpockMajor, targetSpockMajorRequested) + } + + return &database.AvailableUpgrade{ + PostgresVersion: ver.PostgresVersion.String(), + SpockVersion: ver.SpockVersion.String(), + Image: img.PgEdgeImage, + }, nil +} + func (o *Orchestrator) instanceResources(spec *database.InstanceSpec, scripts database.Scripts) (*database.InstanceResource, []resource.Resource, []resource.Resource, error) { images, err := o.resolveInstanceImages(spec) if err != nil { diff --git a/server/internal/orchestrator/systemd/orchestrator.go b/server/internal/orchestrator/systemd/orchestrator.go index a38f540a..75ed055f 100644 --- a/server/internal/orchestrator/systemd/orchestrator.go +++ b/server/internal/orchestrator/systemd/orchestrator.go @@ -163,6 +163,10 @@ func (o *Orchestrator) FindUpgrade(_ *ds.PgEdgeVersion, _ string) (*database.Ava return nil, fmt.Errorf("%w: install the target package via your OS package manager before applying an upgrade on systemd-managed databases", database.ErrUpgradeNotAvailable) } +func (o *Orchestrator) FindMajorUpgrade(_ *ds.PgEdgeVersion, _, _ string) (*database.AvailableUpgrade, error) { + return nil, fmt.Errorf("%w: install the target package via your OS package manager before applying a major-version upgrade on systemd-managed databases", database.ErrUpgradeNotAvailable) +} + func (o *Orchestrator) GenerateInstanceResources(spec *database.InstanceSpec, scripts database.Scripts) (*database.InstanceResources, error) { paths, err := o.InstancePaths(spec.PgEdgeVersion.PostgresVersion, spec.InstanceID) if err != nil { diff --git a/server/internal/task/task.go b/server/internal/task/task.go index 7c01077e..6a349dea 100644 --- a/server/internal/task/task.go +++ b/server/internal/task/task.go @@ -41,6 +41,7 @@ const ( TypeFailover Type = "failover" TypeRemoveHost Type = "remove_host" TypeUpgrade Type = "upgrade" + TypeMajorUpgrade Type = "major_upgrade" ) type Status string diff --git a/server/internal/workflows/activities/activities.go b/server/internal/workflows/activities/activities.go index f434339e..a8f8e3a5 100644 --- a/server/internal/workflows/activities/activities.go +++ b/server/internal/workflows/activities/activities.go @@ -45,8 +45,10 @@ func (a *Activities) Register(work *worker.Worker) error { work.RegisterActivity(a.StopInstance), work.RegisterActivity(a.UpdateDbState), work.RegisterActivity(a.UpdatePlannedInstanceStates), + work.RegisterActivity(a.UpdateSpec), work.RegisterActivity(a.UpdateTask), work.RegisterActivity(a.ValidateInstanceSpecs), + work.RegisterActivity(a.VerifyNodeReplicating), } return errors.Join(errs...) } diff --git a/server/internal/workflows/activities/update_spec.go b/server/internal/workflows/activities/update_spec.go new file mode 100644 index 00000000..441dbf9a --- /dev/null +++ b/server/internal/workflows/activities/update_spec.go @@ -0,0 +1,53 @@ +package activities + +import ( + "context" + "fmt" + + "github.com/cschleiden/go-workflows/activity" + "github.com/cschleiden/go-workflows/workflow" + "github.com/samber/do" + + "github.com/pgEdge/control-plane/server/internal/database" + "github.com/pgEdge/control-plane/server/internal/utils" +) + +// UpdateSpecInput persists a full spec replacement via +// database.Service.ApplyMajorUpgradeSpecChange — the one privileged path +// that's allowed to change an instance's Spock major version. Used +// exclusively by the MajorVersionUpgrade workflow. +type UpdateSpecInput struct { + Spec *database.Spec `json:"spec"` + State database.DatabaseState `json:"state"` +} + +type UpdateSpecOutput struct{} + +func (a *Activities) ExecuteUpdateSpec( + ctx workflow.Context, + input *UpdateSpecInput, +) workflow.Future[*UpdateSpecOutput] { + options := workflow.ActivityOptions{ + Queue: utils.HostQueue(a.Config.HostID), + RetryOptions: workflow.RetryOptions{ + MaxAttempts: 1, + }, + } + return workflow.ExecuteActivity[*UpdateSpecOutput](ctx, options, a.UpdateSpec, input) +} + +func (a *Activities) UpdateSpec(ctx context.Context, input *UpdateSpecInput) (*UpdateSpecOutput, error) { + logger := activity.Logger(ctx).With("database_id", input.Spec.DatabaseID) + logger.Debug("persisting spec change for major-version upgrade") + + dbSvc, err := do.Invoke[*database.Service](a.Injector) + if err != nil { + return nil, err + } + + if _, err := dbSvc.ApplyMajorUpgradeSpecChange(ctx, input.Spec, input.State); err != nil { + return nil, fmt.Errorf("failed to persist spec change: %w", err) + } + + return &UpdateSpecOutput{}, nil +} diff --git a/server/internal/workflows/activities/verify_node_replicating.go b/server/internal/workflows/activities/verify_node_replicating.go new file mode 100644 index 00000000..7d8ae137 --- /dev/null +++ b/server/internal/workflows/activities/verify_node_replicating.go @@ -0,0 +1,136 @@ +package activities + +import ( + "context" + "fmt" + "time" + + "github.com/cschleiden/go-workflows/activity" + "github.com/cschleiden/go-workflows/workflow" + + "github.com/pgEdge/control-plane/server/internal/database" + "github.com/pgEdge/control-plane/server/internal/postgres" + "github.com/pgEdge/control-plane/server/internal/utils" +) + +// VerifyNodeReplicatingInput identifies one node whose primary instance's +// subscriptions must all reach "replicating" before the MajorVersionUpgrade +// workflow moves on to the next node — the fail-loud check for a per-node +// major-version bump, mirroring VerifySubscriptionReplicatingResource's role +// in the add-node pipeline (see design item 9a): rather than assume Spock's +// own extension-upgrade-on-mismatch mechanism (ALTER EXTENSION UPDATE, +// triggered automatically once the new binary starts) brought replication +// back cleanly, this actually checks. +type VerifyNodeReplicatingInput struct { + DatabaseID string `json:"database_id"` + NodeName string `json:"node_name"` + // ExpectedSubscriptions is the number of peer subscriptions this node's + // primary should have once replication has resumed — one per other node + // in the database (Spock replication is a full mesh between node + // primaries, independent of read-replica count). Zero observed + // subscriptions only counts as success when this is also zero (a + // single-node database); otherwise it means the primary hasn't + // re-registered its subscriptions yet after the redeploy, which is a + // distinct, meaningful state from actually having caught up. + ExpectedSubscriptions int `json:"expected_subscriptions"` +} + +type VerifyNodeReplicatingOutput struct{} + +func (a *Activities) ExecuteVerifyNodeReplicating( + ctx workflow.Context, + input *VerifyNodeReplicatingInput, +) workflow.Future[*VerifyNodeReplicatingOutput] { + options := workflow.ActivityOptions{ + Queue: utils.AnyQueue(), + RetryOptions: workflow.RetryOptions{ + MaxAttempts: 1, + }, + } + return workflow.ExecuteActivity[*VerifyNodeReplicatingOutput](ctx, options, a.VerifyNodeReplicating, input) +} + +const ( + verifyNodeReplicatingPollInterval = 5 * time.Second + verifyNodeReplicatingTimeout = 3 * time.Minute +) + +// VerifyNodeReplicating polls the already-collected instance monitor status +// (InstanceStatus.Subscriptions, refreshed independently every +// database.InstanceMonitorRefreshInterval) rather than opening its own +// Postgres connection, since that status already reflects +// spock.sub_show_status() for every subscription on the instance and doing +// it this way means this activity isn't pinned to any specific host — it +// only ever reads from etcd. +func (a *Activities) VerifyNodeReplicating(ctx context.Context, input *VerifyNodeReplicatingInput) (*VerifyNodeReplicatingOutput, error) { + logger := activity.Logger(ctx).With("database_id", input.DatabaseID, "node_name", input.NodeName) + logger.Info("verifying node resumed replicating after major-version upgrade") + + deadline := time.Now().Add(verifyNodeReplicatingTimeout) + var lastReason string + + for { + reason, err := checkNodeReplicating(ctx, a.DatabaseService, input.DatabaseID, input.NodeName, input.ExpectedSubscriptions) + if err != nil { + return nil, err + } + if reason == "" { + logger.Info("node is replicating") + return &VerifyNodeReplicatingOutput{}, nil + } + lastReason = reason + + if time.Now().After(deadline) { + return nil, fmt.Errorf( + "node %q did not resume replicating within %s after its major-version upgrade: %s", + input.NodeName, verifyNodeReplicatingTimeout, lastReason, + ) + } + + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-time.After(verifyNodeReplicatingPollInterval): + } + } +} + +// checkNodeReplicating returns "" if the node's primary instance reports at +// least expectedSubscriptions subscriptions, all replicating, per the most +// recently collected (and not stale) instance status. Otherwise it returns a +// human-readable reason the check hasn't passed yet, to fail with a specific +// error if the overall timeout is reached instead of a bare "timed out." +func checkNodeReplicating(ctx context.Context, dbSvc *database.Service, databaseID, nodeName string, expectedSubscriptions int) (string, error) { + instances, err := dbSvc.GetInstances(ctx, databaseID) + if err != nil { + return "", fmt.Errorf("failed to get instances: %w", err) + } + + var primary *database.Instance + for _, instance := range instances { + if instance.NodeName != nodeName { + continue + } + if instance.Status != nil && instance.Status.IsPrimary() { + primary = instance + break + } + } + if primary == nil { + return fmt.Sprintf("no primary instance found for node %q yet", nodeName), nil + } + if primary.Status == nil || primary.Status.IsStale() { + return fmt.Sprintf("status for node %q's primary instance %q is missing or stale", nodeName, primary.InstanceID), nil + } + if len(primary.Status.Subscriptions) < expectedSubscriptions { + return fmt.Sprintf("node %q's primary reports %d of %d expected subscriptions", + nodeName, len(primary.Status.Subscriptions), expectedSubscriptions), nil + } + for _, sub := range primary.Status.Subscriptions { + if sub.Status != postgres.SubStatusReplicating { + return fmt.Sprintf("subscription %q (from %q) has status %q, not %q", + sub.Name, sub.ProviderNode, sub.Status, postgres.SubStatusReplicating), nil + } + } + return "", nil +} diff --git a/server/internal/workflows/activities/verify_node_replicating_test.go b/server/internal/workflows/activities/verify_node_replicating_test.go new file mode 100644 index 00000000..9077acfd --- /dev/null +++ b/server/internal/workflows/activities/verify_node_replicating_test.go @@ -0,0 +1,119 @@ +package activities + +import ( + "testing" + "time" + + "github.com/google/uuid" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/pgEdge/control-plane/server/internal/config" + "github.com/pgEdge/control-plane/server/internal/database" + "github.com/pgEdge/control-plane/server/internal/logging" + "github.com/pgEdge/control-plane/server/internal/patroni" + "github.com/pgEdge/control-plane/server/internal/postgres" + "github.com/pgEdge/control-plane/server/internal/storage/storagetest" +) + +// newTestDBService constructs a database.Service wired to an embedded test +// etcd, with no orchestrator — checkNodeReplicating never calls it, since it +// only reads back already-collected instance status. +func newTestDBService(t *testing.T) *database.Service { + t.Helper() + srv := storagetest.NewEtcdTestServer(t) + client := srv.Client(t) + store := database.NewStore(client, uuid.NewString()) + logFactory, err := logging.NewFactory(config.Config{}, zerolog.Nop()) + require.NoError(t, err) + return database.NewService(config.Config{}, nil, store, nil, nil, logFactory) +} + +// putInstance creates (or upserts) an instance record and its status. +func putInstance(t *testing.T, dbSvc *database.Service, databaseID, instanceID, nodeName string, role patroni.InstanceRole, subs []database.SubscriptionStatus, statusUpdatedAt time.Time) { + t.Helper() + ctx := t.Context() + require.NoError(t, dbSvc.UpdateInstance(ctx, &database.InstanceUpdateOptions{ + InstanceID: instanceID, + DatabaseID: databaseID, + HostID: "host-1", + NodeName: nodeName, + State: database.InstanceStateAvailable, + })) + require.NoError(t, dbSvc.UpdateInstanceStatus(ctx, databaseID, instanceID, &database.InstanceStatus{ + Role: &role, + Subscriptions: subs, + StatusUpdatedAt: &statusUpdatedAt, + })) +} + +func TestCheckNodeReplicating(t *testing.T) { + replicatingSub := func(name, provider string) database.SubscriptionStatus { + return database.SubscriptionStatus{Name: name, ProviderNode: provider, Status: postgres.SubStatusReplicating} + } + downSub := func(name, provider string) database.SubscriptionStatus { + return database.SubscriptionStatus{Name: name, ProviderNode: provider, Status: "down"} + } + + t.Run("single-node database: zero expected, zero observed passes", func(t *testing.T) { + dbSvc := newTestDBService(t) + putInstance(t, dbSvc, "db1", "db1-n1", "n1", patroni.InstanceRolePrimary, nil, time.Now()) + + reason, err := checkNodeReplicating(t.Context(), dbSvc, "db1", "n1", 0) + require.NoError(t, err) + assert.Empty(t, reason) + }) + + t.Run("multi-node database: zero observed when subscriptions are expected does not pass", func(t *testing.T) { + dbSvc := newTestDBService(t) + putInstance(t, dbSvc, "db2", "db2-n1", "n1", patroni.InstanceRolePrimary, nil, time.Now()) + + reason, err := checkNodeReplicating(t.Context(), dbSvc, "db2", "n1", 2) + require.NoError(t, err) + assert.NotEmpty(t, reason, "must not pass just because subscriptions haven't registered yet") + assert.Contains(t, reason, "0 of 2 expected subscriptions") + }) + + t.Run("multi-node database: all expected subscriptions replicating passes", func(t *testing.T) { + dbSvc := newTestDBService(t) + subs := []database.SubscriptionStatus{replicatingSub("sub_n1n2", "n2"), replicatingSub("sub_n1n3", "n3")} + putInstance(t, dbSvc, "db3", "db3-n1", "n1", patroni.InstanceRolePrimary, subs, time.Now()) + + reason, err := checkNodeReplicating(t.Context(), dbSvc, "db3", "n1", 2) + require.NoError(t, err) + assert.Empty(t, reason) + }) + + t.Run("a subscription not yet replicating does not pass", func(t *testing.T) { + dbSvc := newTestDBService(t) + subs := []database.SubscriptionStatus{replicatingSub("sub_n1n2", "n2"), downSub("sub_n1n3", "n3")} + putInstance(t, dbSvc, "db4", "db4-n1", "n1", patroni.InstanceRolePrimary, subs, time.Now()) + + reason, err := checkNodeReplicating(t.Context(), dbSvc, "db4", "n1", 2) + require.NoError(t, err) + assert.Contains(t, reason, `"down"`) + }) + + t.Run("no primary found yet does not pass", func(t *testing.T) { + dbSvc := newTestDBService(t) + reason, err := checkNodeReplicating(t.Context(), dbSvc, "db5", "n1", 2) + require.NoError(t, err) + assert.Contains(t, reason, "no primary instance found") + }) + + t.Run("stale status does not pass", func(t *testing.T) { + dbSvc := newTestDBService(t) + subs := []database.SubscriptionStatus{replicatingSub("sub_n1n2", "n2"), replicatingSub("sub_n1n3", "n3")} + putInstance(t, dbSvc, "db6", "db6-n1", "n1", patroni.InstanceRolePrimary, subs, time.Now().Add(-time.Hour)) + + // storedToInstance already demotes a stale "available" instance to + // State: Unknown, Status: nil before checkNodeReplicating ever sees + // it, so this surfaces as "no primary found" rather than reaching + // checkNodeReplicating's own staleness branch — either way, it must + // not pass. + reason, err := checkNodeReplicating(t.Context(), dbSvc, "db6", "n1", 2) + require.NoError(t, err) + assert.NotEmpty(t, reason) + }) +} diff --git a/server/internal/workflows/major_version_upgrade.go b/server/internal/workflows/major_version_upgrade.go new file mode 100644 index 00000000..66f6d2b6 --- /dev/null +++ b/server/internal/workflows/major_version_upgrade.go @@ -0,0 +1,219 @@ +package workflows + +import ( + "errors" + "fmt" + + "github.com/cschleiden/go-workflows/workflow" + "github.com/google/uuid" + + "github.com/pgEdge/control-plane/server/internal/database" + "github.com/pgEdge/control-plane/server/internal/database/operations" + "github.com/pgEdge/control-plane/server/internal/resource" + "github.com/pgEdge/control-plane/server/internal/task" + "github.com/pgEdge/control-plane/server/internal/workflows/activities" +) + +// MajorVersionUpgradeInput drives a rolling Spock major-version upgrade +// (e.g. 5.x to 6.x). Deliberately separate from UpdateDatabaseInput: rather +// than redeploy every node onto the new image at once the way a same-major +// minor/patch bump does, this walks NodeOrder one node at a time, verifying +// each node actually resumed replicating before moving to the next — the +// only upgrade path proven to work for a Spock major bump (see the +// compatibility finding below), since a from-scratch Spock 6 subscription +// syncing from a Spock 5 peer fails outright (spock.read_peer_progress does +// not exist on 5.x), which rules out any mechanism that would establish a +// brand-new cross-major subscription. +type MajorVersionUpgradeInput struct { + TaskID uuid.UUID `json:"task_id"` + Spec *database.Spec `json:"spec"` + TargetSpockVersion string `json:"target_spock_version"` + Image string `json:"image"` + NodeOrder []string `json:"node_order"` +} + +type MajorVersionUpgradeOutput struct { + Updated *resource.State `json:"current"` +} + +func (w *Workflows) MajorVersionUpgrade(ctx workflow.Context, input *MajorVersionUpgradeInput) (*MajorVersionUpgradeOutput, error) { + logger := workflow.Logger(ctx).With("database_id", input.Spec.DatabaseID) + defer func() { + if errors.Is(ctx.Err(), workflow.Canceled) { + logger.Warn("workflow was canceled") + cleanupCtx := workflow.NewDisconnectedContext(ctx) + + updateStateInput := &activities.UpdateDbStateInput{ + DatabaseID: input.Spec.DatabaseID, + State: database.DatabaseStateFailed, + } + if _, err := w.Activities.ExecuteUpdateDbState(cleanupCtx, updateStateInput).Get(cleanupCtx); err != nil { + logger.With("error", err).Error("failed to update database state") + } + + w.cancelTask(cleanupCtx, task.ScopeDatabase, input.Spec.DatabaseID, input.TaskID, logger) + } + }() + + logger.Info("starting spock major-version upgrade") + + handleError := func(cause error) error { + logger.With("error", cause).Error("failed to apply spock major-version upgrade") + + updateStateInput := &activities.UpdateDbStateInput{ + DatabaseID: input.Spec.DatabaseID, + State: database.DatabaseStateFailed, + } + if _, stateErr := w.Activities.ExecuteUpdateDbState(ctx, updateStateInput).Get(ctx); stateErr != nil { + logger.With("error", stateErr).Error("failed to update database state") + } + + updateTaskInput := &activities.UpdateTaskInput{ + Scope: task.ScopeDatabase, + EntityID: input.Spec.DatabaseID, + TaskID: input.TaskID, + UpdateOptions: task.UpdateFail(cause), + } + _ = w.updateTask(ctx, logger, updateTaskInput) + + return cause + } + + logEvent := func(message string) { + if err := w.logTaskEvent(ctx, task.ScopeDatabase, input.Spec.DatabaseID, input.TaskID, + task.LogEntry{Message: message}); err != nil { + logger.With("error", err).Error("failed to log task event") + } + } + + updateTaskInput := &activities.UpdateTaskInput{ + Scope: task.ScopeDatabase, + EntityID: input.Spec.DatabaseID, + TaskID: input.TaskID, + UpdateOptions: task.UpdateStart(), + } + if err := w.updateTask(ctx, logger, updateTaskInput); err != nil { + return nil, handleError(err) + } + + if len(input.NodeOrder) == 0 { + return nil, handleError(errors.New("node_order must not be empty")) + } + + spec := input.Spec + var lastState *resource.State + + for i, nodeName := range input.NodeOrder { + logEvent(fmt.Sprintf("upgrading node %q to spock %s via image %s (%d/%d)", nodeName, input.TargetSpockVersion, input.Image, i+1, len(input.NodeOrder))) + + nodeSpec := spec.Clone() + found := false + for _, node := range nodeSpec.Nodes { + if node.Name != nodeName { + continue + } + // Only the Spock version needs to change here. SwarmOpts.Image is a + // user-only field the CP must never write; SwarmOpts.ResolvedImage is + // the CP-managed one, and ReconcileInstanceSpec already clears it and + // re-derives the correct image from the manifest whenever + // PgEdgeVersion changes — the same mechanism ApplyUpgrade relies on + // for Postgres minor bumps. Setting Image here would silently + // clobber a real per-node pin. + node.SpockVersion = input.TargetSpockVersion + found = true + break + } + if !found { + return nil, handleError(fmt.Errorf("node %q not found in database spec", nodeName)) + } + + // Persist this node's spec change durably, one node at a time, before + // applying it — via the privileged path that bypasses + // ValidateChangedSpec's ordinary same-major guard, so that a + // crashed/resumed workflow can tell exactly which nodes have already + // been rolled just by reading the spec back. + updateSpecInput := &activities.UpdateSpecInput{ + Spec: nodeSpec, + State: database.DatabaseStateModifying, + } + if _, err := w.Activities.ExecuteUpdateSpec(ctx, updateSpecInput).Get(ctx); err != nil { + return nil, handleError(fmt.Errorf("failed to persist spec change for node %q: %w", nodeName, err)) + } + + refreshCurrentInput := &RefreshCurrentStateInput{ + DatabaseID: input.Spec.DatabaseID, + TaskID: input.TaskID, + } + refreshCurrentOutput, err := w.ExecuteRefreshCurrentState(ctx, refreshCurrentInput).Get(ctx) + if err != nil { + return nil, handleError(fmt.Errorf("failed to get current state before upgrading node %q: %w", nodeName, err)) + } + current := refreshCurrentOutput.State + + planInput := &PlanUpdateInput{ + Spec: nodeSpec, + Current: current, + Options: operations.UpdateDatabaseOptions{}, + } + planOutput, err := w.ExecutePlanUpdate(ctx, planInput).Get(ctx) + if err != nil { + return nil, handleError(fmt.Errorf("failed to plan upgrade for node %q: %w", nodeName, err)) + } + + if err := w.persistPlans(ctx, input.Spec.DatabaseID, input.TaskID, planOutput.Plans); err != nil { + return nil, handleError(err) + } + + if err := w.applyPlans(ctx, input.Spec.DatabaseID, input.TaskID, current, nil, planOutput.Plans); err != nil { + return nil, handleError(fmt.Errorf("failed to redeploy node %q: %w", nodeName, err)) + } + + // The fail-loud check: don't move on to the next node — and don't + // leave a future add-node/other operation to silently discover this + // later — until this node's replication has actually resumed. + verifyInput := &activities.VerifyNodeReplicatingInput{ + DatabaseID: input.Spec.DatabaseID, + NodeName: nodeName, + ExpectedSubscriptions: len(nodeSpec.Nodes) - 1, + } + if _, err := w.Activities.ExecuteVerifyNodeReplicating(ctx, verifyInput).Get(ctx); err != nil { + return nil, handleError(err) + } + + logEvent(fmt.Sprintf("node %q upgraded and replicating on spock %s", nodeName, input.TargetSpockVersion)) + + spec = nodeSpec + lastState = current + } + + // Every node is now on the target Spock major. Normalize the spec: move + // the version onto the database-level field and clear the now-redundant + // per-node overrides, so the database looks like an ordinary, + // steady-state spec again rather than one perpetually "mid-upgrade". + finalSpec := spec.Clone() + finalSpec.SpockVersion = input.TargetSpockVersion + for _, node := range finalSpec.Nodes { + node.SpockVersion = "" + } + + finalizeInput := &activities.UpdateSpecInput{ + Spec: finalSpec, + State: database.DatabaseStateAvailable, + } + if _, err := w.Activities.ExecuteUpdateSpec(ctx, finalizeInput).Get(ctx); err != nil { + return nil, handleError(fmt.Errorf("failed to normalize spec after major-version upgrade: %w", err)) + } + + updateTaskInput = &activities.UpdateTaskInput{ + Scope: task.ScopeDatabase, + EntityID: input.Spec.DatabaseID, + TaskID: input.TaskID, + UpdateOptions: task.UpdateComplete(), + } + if err := w.updateTask(ctx, logger, updateTaskInput); err != nil { + return nil, handleError(err) + } + logger.Info("successfully completed spock major-version upgrade") + + return &MajorVersionUpgradeOutput{Updated: lastState}, nil +} diff --git a/server/internal/workflows/service.go b/server/internal/workflows/service.go index 29a1cb67..e5b27eb1 100644 --- a/server/internal/workflows/service.go +++ b/server/internal/workflows/service.go @@ -118,6 +118,34 @@ func (s *Service) UpgradeDatabase(ctx context.Context, db *database.Database) (* return t, nil } +// UpgradeDatabaseMajorVersion kicks off a dedicated Spock major-version +// upgrade, rolling through result.NodeOrder one node at a time. Separate +// from UpgradeDatabase (which reuses the plain UpdateDatabase workflow for +// same-major minor/patch bumps) since a major bump needs its own dedicated +// per-node workflow, not a single uniform redeploy. +func (s *Service) UpgradeDatabaseMajorVersion(ctx context.Context, result *database.ApplyMajorUpgradeResult) (*task.Task, error) { + databaseID := result.Database.DatabaseID + t, err := s.taskSvc.CreateTask(ctx, task.Options{ + Scope: task.ScopeDatabase, + DatabaseID: databaseID, + Type: task.TypeMajorUpgrade, + }) + if err != nil { + return nil, fmt.Errorf("failed to create major-version upgrade task: %w", err) + } + input := &MajorVersionUpgradeInput{ + TaskID: t.TaskID, + Spec: result.Database.Spec, + TargetSpockVersion: result.TargetSpockVersion, + Image: result.Image, + NodeOrder: result.NodeOrder, + } + if err := s.createWorkflow(ctx, t, s.workflows.MajorVersionUpgrade, input); err != nil { + return nil, err + } + return t, nil +} + func (s *Service) DeleteDatabase(ctx context.Context, db *database.Database) (*task.Task, error) { t, err := s.taskSvc.CreateTask(ctx, task.Options{ Scope: task.ScopeDatabase, diff --git a/server/internal/workflows/workflows.go b/server/internal/workflows/workflows.go index 21f94199..9db8a407 100644 --- a/server/internal/workflows/workflows.go +++ b/server/internal/workflows/workflows.go @@ -24,6 +24,7 @@ func (w *Workflows) Register(work *worker.Worker) error { work.RegisterWorkflow(w.CreatePgBackRestBackup), work.RegisterWorkflow(w.Failover), work.RegisterWorkflow(w.DeleteDatabase), + work.RegisterWorkflow(w.MajorVersionUpgrade), work.RegisterWorkflow(w.PgBackRestRestore), work.RegisterWorkflow(w.PlanRestore), work.RegisterWorkflow(w.PlanUpdate),