From 0ffa2b02b6cb004aaa6c5a64a7fe3cd323d17d20 Mon Sep 17 00:00:00 2001 From: Siva Date: Mon, 22 Jun 2026 21:26:32 +0530 Subject: [PATCH] feat: add POST /v1/databases/{id}/upgrade endpoint --- api/apiv1/design/api.go | 27 + api/apiv1/design/database.go | 39 + api/apiv1/gen/control_plane/client.go | 23 +- api/apiv1/gen/control_plane/endpoints.go | 12 + api/apiv1/gen/control_plane/service.go | 31 +- api/apiv1/gen/http/cli/control_plane/cli.go | 34 +- .../gen/http/control_plane/client/cli.go | 41 + .../gen/http/control_plane/client/client.go | 29 + .../control_plane/client/encode_decode.go | 180 + .../gen/http/control_plane/client/paths.go | 5 + .../gen/http/control_plane/client/types.go | 204 + .../control_plane/server/encode_decode.go | 151 + .../gen/http/control_plane/server/paths.go | 5 + .../gen/http/control_plane/server/server.go | 58 + .../gen/http/control_plane/server/types.go | 181 + api/apiv1/gen/http/openapi.json | 137 + api/apiv1/gen/http/openapi.yaml | 96 + api/apiv1/gen/http/openapi3.json | 9054 +++++++++++------ api/apiv1/gen/http/openapi3.yaml | 4627 ++++++--- server/internal/api/apiv1/errors.go | 2 + .../internal/api/apiv1/post_init_handlers.go | 25 + .../internal/api/apiv1/pre_init_handlers.go | 4 + .../internal/database/apply_upgrade_test.go | 221 + server/internal/database/orchestrator.go | 8 + server/internal/database/service.go | 165 +- .../orchestrator/swarm/find_upgrade_test.go | 199 + server/internal/orchestrator/swarm/images.go | 16 + .../orchestrator/swarm/orchestrator.go | 38 + .../orchestrator/systemd/orchestrator.go | 4 + server/internal/task/task.go | 1 + server/internal/workflows/service.go | 21 + 31 files changed, 11195 insertions(+), 4443 deletions(-) create mode 100644 server/internal/database/apply_upgrade_test.go create mode 100644 server/internal/orchestrator/swarm/find_upgrade_test.go diff --git a/api/apiv1/design/api.go b/api/apiv1/design/api.go index a8cd55bb..b56d7254 100644 --- a/api/apiv1/design/api.go +++ b/api/apiv1/design/api.go @@ -309,6 +309,33 @@ var _ = g.Service("control-plane", func() { }) }) + g.Method("apply-upgrade", func() { + g.Description("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.") + g.Meta("openapi:summary", "Apply database 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", ApplyUpgradeRequest) + + g.Required("database_id", "request") + }) + g.Result(ApplyUpgradeResponse) + 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") + 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 1130b517..52a237d7 100644 --- a/api/apiv1/design/database.go +++ b/api/apiv1/design/database.go @@ -1327,6 +1327,45 @@ var DeleteDatabaseResponse = g.Type("DeleteDatabaseResponse", func() { }) }) +var ApplyUpgradeRequest = g.Type("ApplyUpgradeRequest", func() { + g.Attribute("image", g.String, func() { + g.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.") + g.Example("ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.8-standard-1") + g.MinLength(1) + g.Meta("struct:tag:json", "image") + }) + g.Required("image") +}) + +var ApplyUpgradeResponse = g.Type("ApplyUpgradeResponse", func() { + g.Attribute("task", Task, func() { + g.Description("The task tracking the 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") + + g.Example(map[string]any{ + "database": map[string]any{ + "created_at": "2025-06-18T16:52:05Z", + "id": "storefront", + "state": "modifying", + "updated_at": "2025-06-18T17:58:59Z", + }, + "task": map[string]any{ + "created_at": "2025-06-18T17:58:59Z", + "database_id": "storefront", + "status": "pending", + "task_id": "01978431-b628-758a-aec6-03b331fa1a17", + "type": "upgrade", + }, + }) +}) + 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 93c576c0..5ff8009b 100644 --- a/api/apiv1/gen/control_plane/client.go +++ b/api/apiv1/gen/control_plane/client.go @@ -27,6 +27,7 @@ type Client struct { CreateDatabaseEndpoint goa.Endpoint GetDatabaseEndpoint goa.Endpoint UpdateDatabaseEndpoint goa.Endpoint + ApplyUpgradeEndpoint goa.Endpoint DeleteDatabaseEndpoint goa.Endpoint BackupDatabaseNodeEndpoint goa.Endpoint SwitchoverDatabaseNodeEndpoint goa.Endpoint @@ -47,7 +48,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, 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, 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, @@ -61,6 +62,7 @@ func NewClient(initCluster, joinCluster, getJoinToken, getJoinOptions, getCluste CreateDatabaseEndpoint: createDatabase, GetDatabaseEndpoint: getDatabase, UpdateDatabaseEndpoint: updateDatabase, + ApplyUpgradeEndpoint: applyUpgrade, DeleteDatabaseEndpoint: deleteDatabase, BackupDatabaseNodeEndpoint: backupDatabaseNode, SwitchoverDatabaseNodeEndpoint: switchoverDatabaseNode, @@ -268,6 +270,25 @@ func (c *Client) UpdateDatabase(ctx context.Context, p *UpdateDatabasePayload) ( return ires.(*UpdateDatabaseResponse), nil } +// ApplyUpgrade calls the "apply-upgrade" endpoint of the "control-plane" +// service. +// ApplyUpgrade 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) ApplyUpgrade(ctx context.Context, p *ApplyUpgradePayload) (res *ApplyUpgradeResponse, err error) { + var ires any + ires, err = c.ApplyUpgradeEndpoint(ctx, p) + if err != nil { + return + } + return ires.(*ApplyUpgradeResponse), 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 d04ce97f..281ef4f0 100644 --- a/api/apiv1/gen/control_plane/endpoints.go +++ b/api/apiv1/gen/control_plane/endpoints.go @@ -27,6 +27,7 @@ type Endpoints struct { CreateDatabase goa.Endpoint GetDatabase goa.Endpoint UpdateDatabase goa.Endpoint + ApplyUpgrade goa.Endpoint DeleteDatabase goa.Endpoint BackupDatabaseNode goa.Endpoint SwitchoverDatabaseNode goa.Endpoint @@ -61,6 +62,7 @@ func NewEndpoints(s Service) *Endpoints { CreateDatabase: NewCreateDatabaseEndpoint(s), GetDatabase: NewGetDatabaseEndpoint(s), UpdateDatabase: NewUpdateDatabaseEndpoint(s), + ApplyUpgrade: NewApplyUpgradeEndpoint(s), DeleteDatabase: NewDeleteDatabaseEndpoint(s), BackupDatabaseNode: NewBackupDatabaseNodeEndpoint(s), SwitchoverDatabaseNode: NewSwitchoverDatabaseNodeEndpoint(s), @@ -96,6 +98,7 @@ func (e *Endpoints) Use(m func(goa.Endpoint) goa.Endpoint) { e.CreateDatabase = m(e.CreateDatabase) e.GetDatabase = m(e.GetDatabase) e.UpdateDatabase = m(e.UpdateDatabase) + e.ApplyUpgrade = m(e.ApplyUpgrade) e.DeleteDatabase = m(e.DeleteDatabase) e.BackupDatabaseNode = m(e.BackupDatabaseNode) e.SwitchoverDatabaseNode = m(e.SwitchoverDatabaseNode) @@ -220,6 +223,15 @@ func NewUpdateDatabaseEndpoint(s Service) goa.Endpoint { } } +// NewApplyUpgradeEndpoint returns an endpoint function that calls the method +// "apply-upgrade" of service "control-plane". +func NewApplyUpgradeEndpoint(s Service) goa.Endpoint { + return func(ctx context.Context, req any) (any, error) { + p := req.(*ApplyUpgradePayload) + return s.ApplyUpgrade(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 291b3453..633057cc 100644 --- a/api/apiv1/gen/control_plane/service.go +++ b/api/apiv1/gen/control_plane/service.go @@ -39,6 +39,11 @@ type Service interface { GetDatabase(context.Context, *GetDatabasePayload) (res *Database, err error) // Updates a database with the given specification. UpdateDatabase(context.Context, *UpdateDatabasePayload) (res *UpdateDatabaseResponse, err error) + // 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. + ApplyUpgrade(context.Context, *ApplyUpgradePayload) (res *ApplyUpgradeResponse, err error) // Deletes a database from the cluster. DeleteDatabase(context.Context, *DeleteDatabasePayload) (res *DeleteDatabaseResponse, err error) // Initiates a backup for a database node. @@ -91,7 +96,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 = [29]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", "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 = [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"} // A Control Plane API error. type APIError struct { @@ -101,6 +106,30 @@ type APIError struct { Message string `json:"message"` } +// ApplyUpgradePayload is the payload type of the control-plane service +// apply-upgrade method. +type ApplyUpgradePayload struct { + // ID of the database to upgrade. + DatabaseID Identifier + Request *ApplyUpgradeRequest +} + +type ApplyUpgradeRequest struct { + // 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. + Image string `json:"image"` +} + +// ApplyUpgradeResponse is the result type of the control-plane service +// apply-upgrade method. +type ApplyUpgradeResponse struct { + // The task tracking the upgrade operation. + Task *Task `json:"task"` + // The database being upgraded. + Database *Database `json:"database"` +} + // A newer stable image available for the database in the same Postgres major / // Spock major bucket. type AvailableUpgrade struct { diff --git a/api/apiv1/gen/http/cli/control_plane/cli.go b/api/apiv1/gen/http/cli/control_plane/cli.go index 3c1cda0a..80eebed1 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|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|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)", } } @@ -83,6 +83,10 @@ func ParseEndpoint( controlPlaneUpdateDatabaseForceUpdateFlag = controlPlaneUpdateDatabaseFlags.String("force-update", "", "") controlPlaneUpdateDatabaseRemoveHostFlag = controlPlaneUpdateDatabaseFlags.String("remove-host", "", "") + controlPlaneApplyUpgradeFlags = flag.NewFlagSet("apply-upgrade", flag.ExitOnError) + controlPlaneApplyUpgradeBodyFlag = controlPlaneApplyUpgradeFlags.String("body", "REQUIRED", "") + controlPlaneApplyUpgradeDatabaseIDFlag = controlPlaneApplyUpgradeFlags.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", "", "") @@ -181,6 +185,7 @@ func ParseEndpoint( controlPlaneCreateDatabaseFlags.Usage = controlPlaneCreateDatabaseUsage controlPlaneGetDatabaseFlags.Usage = controlPlaneGetDatabaseUsage controlPlaneUpdateDatabaseFlags.Usage = controlPlaneUpdateDatabaseUsage + controlPlaneApplyUpgradeFlags.Usage = controlPlaneApplyUpgradeUsage controlPlaneDeleteDatabaseFlags.Usage = controlPlaneDeleteDatabaseUsage controlPlaneBackupDatabaseNodeFlags.Usage = controlPlaneBackupDatabaseNodeUsage controlPlaneSwitchoverDatabaseNodeFlags.Usage = controlPlaneSwitchoverDatabaseNodeUsage @@ -269,6 +274,9 @@ func ParseEndpoint( case "update-database": epf = controlPlaneUpdateDatabaseFlags + case "apply-upgrade": + epf = controlPlaneApplyUpgradeFlags + case "delete-database": epf = controlPlaneDeleteDatabaseFlags @@ -378,6 +386,9 @@ func ParseEndpoint( case "update-database": endpoint = c.UpdateDatabase() data, err = controlplanec.BuildUpdateDatabasePayload(*controlPlaneUpdateDatabaseBodyFlag, *controlPlaneUpdateDatabaseDatabaseIDFlag, *controlPlaneUpdateDatabaseForceUpdateFlag, *controlPlaneUpdateDatabaseRemoveHostFlag) + case "apply-upgrade": + endpoint = c.ApplyUpgrade() + data, err = controlplanec.BuildApplyUpgradePayload(*controlPlaneApplyUpgradeBodyFlag, *controlPlaneApplyUpgradeDatabaseIDFlag) case "delete-database": endpoint = c.DeleteDatabase() data, err = controlplanec.BuildDeleteDatabasePayload(*controlPlaneDeleteDatabaseDatabaseIDFlag, *controlPlaneDeleteDatabaseForceFlag) @@ -456,6 +467,7 @@ func controlPlaneUsage() { fmt.Fprintln(os.Stderr, ` create-database: Creates a new database in the cluster.`) 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, ` 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.`) @@ -697,6 +709,26 @@ func controlPlaneUpdateDatabaseUsage() { fmt.Fprintf(os.Stderr, " %s %s\n", os.Args[0], "control-plane update-database --body '{\n \"spec\": {\n \"database_name\": \"storefront\",\n \"database_users\": [\n {\n \"attributes\": [\n \"LOGIN\",\n \"SUPERUSER\"\n ],\n \"db_owner\": true,\n \"username\": \"admin\"\n }\n ],\n \"nodes\": [\n {\n \"backup_config\": {\n \"repositories\": [\n {\n \"s3_bucket\": \"storefront-db-backups-us-east-1\",\n \"type\": \"s3\"\n }\n ]\n },\n \"host_ids\": [\n \"us-east-1\"\n ],\n \"name\": \"n1\"\n },\n {\n \"backup_config\": {\n \"repositories\": [\n {\n \"s3_bucket\": \"storefront-db-backups-ap-south-1\",\n \"type\": \"s3\"\n }\n ]\n },\n \"host_ids\": [\n \"ap-south-1\"\n ],\n \"name\": \"n2\"\n },\n {\n \"backup_config\": {\n \"repositories\": [\n {\n \"s3_bucket\": \"storefront-db-backups-eu-central-1\",\n \"type\": \"s3\"\n }\n ]\n },\n \"host_ids\": [\n \"eu-central-1\"\n ],\n \"name\": \"n3\",\n \"restore_config\": {\n \"repository\": {\n \"s3_bucket\": \"storefront-db-backups-us-east-1\",\n \"type\": \"s3\"\n },\n \"source_database_id\": \"storefront\",\n \"source_database_name\": \"storefront\",\n \"source_node_name\": \"n1\"\n }\n }\n ],\n \"port\": 5432\n }\n }' --database-id \"76f9b8c0-4958-11f0-a489-3bb29577c696\" --force-update true --remove-host '[\n \"In doloremque.\",\n \"Officia rerum eum nemo autem iste illo.\",\n \"Non libero quibusdam et sapiente.\"\n ]'") } +func controlPlaneApplyUpgradeUsage() { + // Header with flags + fmt.Fprintf(os.Stderr, "%s [flags] control-plane apply-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 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.`) + + // 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-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 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 2bc302a7..743009be 100644 --- a/api/apiv1/gen/http/control_plane/client/cli.go +++ b/api/apiv1/gen/http/control_plane/client/cli.go @@ -373,6 +373,47 @@ func BuildUpdateDatabasePayload(controlPlaneUpdateDatabaseBody string, controlPl return res, nil } +// BuildApplyUpgradePayload builds the payload for the control-plane +// apply-upgrade endpoint from CLI flags. +func BuildApplyUpgradePayload(controlPlaneApplyUpgradeBody string, controlPlaneApplyUpgradeDatabaseID string) (*controlplane.ApplyUpgradePayload, error) { + var err error + var body ApplyUpgradeRequestBody + { + err = json.Unmarshal([]byte(controlPlaneApplyUpgradeBody), &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:17.10-spock5.0.8-standard-1\"\n }'") + } + 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 = controlPlaneApplyUpgradeDatabaseID + 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.ApplyUpgradeRequest{ + Image: body.Image, + } + res := &controlplane.ApplyUpgradePayload{ + 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 908aa546..cdf440f1 100644 --- a/api/apiv1/gen/http/control_plane/client/client.go +++ b/api/apiv1/gen/http/control_plane/client/client.go @@ -65,6 +65,10 @@ type Client struct { // update-database endpoint. UpdateDatabaseDoer goahttp.Doer + // ApplyUpgrade Doer is the HTTP client used to make requests to the + // apply-upgrade endpoint. + ApplyUpgradeDoer goahttp.Doer + // DeleteDatabase Doer is the HTTP client used to make requests to the // delete-database endpoint. DeleteDatabaseDoer goahttp.Doer @@ -166,6 +170,7 @@ func NewClient( CreateDatabaseDoer: doer, GetDatabaseDoer: doer, UpdateDatabaseDoer: doer, + ApplyUpgradeDoer: doer, DeleteDatabaseDoer: doer, BackupDatabaseNodeDoer: doer, SwitchoverDatabaseNodeDoer: doer, @@ -459,6 +464,30 @@ func (c *Client) UpdateDatabase() goa.Endpoint { } } +// ApplyUpgrade returns an endpoint that makes HTTP requests to the +// control-plane service apply-upgrade server. +func (c *Client) ApplyUpgrade() goa.Endpoint { + var ( + encodeRequest = EncodeApplyUpgradeRequest(c.encoder) + decodeResponse = DecodeApplyUpgradeResponse(c.decoder, c.RestoreResponseBody) + ) + return func(ctx context.Context, v any) (any, error) { + req, err := c.BuildApplyUpgradeRequest(ctx, v) + if err != nil { + return nil, err + } + err = encodeRequest(req, v) + if err != nil { + return nil, err + } + resp, err := c.ApplyUpgradeDoer.Do(req) + if err != nil { + return nil, goahttp.ErrRequestError("control-plane", "apply-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 7dd4a437..5907dae1 100644 --- a/api/apiv1/gen/http/control_plane/client/encode_decode.go +++ b/api/apiv1/gen/http/control_plane/client/encode_decode.go @@ -1510,6 +1510,186 @@ func DecodeUpdateDatabaseResponse(decoder func(*http.Response) goahttp.Decoder, } } +// BuildApplyUpgradeRequest instantiates a HTTP request object with method and +// path set to call the "control-plane" service "apply-upgrade" endpoint +func (c *Client) BuildApplyUpgradeRequest(ctx context.Context, v any) (*http.Request, error) { + var ( + databaseID string + ) + { + p, ok := v.(*controlplane.ApplyUpgradePayload) + if !ok { + return nil, goahttp.ErrInvalidType("control-plane", "apply-upgrade", "*controlplane.ApplyUpgradePayload", v) + } + databaseID = string(p.DatabaseID) + } + u := &url.URL{Scheme: c.scheme, Host: c.host, Path: ApplyUpgradeControlPlanePath(databaseID)} + req, err := http.NewRequest("POST", u.String(), nil) + if err != nil { + return nil, goahttp.ErrInvalidURL("control-plane", "apply-upgrade", u.String(), err) + } + if ctx != nil { + req = req.WithContext(ctx) + } + + return req, nil +} + +// EncodeApplyUpgradeRequest returns an encoder for requests sent to the +// control-plane apply-upgrade server. +func EncodeApplyUpgradeRequest(encoder func(*http.Request) goahttp.Encoder) func(*http.Request, any) error { + return func(req *http.Request, v any) error { + p, ok := v.(*controlplane.ApplyUpgradePayload) + if !ok { + return goahttp.ErrInvalidType("control-plane", "apply-upgrade", "*controlplane.ApplyUpgradePayload", v) + } + body := NewApplyUpgradeRequestBody(p) + if err := encoder(req).Encode(&body); err != nil { + return goahttp.ErrEncodingError("control-plane", "apply-upgrade", err) + } + return nil + } +} + +// DecodeApplyUpgradeResponse returns a decoder for responses returned by the +// control-plane apply-upgrade endpoint. restoreBody controls whether the +// response body should be restored after having been read. +// DecodeApplyUpgradeResponse 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 DecodeApplyUpgradeResponse(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 ApplyUpgradeResponseBody + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("control-plane", "apply-upgrade", err) + } + err = ValidateApplyUpgradeResponseBody(&body) + if err != nil { + return nil, goahttp.ErrValidationError("control-plane", "apply-upgrade", err) + } + res := NewApplyUpgradeResponseOK(&body) + return res, nil + case http.StatusConflict: + en := resp.Header.Get("goa-error") + switch en { + case "cluster_not_initialized": + var ( + body ApplyUpgradeClusterNotInitializedResponseBody + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("control-plane", "apply-upgrade", err) + } + err = ValidateApplyUpgradeClusterNotInitializedResponseBody(&body) + if err != nil { + return nil, goahttp.ErrValidationError("control-plane", "apply-upgrade", err) + } + return nil, NewApplyUpgradeClusterNotInitialized(&body) + case "database_not_modifiable": + var ( + body ApplyUpgradeDatabaseNotModifiableResponseBody + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("control-plane", "apply-upgrade", err) + } + err = ValidateApplyUpgradeDatabaseNotModifiableResponseBody(&body) + if err != nil { + return nil, goahttp.ErrValidationError("control-plane", "apply-upgrade", err) + } + return nil, NewApplyUpgradeDatabaseNotModifiable(&body) + case "operation_already_in_progress": + var ( + body ApplyUpgradeOperationAlreadyInProgressResponseBody + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("control-plane", "apply-upgrade", err) + } + err = ValidateApplyUpgradeOperationAlreadyInProgressResponseBody(&body) + if err != nil { + return nil, goahttp.ErrValidationError("control-plane", "apply-upgrade", err) + } + return nil, NewApplyUpgradeOperationAlreadyInProgress(&body) + default: + body, _ := io.ReadAll(resp.Body) + return nil, goahttp.ErrInvalidResponse("control-plane", "apply-upgrade", resp.StatusCode, string(body)) + } + case http.StatusBadRequest: + var ( + body ApplyUpgradeInvalidInputResponseBody + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("control-plane", "apply-upgrade", err) + } + err = ValidateApplyUpgradeInvalidInputResponseBody(&body) + if err != nil { + return nil, goahttp.ErrValidationError("control-plane", "apply-upgrade", err) + } + return nil, NewApplyUpgradeInvalidInput(&body) + case http.StatusNotFound: + var ( + body ApplyUpgradeNotFoundResponseBody + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("control-plane", "apply-upgrade", err) + } + err = ValidateApplyUpgradeNotFoundResponseBody(&body) + if err != nil { + return nil, goahttp.ErrValidationError("control-plane", "apply-upgrade", err) + } + return nil, NewApplyUpgradeNotFound(&body) + case http.StatusInternalServerError: + var ( + body ApplyUpgradeServerErrorResponseBody + err error + ) + err = decoder(resp).Decode(&body) + if err != nil { + return nil, goahttp.ErrDecodingError("control-plane", "apply-upgrade", err) + } + err = ValidateApplyUpgradeServerErrorResponseBody(&body) + if err != nil { + return nil, goahttp.ErrValidationError("control-plane", "apply-upgrade", err) + } + return nil, NewApplyUpgradeServerError(&body) + default: + body, _ := io.ReadAll(resp.Body) + return nil, goahttp.ErrInvalidResponse("control-plane", "apply-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) { diff --git a/api/apiv1/gen/http/control_plane/client/paths.go b/api/apiv1/gen/http/control_plane/client/paths.go index 5ba5ea79..c7c78811 100644 --- a/api/apiv1/gen/http/control_plane/client/paths.go +++ b/api/apiv1/gen/http/control_plane/client/paths.go @@ -71,6 +71,11 @@ func UpdateDatabaseControlPlanePath(databaseID string) string { return fmt.Sprintf("/v1/databases/%v", databaseID) } +// ApplyUpgradeControlPlanePath returns the URL path to the control-plane service apply-upgrade HTTP endpoint. +func ApplyUpgradeControlPlanePath(databaseID string) string { + return fmt.Sprintf("/v1/databases/%v/upgrade", 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 cedcd4ae..4cb91a20 100644 --- a/api/apiv1/gen/http/control_plane/client/types.go +++ b/api/apiv1/gen/http/control_plane/client/types.go @@ -56,6 +56,15 @@ type UpdateDatabaseRequestBody struct { Spec *DatabaseSpecRequestBodyRequestBody `json:"spec"` } +// ApplyUpgradeRequestBody is the type of the "control-plane" service +// "apply-upgrade" endpoint HTTP request body. +type ApplyUpgradeRequestBody struct { + // 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. + Image string `json:"image"` +} + // BackupDatabaseNodeRequestBody is the type of the "control-plane" service // "backup-database-node" endpoint HTTP request body. type BackupDatabaseNodeRequestBody struct { @@ -229,6 +238,15 @@ type UpdateDatabaseResponseBody struct { Database *DatabaseResponseBody `json:"database"` } +// ApplyUpgradeResponseBody is the type of the "control-plane" service +// "apply-upgrade" endpoint HTTP response body. +type ApplyUpgradeResponseBody struct { + // The task tracking the 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 { @@ -866,6 +884,65 @@ type UpdateDatabaseServerErrorResponseBody struct { Message *string `json:"message"` } +// ApplyUpgradeClusterNotInitializedResponseBody is the type of the +// "control-plane" service "apply-upgrade" endpoint HTTP response body for the +// "cluster_not_initialized" error. +type ApplyUpgradeClusterNotInitializedResponseBody struct { + // The name of the error. + Name *string `json:"name"` + // The error message. + Message *string `json:"message"` +} + +// ApplyUpgradeDatabaseNotModifiableResponseBody is the type of the +// "control-plane" service "apply-upgrade" endpoint HTTP response body for the +// "database_not_modifiable" error. +type ApplyUpgradeDatabaseNotModifiableResponseBody struct { + // The name of the error. + Name *string `json:"name"` + // The error message. + Message *string `json:"message"` +} + +// ApplyUpgradeOperationAlreadyInProgressResponseBody is the type of the +// "control-plane" service "apply-upgrade" endpoint HTTP response body for the +// "operation_already_in_progress" error. +type ApplyUpgradeOperationAlreadyInProgressResponseBody struct { + // The name of the error. + Name *string `json:"name"` + // The error message. + Message *string `json:"message"` +} + +// ApplyUpgradeInvalidInputResponseBody is the type of the "control-plane" +// service "apply-upgrade" endpoint HTTP response body for the "invalid_input" +// error. +type ApplyUpgradeInvalidInputResponseBody struct { + // The name of the error. + Name *string `json:"name"` + // The error message. + Message *string `json:"message"` +} + +// ApplyUpgradeNotFoundResponseBody is the type of the "control-plane" service +// "apply-upgrade" endpoint HTTP response body for the "not_found" error. +type ApplyUpgradeNotFoundResponseBody struct { + // The name of the error. + Name *string `json:"name"` + // The error message. + Message *string `json:"message"` +} + +// ApplyUpgradeServerErrorResponseBody is the type of the "control-plane" +// service "apply-upgrade" endpoint HTTP response body for the "server_error" +// error. +type ApplyUpgradeServerErrorResponseBody 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. @@ -3095,6 +3172,15 @@ func NewUpdateDatabaseRequestBody(p *controlplane.UpdateDatabasePayload) *Update return body } +// NewApplyUpgradeRequestBody builds the HTTP request body from the payload of +// the "apply-upgrade" endpoint of the "control-plane" service. +func NewApplyUpgradeRequestBody(p *controlplane.ApplyUpgradePayload) *ApplyUpgradeRequestBody { + body := &ApplyUpgradeRequestBody{ + Image: p.Request.Image, + } + return body +} + // NewBackupDatabaseNodeRequestBody builds the HTTP request body from the // payload of the "backup-database-node" endpoint of the "control-plane" // service. @@ -3843,6 +3929,82 @@ func NewUpdateDatabaseServerError(body *UpdateDatabaseServerErrorResponseBody) * return v } +// NewApplyUpgradeResponseOK builds a "control-plane" service "apply-upgrade" +// endpoint result from a HTTP "OK" response. +func NewApplyUpgradeResponseOK(body *ApplyUpgradeResponseBody) *controlplane.ApplyUpgradeResponse { + v := &controlplane.ApplyUpgradeResponse{} + v.Task = unmarshalTaskResponseBodyToControlplaneTask(body.Task) + v.Database = unmarshalDatabaseResponseBodyToControlplaneDatabase(body.Database) + + return v +} + +// NewApplyUpgradeClusterNotInitialized builds a control-plane service +// apply-upgrade endpoint cluster_not_initialized error. +func NewApplyUpgradeClusterNotInitialized(body *ApplyUpgradeClusterNotInitializedResponseBody) *controlplane.APIError { + v := &controlplane.APIError{ + Name: *body.Name, + Message: *body.Message, + } + + return v +} + +// NewApplyUpgradeDatabaseNotModifiable builds a control-plane service +// apply-upgrade endpoint database_not_modifiable error. +func NewApplyUpgradeDatabaseNotModifiable(body *ApplyUpgradeDatabaseNotModifiableResponseBody) *controlplane.APIError { + v := &controlplane.APIError{ + Name: *body.Name, + Message: *body.Message, + } + + return v +} + +// NewApplyUpgradeOperationAlreadyInProgress builds a control-plane service +// apply-upgrade endpoint operation_already_in_progress error. +func NewApplyUpgradeOperationAlreadyInProgress(body *ApplyUpgradeOperationAlreadyInProgressResponseBody) *controlplane.APIError { + v := &controlplane.APIError{ + Name: *body.Name, + Message: *body.Message, + } + + return v +} + +// NewApplyUpgradeInvalidInput builds a control-plane service apply-upgrade +// endpoint invalid_input error. +func NewApplyUpgradeInvalidInput(body *ApplyUpgradeInvalidInputResponseBody) *controlplane.APIError { + v := &controlplane.APIError{ + Name: *body.Name, + Message: *body.Message, + } + + return v +} + +// NewApplyUpgradeNotFound builds a control-plane service apply-upgrade +// endpoint not_found error. +func NewApplyUpgradeNotFound(body *ApplyUpgradeNotFoundResponseBody) *controlplane.APIError { + v := &controlplane.APIError{ + Name: *body.Name, + Message: *body.Message, + } + + return v +} + +// NewApplyUpgradeServerError builds a control-plane service apply-upgrade +// endpoint server_error error. +func NewApplyUpgradeServerError(body *ApplyUpgradeServerErrorResponseBody) *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 { @@ -4966,6 +5128,12 @@ func ValidateUpdateDatabaseResponseBody(body *UpdateDatabaseResponseBody) (err e return } +// ValidateApplyUpgradeResponseBody runs a no-op validation on +// Apply-UpgradeResponseBody +func ValidateApplyUpgradeResponseBody(body *ApplyUpgradeResponseBody) (err error) { + return +} + // ValidateDeleteDatabaseResponseBody runs a no-op validation on // Delete-DatabaseResponseBody func ValidateDeleteDatabaseResponseBody(body *DeleteDatabaseResponseBody) (err error) { @@ -5320,6 +5488,42 @@ func ValidateUpdateDatabaseServerErrorResponseBody(body *UpdateDatabaseServerErr return } +// ValidateApplyUpgradeClusterNotInitializedResponseBody runs a no-op +// validation on apply-upgrade_cluster_not_initialized_response_body +func ValidateApplyUpgradeClusterNotInitializedResponseBody(body *ApplyUpgradeClusterNotInitializedResponseBody) (err error) { + return +} + +// ValidateApplyUpgradeDatabaseNotModifiableResponseBody runs a no-op +// validation on apply-upgrade_database_not_modifiable_response_body +func ValidateApplyUpgradeDatabaseNotModifiableResponseBody(body *ApplyUpgradeDatabaseNotModifiableResponseBody) (err error) { + return +} + +// ValidateApplyUpgradeOperationAlreadyInProgressResponseBody runs a no-op +// validation on apply-upgrade_operation_already_in_progress_response_body +func ValidateApplyUpgradeOperationAlreadyInProgressResponseBody(body *ApplyUpgradeOperationAlreadyInProgressResponseBody) (err error) { + return +} + +// ValidateApplyUpgradeInvalidInputResponseBody runs a no-op validation on +// apply-upgrade_invalid_input_response_body +func ValidateApplyUpgradeInvalidInputResponseBody(body *ApplyUpgradeInvalidInputResponseBody) (err error) { + return +} + +// ValidateApplyUpgradeNotFoundResponseBody runs a no-op validation on +// apply-upgrade_not_found_response_body +func ValidateApplyUpgradeNotFoundResponseBody(body *ApplyUpgradeNotFoundResponseBody) (err error) { + return +} + +// ValidateApplyUpgradeServerErrorResponseBody runs a no-op validation on +// apply-upgrade_server_error_response_body +func ValidateApplyUpgradeServerErrorResponseBody(body *ApplyUpgradeServerErrorResponseBody) (err error) { + return +} + // ValidateDeleteDatabaseClusterNotInitializedResponseBody runs a no-op // validation on delete-database_cluster_not_initialized_response_body func ValidateDeleteDatabaseClusterNotInitializedResponseBody(body *DeleteDatabaseClusterNotInitializedResponseBody) (err error) { 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 89dc17d6..bd6c84d1 100644 --- a/api/apiv1/gen/http/control_plane/server/encode_decode.go +++ b/api/apiv1/gen/http/control_plane/server/encode_decode.go @@ -1181,6 +1181,157 @@ func EncodeUpdateDatabaseError(encoder func(context.Context, http.ResponseWriter } } +// EncodeApplyUpgradeResponse returns an encoder for responses returned by the +// control-plane apply-upgrade endpoint. +func EncodeApplyUpgradeResponse(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.ApplyUpgradeResponse) + enc := encoder(ctx, w) + body := NewApplyUpgradeResponseBody(res) + w.WriteHeader(http.StatusOK) + return enc.Encode(body) + } +} + +// DecodeApplyUpgradeRequest returns a decoder for requests sent to the +// control-plane apply-upgrade endpoint. +func DecodeApplyUpgradeRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.Decoder) func(*http.Request) (*controlplane.ApplyUpgradePayload, error) { + return func(r *http.Request) (*controlplane.ApplyUpgradePayload, error) { + var ( + body ApplyUpgradeRequestBody + 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 = ValidateApplyUpgradeRequestBody(&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 := NewApplyUpgradePayload(&body, databaseID) + + return payload, nil + } +} + +// EncodeApplyUpgradeError returns an encoder for errors returned by the +// apply-upgrade control-plane endpoint. +func EncodeApplyUpgradeError(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 = NewApplyUpgradeClusterNotInitializedResponseBody(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 = NewApplyUpgradeDatabaseNotModifiableResponseBody(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 = NewApplyUpgradeOperationAlreadyInProgressResponseBody(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 = NewApplyUpgradeInvalidInputResponseBody(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 = NewApplyUpgradeNotFoundResponseBody(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 = NewApplyUpgradeServerErrorResponseBody(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 { diff --git a/api/apiv1/gen/http/control_plane/server/paths.go b/api/apiv1/gen/http/control_plane/server/paths.go index 524c024d..8e517da2 100644 --- a/api/apiv1/gen/http/control_plane/server/paths.go +++ b/api/apiv1/gen/http/control_plane/server/paths.go @@ -71,6 +71,11 @@ func UpdateDatabaseControlPlanePath(databaseID string) string { return fmt.Sprintf("/v1/databases/%v", databaseID) } +// ApplyUpgradeControlPlanePath returns the URL path to the control-plane service apply-upgrade HTTP endpoint. +func ApplyUpgradeControlPlanePath(databaseID string) string { + return fmt.Sprintf("/v1/databases/%v/upgrade", 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 0abbbcab..49d74c2a 100644 --- a/api/apiv1/gen/http/control_plane/server/server.go +++ b/api/apiv1/gen/http/control_plane/server/server.go @@ -32,6 +32,7 @@ type Server struct { CreateDatabase http.Handler GetDatabase http.Handler UpdateDatabase http.Handler + ApplyUpgrade http.Handler DeleteDatabase http.Handler BackupDatabaseNode http.Handler SwitchoverDatabaseNode http.Handler @@ -96,6 +97,7 @@ func New( {"CreateDatabase", "POST", "/v1/databases"}, {"GetDatabase", "GET", "/v1/databases/{database_id}"}, {"UpdateDatabase", "POST", "/v1/databases/{database_id}"}, + {"ApplyUpgrade", "POST", "/v1/databases/{database_id}/upgrade"}, {"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"}, @@ -127,6 +129,7 @@ func New( CreateDatabase: NewCreateDatabaseHandler(e.CreateDatabase, mux, decoder, encoder, errhandler, formatter), 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), 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), @@ -165,6 +168,7 @@ func (s *Server) Use(m func(http.Handler) http.Handler) { s.CreateDatabase = m(s.CreateDatabase) s.GetDatabase = m(s.GetDatabase) s.UpdateDatabase = m(s.UpdateDatabase) + s.ApplyUpgrade = m(s.ApplyUpgrade) s.DeleteDatabase = m(s.DeleteDatabase) s.BackupDatabaseNode = m(s.BackupDatabaseNode) s.SwitchoverDatabaseNode = m(s.SwitchoverDatabaseNode) @@ -201,6 +205,7 @@ func Mount(mux goahttp.Muxer, h *Server) { MountCreateDatabaseHandler(mux, h.CreateDatabase) MountGetDatabaseHandler(mux, h.GetDatabase) MountUpdateDatabaseHandler(mux, h.UpdateDatabase) + MountApplyUpgradeHandler(mux, h.ApplyUpgrade) MountDeleteDatabaseHandler(mux, h.DeleteDatabase) MountBackupDatabaseNodeHandler(mux, h.BackupDatabaseNode) MountSwitchoverDatabaseNodeHandler(mux, h.SwitchoverDatabaseNode) @@ -841,6 +846,59 @@ func NewUpdateDatabaseHandler( }) } +// MountApplyUpgradeHandler configures the mux to serve the "control-plane" +// service "apply-upgrade" endpoint. +func MountApplyUpgradeHandler(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", f) +} + +// NewApplyUpgradeHandler creates a HTTP handler which loads the HTTP request +// and calls the "control-plane" service "apply-upgrade" endpoint. +func NewApplyUpgradeHandler( + 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 = DecodeApplyUpgradeRequest(mux, decoder) + encodeResponse = EncodeApplyUpgradeResponse(encoder) + encodeError = EncodeApplyUpgradeError(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-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 3852dbb8..a2ae600e 100644 --- a/api/apiv1/gen/http/control_plane/server/types.go +++ b/api/apiv1/gen/http/control_plane/server/types.go @@ -56,6 +56,15 @@ type UpdateDatabaseRequestBody struct { Spec *DatabaseSpecRequestBodyRequestBody `json:"spec"` } +// ApplyUpgradeRequestBody is the type of the "control-plane" service +// "apply-upgrade" endpoint HTTP request body. +type ApplyUpgradeRequestBody struct { + // 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. + Image *string `json:"image"` +} + // BackupDatabaseNodeRequestBody is the type of the "control-plane" service // "backup-database-node" endpoint HTTP request body. type BackupDatabaseNodeRequestBody struct { @@ -229,6 +238,15 @@ type UpdateDatabaseResponseBody struct { Database *DatabaseResponseBody `json:"database"` } +// ApplyUpgradeResponseBody is the type of the "control-plane" service +// "apply-upgrade" endpoint HTTP response body. +type ApplyUpgradeResponseBody struct { + // The task tracking the 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 { @@ -866,6 +884,65 @@ type UpdateDatabaseServerErrorResponseBody struct { Message string `json:"message"` } +// ApplyUpgradeClusterNotInitializedResponseBody is the type of the +// "control-plane" service "apply-upgrade" endpoint HTTP response body for the +// "cluster_not_initialized" error. +type ApplyUpgradeClusterNotInitializedResponseBody struct { + // The name of the error. + Name string `json:"name"` + // The error message. + Message string `json:"message"` +} + +// ApplyUpgradeDatabaseNotModifiableResponseBody is the type of the +// "control-plane" service "apply-upgrade" endpoint HTTP response body for the +// "database_not_modifiable" error. +type ApplyUpgradeDatabaseNotModifiableResponseBody struct { + // The name of the error. + Name string `json:"name"` + // The error message. + Message string `json:"message"` +} + +// ApplyUpgradeOperationAlreadyInProgressResponseBody is the type of the +// "control-plane" service "apply-upgrade" endpoint HTTP response body for the +// "operation_already_in_progress" error. +type ApplyUpgradeOperationAlreadyInProgressResponseBody struct { + // The name of the error. + Name string `json:"name"` + // The error message. + Message string `json:"message"` +} + +// ApplyUpgradeInvalidInputResponseBody is the type of the "control-plane" +// service "apply-upgrade" endpoint HTTP response body for the "invalid_input" +// error. +type ApplyUpgradeInvalidInputResponseBody struct { + // The name of the error. + Name string `json:"name"` + // The error message. + Message string `json:"message"` +} + +// ApplyUpgradeNotFoundResponseBody is the type of the "control-plane" service +// "apply-upgrade" endpoint HTTP response body for the "not_found" error. +type ApplyUpgradeNotFoundResponseBody struct { + // The name of the error. + Name string `json:"name"` + // The error message. + Message string `json:"message"` +} + +// ApplyUpgradeServerErrorResponseBody is the type of the "control-plane" +// service "apply-upgrade" endpoint HTTP response body for the "server_error" +// error. +type ApplyUpgradeServerErrorResponseBody 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. @@ -3282,6 +3359,19 @@ func NewUpdateDatabaseResponseBody(res *controlplane.UpdateDatabaseResponse) *Up return body } +// NewApplyUpgradeResponseBody builds the HTTP response body from the result of +// the "apply-upgrade" endpoint of the "control-plane" service. +func NewApplyUpgradeResponseBody(res *controlplane.ApplyUpgradeResponse) *ApplyUpgradeResponseBody { + body := &ApplyUpgradeResponseBody{} + 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 { @@ -3999,6 +4089,69 @@ func NewUpdateDatabaseServerErrorResponseBody(res *controlplane.APIError) *Updat return body } +// NewApplyUpgradeClusterNotInitializedResponseBody builds the HTTP response +// body from the result of the "apply-upgrade" endpoint of the "control-plane" +// service. +func NewApplyUpgradeClusterNotInitializedResponseBody(res *controlplane.APIError) *ApplyUpgradeClusterNotInitializedResponseBody { + body := &ApplyUpgradeClusterNotInitializedResponseBody{ + Name: res.Name, + Message: res.Message, + } + return body +} + +// NewApplyUpgradeDatabaseNotModifiableResponseBody builds the HTTP response +// body from the result of the "apply-upgrade" endpoint of the "control-plane" +// service. +func NewApplyUpgradeDatabaseNotModifiableResponseBody(res *controlplane.APIError) *ApplyUpgradeDatabaseNotModifiableResponseBody { + body := &ApplyUpgradeDatabaseNotModifiableResponseBody{ + Name: res.Name, + Message: res.Message, + } + return body +} + +// NewApplyUpgradeOperationAlreadyInProgressResponseBody builds the HTTP +// response body from the result of the "apply-upgrade" endpoint of the +// "control-plane" service. +func NewApplyUpgradeOperationAlreadyInProgressResponseBody(res *controlplane.APIError) *ApplyUpgradeOperationAlreadyInProgressResponseBody { + body := &ApplyUpgradeOperationAlreadyInProgressResponseBody{ + Name: res.Name, + Message: res.Message, + } + return body +} + +// NewApplyUpgradeInvalidInputResponseBody builds the HTTP response body from +// the result of the "apply-upgrade" endpoint of the "control-plane" service. +func NewApplyUpgradeInvalidInputResponseBody(res *controlplane.APIError) *ApplyUpgradeInvalidInputResponseBody { + body := &ApplyUpgradeInvalidInputResponseBody{ + Name: res.Name, + Message: res.Message, + } + return body +} + +// NewApplyUpgradeNotFoundResponseBody builds the HTTP response body from the +// result of the "apply-upgrade" endpoint of the "control-plane" service. +func NewApplyUpgradeNotFoundResponseBody(res *controlplane.APIError) *ApplyUpgradeNotFoundResponseBody { + body := &ApplyUpgradeNotFoundResponseBody{ + Name: res.Name, + Message: res.Message, + } + return body +} + +// NewApplyUpgradeServerErrorResponseBody builds the HTTP response body from +// the result of the "apply-upgrade" endpoint of the "control-plane" service. +func NewApplyUpgradeServerErrorResponseBody(res *controlplane.APIError) *ApplyUpgradeServerErrorResponseBody { + body := &ApplyUpgradeServerErrorResponseBody{ + 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. @@ -4893,6 +5046,20 @@ func NewUpdateDatabasePayload(body *UpdateDatabaseRequestBody, databaseID string return res } +// NewApplyUpgradePayload builds a control-plane service apply-upgrade endpoint +// payload. +func NewApplyUpgradePayload(body *ApplyUpgradeRequestBody, databaseID string) *controlplane.ApplyUpgradePayload { + v := &controlplane.ApplyUpgradeRequest{ + Image: *body.Image, + } + res := &controlplane.ApplyUpgradePayload{ + 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 { @@ -5226,6 +5393,20 @@ func ValidateUpdateDatabaseRequestBody(body *UpdateDatabaseRequestBody) (err err return } +// ValidateApplyUpgradeRequestBody runs the validations defined on +// Apply-UpgradeRequestBody +func ValidateApplyUpgradeRequestBody(body *ApplyUpgradeRequestBody) (err error) { + if body.Image == nil { + err = goa.MergeErrors(err, goa.MissingFieldError("image", "body")) + } + 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) { diff --git a/api/apiv1/gen/http/openapi.json b/api/apiv1/gen/http/openapi.json index 06da509c..2caf49c1 100644 --- a/api/apiv1/gen/http/openapi.json +++ b/api/apiv1/gen/http/openapi.json @@ -1760,6 +1760,94 @@ ] } }, + "/v1/databases/{database_id}/upgrade": { + "post": { + "tags": [ + "Database" + ], + "summary": "Apply database upgrade", + "description": "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.", + "operationId": "control-plane#apply-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-UpgradeRequestBody", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ApplyUpgradeRequest" + } + } + ], + "responses": { + "200": { + "description": "OK response.", + "schema": { + "$ref": "#/definitions/ApplyUpgradeResponse", + "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": [ @@ -2466,6 +2554,55 @@ "message" ] }, + "ApplyUpgradeRequest": { + "title": "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": { + "title": "ApplyUpgradeResponse", + "type": "object", + "properties": { + "database": { + "$ref": "#/definitions/Database" + }, + "task": { + "$ref": "#/definitions/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": { "title": "AvailableUpgrade", "type": "object", diff --git a/api/apiv1/gen/http/openapi.yaml b/api/apiv1/gen/http/openapi.yaml index 7a8aea77..aeedde4a 100644 --- a/api/apiv1/gen/http/openapi.yaml +++ b/api/apiv1/gen/http/openapi.yaml @@ -1222,6 +1222,66 @@ paths: $ref: '#/definitions/APIError' schemes: - http + /v1/databases/{database_id}/upgrade: + post: + tags: + - Database + summary: Apply database upgrade + description: 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. + operationId: control-plane#apply-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-UpgradeRequestBody + in: body + required: true + schema: + $ref: '#/definitions/ApplyUpgradeRequest' + responses: + "200": + description: OK response. + schema: + $ref: '#/definitions/ApplyUpgradeResponse' + 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: @@ -1719,6 +1779,42 @@ definitions: required: - name - message + ApplyUpgradeRequest: + title: 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: + title: ApplyUpgradeResponse + type: object + properties: + database: + $ref: '#/definitions/Database' + task: + $ref: '#/definitions/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: title: AvailableUpgrade type: object diff --git a/api/apiv1/gen/http/openapi3.json b/api/apiv1/gen/http/openapi3.json index 929d9e78..7ec29cbd 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": "Esse id natus aut omnis minus." + "example": "Tempora laboriosam aut." }, "description": "Optional fields to include in each database response. Supported values: available_upgrades.", "example": [ @@ -1498,7 +1498,7 @@ "type": "array", "items": { "type": "string", - "example": "Totam et et architecto voluptatem." + "example": "Est dolor consequatur." }, "description": "Optional fields to include in the response. Supported values: available_upgrades.", "example": [ @@ -1792,18 +1792,20 @@ "type": "array", "items": { "type": "string", - "example": "Fuga qui id libero dignissimos." + "example": "Illo delectus dolorum." }, "description": "Host IDs to treat as removed during this update. Events targeting these hosts will be skipped.", "example": [ - "Numquam perspiciatis et exercitationem sequi saepe velit.", - "Ex sint dolorum vel.", - "Laboriosam aut dolorum est." + "Aut aut veritatis ut nulla.", + "Earum distinctio qui qui dolores quibusdam officiis.", + "Recusandae sequi vel aspernatur libero nihil sunt." ] }, "example": [ - "Mollitia illo delectus.", - "Aut ducimus aut aut veritatis ut." + "Quasi quo maiores minima velit.", + "Sit rerum autem explicabo nemo et architecto.", + "In cum enim est.", + "Repudiandae in quis eum." ] }, { @@ -4202,6 +4204,142 @@ } } }, + "/v1/databases/{database_id}/upgrade": { + "post": { + "tags": [ + "Database" + ], + "summary": "Apply database upgrade", + "description": "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.", + "operationId": "apply-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/ApplyUpgradeRequest" + }, + "example": { + "image": "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.8-standard-1" + } + } + } + }, + "responses": { + "200": { + "description": "OK response.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApplyUpgradeResponse2" + }, + "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" + } + } + } + } + }, + "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": [ @@ -5582,6 +5720,83 @@ "message" ] }, + "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": { @@ -8937,179 +9152,47 @@ "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": [ { - "connection_info": { + "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" ], - "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_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": [ { - "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" - }, - { - "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" + "container_port": 8080, + "host_port": 8080, + "name": "web-client" }, { "container_port": 8080, @@ -9359,633 +9442,515 @@ "state" ] }, - "DatabaseConnection": { + "Database6": { "type": "object", "properties": { - "target_nodes": { + "available_upgrades": { "type": "array", "items": { - "type": "string", - "example": "Qui ut et." + "$ref": "#/components/schemas/AvailableUpgrade" }, - "description": "Optional ordered list of database node names. When set, the service's database connection includes only the listed nodes in the specified order.", + "description": "Newer stable image versions available in the same Postgres major / Spock major bucket. Present only when ?include=available_upgrades is set.", "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" + { + "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" + } ] - } - }, - "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", - "de3b1388-1f0c-42f1-a86c-59ab72f255ec", - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" - ], - "minItems": 1 }, - "memory": { + "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 + "description": "The time that the database was created.", + "example": "2025-01-01T01:30:00Z", + "format": "date-time" }, - "name": { + "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 + "description": "Unique identifier for the database.", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 }, - "pg_hba_conf": { + "instances": { "type": "array", "items": { - "type": "string", - "example": "Non quae." + "$ref": "#/components/schemas/Instance" }, - "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": "All of the instances in the database.", "example": [ - "host example myapp_user 10.0.0.0/8 scram-sha-256" - ] - }, - "pg_ident_conf": { - "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.", - "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" + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 }, - "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" + "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" }, - "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" + "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" - } - ] - }, - "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" + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" + "port": 5432 }, - { - "aliases": [ - "pg-db", - "db-alias" + "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" + } ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" + "version": "4.10.0" }, - { - "aliases": [ - "pg-db", - "db-alias" + "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" ], - "driver_opts": { - "com.docker.network.endpoint.expose": "true" - }, - "id": "traefik-public" - } - ], - "extra_volumes": [ - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" + "port": 5432 }, - { - "destination_path": "/backups/container", - "host_path": "/Users/user/backups/host" + "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" }, - { - "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" - }, - "required": [ - "name", - "host_ids" - ] - }, - "DatabaseNodeSpec2": { - "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)?$" + "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_ids": { + "service_instances": { "type": "array", "items": { - "type": "string", - "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", - "minLength": 1, - "maxLength": 36 + "$ref": "#/components/schemas/ServiceInstance" }, - "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": "Service instances running alongside this database.", "example": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696" - ], - "minItems": 1 + { + "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" + } + ] }, - "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 + "spec": { + "$ref": "#/components/schemas/DatabaseSpec8" }, - "name": { + "state": { "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": "Sapiente neque doloribus consequatur voluptatibus sed." - }, - "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": "Nisi nihil corporis perspiciatis et." - }, - "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" + "description": "Current state of the database.", + "example": "available", + "enum": [ + "creating", + "modifying", + "available", + "deleting", + "degraded", + "failed", + "restoring", + "unknown" ] }, - "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": { + "tenant_id": { "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}$" + "description": "Unique identifier for the database's owner.", + "example": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "minLength": 1, + "maxLength": 36 }, - "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": { + "updated_at": { "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 time that the database was last updated.", + "example": "2025-01-01T02:30:00Z", + "format": "date-time" } }, "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" + "created_at": "2025-06-18T16:52:05Z", + "id": "storefront", + "instances": [ + { + "connection_info": { + "addresses": [ + "10.24.34.2", + "i-0123456789abcdef.ec2.internal" + ], + "port": 5432 }, - { - "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" + "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": [ { - "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" + "attributes": [ + "SUPERUSER", + "LOGIN" + ], + "db_owner": true, + "username": "admin" } ], - "schedules": [ + "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" } + ], + "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": "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" ] }, - "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": "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" + "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" + ] + } }, - "required": [ - "name", - "host_ids" - ] + "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" + } }, - "DatabaseNodeSpec3": { + "DatabaseNodeSpec": { "type": "object", "properties": { "backup_config": { @@ -10001,13 +9966,16 @@ "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": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696" + "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "de3b1388-1f0c-42f1-a86c-59ab72f255ec" ], "minItems": 1 }, @@ -10038,7 +10006,7 @@ "type": "array", "items": { "type": "string", - "example": "Distinctio sed amet rem voluptas qui." + "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.", "example": [ @@ -10049,7 +10017,7 @@ "type": "array", "items": { "type": "string", - "example": "Voluptatem nesciunt dignissimos voluptas vel earum." + "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.", "example": [ @@ -10103,7 +10071,7 @@ "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", "retention_full": 2, "retention_full_type": "count", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -10126,7 +10094,7 @@ "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "id": "f6b84a99-5e91-4203-be1e-131fe82e5984", "retention_full": 2, "retention_full_type": "count", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -10157,9 +10125,9 @@ }, "cpus": "500m", "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696", - "76f9b8c0-4958-11f0-a489-3bb29577c696" + "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "de3b1388-1f0c-42f1-a86c-59ab72f255ec", + "de3b1388-1f0c-42f1-a86c-59ab72f255ec" ], "memory": "500M", "name": "n1", @@ -10215,7 +10183,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Animi recusandae." } }, "patroni_port": 8888, @@ -10243,7 +10211,7 @@ "gcs_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", "gcs_endpoint": "localhost", "gcs_key": "ZXhhbXBsZSBnY3Mga2V5Cg==", - "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "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", @@ -10256,7 +10224,7 @@ "target": "123456", "type": "xid" }, - "source_database_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "source_database_id": "02f1a7db-fca8-4521-b57a-2a375c1ced51", "source_database_name": "northwind", "source_node_name": "n1" }, @@ -10267,7 +10235,7 @@ "host_ids" ] }, - "DatabaseNodeSpec4": { + "DatabaseNodeSpec2": { "type": "object", "properties": { "backup_config": { @@ -10289,8 +10257,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 @@ -10322,7 +10288,7 @@ "type": "array", "items": { "type": "string", - "example": "Harum iste dignissimos." + "example": "Sapiente neque doloribus consequatur voluptatibus sed." }, "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": [ @@ -10333,7 +10299,7 @@ "type": "array", "items": { "type": "string", - "example": "Beatae nobis quam sequi quasi aliquid." + "example": "Nisi nihil corporis perspiciatis et." }, "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": [ @@ -10397,6 +10363,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", @@ -10441,6 +10430,7 @@ }, "cpus": "500m", "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "500M", @@ -10497,7 +10487,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Reprehenderit atque aliquid." } }, "patroni_port": 8888, @@ -10549,7 +10539,7 @@ "host_ids" ] }, - "DatabaseNodeSpec5": { + "DatabaseNodeSpec3": { "type": "object", "properties": { "backup_config": { @@ -10571,8 +10561,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 @@ -10604,7 +10592,7 @@ "type": "array", "items": { "type": "string", - "example": "Dolor sit quae et tempore et aut." + "example": "Distinctio sed amet rem voluptas qui." }, "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": [ @@ -10615,7 +10603,7 @@ "type": "array", "items": { "type": "string", - "example": "Nisi eveniet sit dignissimos ducimus." + "example": "Voluptatem nesciunt dignissimos voluptas vel earum." }, "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": [ @@ -10679,29 +10667,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", @@ -10746,6 +10711,8 @@ }, "cpus": "500m", "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "500M", @@ -10802,7 +10769,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Et odio." + "image": "Incidunt in quas totam." } }, "patroni_port": 8888, @@ -10854,7 +10821,7 @@ "host_ids" ] }, - "DatabaseNodeSpec6": { + "DatabaseNodeSpec4": { "type": "object", "properties": { "backup_config": { @@ -10876,6 +10843,7 @@ }, "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" ], @@ -10908,7 +10876,7 @@ "type": "array", "items": { "type": "string", - "example": "Laudantium molestiae error quas iste." + "example": "Harum iste dignissimos." }, "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": [ @@ -10919,7 +10887,7 @@ "type": "array", "items": { "type": "string", - "example": "Assumenda et." + "example": "Beatae nobis quam sequi quasi aliquid." }, "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": [ @@ -11135,7 +11103,7 @@ "host_ids" ] }, - "DatabaseNodeSpec7": { + "DatabaseNodeSpec5": { "type": "object", "properties": { "backup_config": { @@ -11157,6 +11125,7 @@ }, "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" ], @@ -11189,7 +11158,7 @@ "type": "array", "items": { "type": "string", - "example": "Praesentium possimus id laudantium sed delectus." + "example": "Dolor sit quae et tempore et aut." }, "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": [ @@ -11200,7 +11169,7 @@ "type": "array", "items": { "type": "string", - "example": "Ut distinctio expedita." + "example": "Nisi eveniet sit dignissimos ducimus." }, "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": [ @@ -11286,30 +11255,51 @@ "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", + "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", @@ -11366,80 +11356,2574 @@ "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" + ], + "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" + ] + }, + "DatabaseNodeSpec6": { + "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" + ], + "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": "Laudantium molestiae error quas iste." + }, + "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": "Assumenda et." + }, + "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" + } + }, + "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", + "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" + }, + "required": [ + "name", + "host_ids" + ] + }, + "DatabaseNodeSpec7": { + "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" + ], + "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": "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": { + "type": "array", + "items": { + "type": "string", + "example": "Possimus id laudantium sed delectus." + }, + "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" + } + }, + "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", + "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" + }, + "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" + ], + "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": "Id natus aut." + }, + "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": "Minus sint totam et et." + }, + "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" + } + }, + "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" + }, + "required": [ + "name", + "host_ids" + ] + }, + "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": { + "$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/DatabaseNodeSpec" + }, + "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": "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." + } + }, + "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." + } + }, + "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" + } + ], + "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", + "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" + } + ], + "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" + } + ], + "image": "Animi recusandae." + } + }, + "port": 0, + "service_id": "analytics-service", + "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": "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": "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." + } + }, + "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" + } + ], + "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." + } + }, + "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" + } + ], + "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" + } + ], + "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" + } + ], + "image": "Animi recusandae." + } + }, + "port": 0, + "service_id": "analytics-service", + "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": "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": { @@ -11471,7 +13955,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": false, + "db_owner": true, "password": "secret", "roles": [ "pgedge_superuser" @@ -11484,7 +13968,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": false, + "db_owner": true, "password": "secret", "roles": [ "pgedge_superuser" @@ -11497,7 +13981,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": false, + "db_owner": true, "password": "secret", "roles": [ "pgedge_superuser" @@ -11516,7 +14000,7 @@ "nodes": { "type": "array", "items": { - "$ref": "#/components/schemas/DatabaseNodeSpec" + "$ref": "#/components/schemas/DatabaseNodeSpec2" }, "description": "The Spock nodes for this database.", "example": [ @@ -11536,30 +14020,7 @@ "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", + "id": "76f9b8c0-4958-11f0-a489-3bb29577c696", "retention_full": 2, "retention_full_type": "count", "s3_bucket": "pgedge-backups-9f81786f-373b-4ff2-afee-e054a06a96f1", @@ -11568,136 +14029,7 @@ "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." - } - }, - "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", @@ -11711,7 +14043,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", @@ -11734,7 +14066,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", @@ -11765,9 +14097,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", @@ -11823,7 +14155,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Animi recusandae." + "image": "Reprehenderit atque aliquid." } }, "patroni_port": 8888, @@ -11851,7 +14183,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", @@ -11864,7 +14196,7 @@ "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" }, @@ -11889,7 +14221,7 @@ "type": "array", "items": { "type": "string", - "example": "Velit et labore in dolor quisquam placeat." + "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": [ @@ -11901,7 +14233,7 @@ "type": "array", "items": { "type": "string", - "example": "Eos molestiae voluptates laborum." + "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": [ @@ -11940,7 +14272,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": [ @@ -11960,7 +14292,7 @@ "target_session_attrs": "primary" }, "host_ids": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", "orchestrator_opts": { @@ -12015,11 +14347,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" }, @@ -12039,7 +14371,7 @@ "target_session_attrs": "primary" }, "host_ids": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", "orchestrator_opts": { @@ -12094,11 +14426,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" }, @@ -12118,7 +14450,7 @@ "target_session_attrs": "primary" }, "host_ids": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", "orchestrator_opts": { @@ -12173,11 +14505,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" } @@ -12206,7 +14538,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", @@ -12229,7 +14561,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", @@ -12266,218 +14621,43 @@ "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": "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" + ], + "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": [ @@ -12494,7 +14674,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", @@ -12517,7 +14697,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", @@ -12548,9 +14751,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", @@ -12606,7 +14809,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Animi recusandae." + "image": "Reprehenderit atque aliquid." } }, "patroni_port": 8888, @@ -12634,7 +14837,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", @@ -12647,141 +14850,111 @@ "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" - } - ], - "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." - } - }, - "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" + "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" + } ], - "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": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + "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": { @@ -12834,33 +15007,152 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Animi recusandae." + "image": "Reprehenderit atque aliquid." } }, - "port": 0, - "service_id": "analytics-service", - "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" }, { - "config": { - "llm_model": "gpt-4", - "llm_provider": "openai", - "openai_api_key": "sk-..." - }, - "connect_as": "app", - "cpus": "500m", - "database_connection": { - "target_nodes": [ - "n1", - "n2" + "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" + } ], - "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": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + "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": { @@ -12913,14 +15205,165 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Animi recusandae." + "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" + } + ], + "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": [ + "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", @@ -12937,7 +15380,7 @@ "target_session_attrs": "primary" }, "host_ids": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", "orchestrator_opts": { @@ -12992,11 +15435,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" }, @@ -13016,7 +15459,7 @@ "target_session_attrs": "primary" }, "host_ids": [ - "de3b1388-1f0c-42f1-a86c-59ab72f255ec" + "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", "orchestrator_opts": { @@ -13071,11 +15514,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" } @@ -13087,7 +15530,7 @@ "nodes" ] }, - "DatabaseSpec2": { + "DatabaseSpec3": { "type": "object", "properties": { "backup_config": { @@ -13119,7 +15562,20 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": true, + "db_owner": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + }, + { + "attributes": [ + "LOGIN", + "CREATEDB", + "CREATEROLE" + ], + "db_owner": false, "password": "secret", "roles": [ "pgedge_superuser" @@ -13132,42 +15588,204 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": true, - "password": "secret", - "roles": [ - "pgedge_superuser" + "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/DatabaseNodeSpec3" + }, + "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" ], - "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" }, - { - "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/DatabaseNodeSpec2" - }, - "description": "The Spock nodes for this database.", - "example": [ { "backup_config": { "repositories": [ @@ -13194,29 +15812,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", @@ -13319,7 +15914,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Reprehenderit atque aliquid." + "image": "Incidunt in quas totam." } }, "patroni_port": 8888, @@ -13385,7 +15980,7 @@ "type": "array", "items": { "type": "string", - "example": "Optio accusantium." + "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": [ @@ -13397,7 +15992,7 @@ "type": "array", "items": { "type": "string", - "example": "Voluptatibus sunt deserunt sapiente doloribus est." + "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": [ @@ -13436,7 +16031,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": [ @@ -13456,6 +16051,7 @@ "target_session_attrs": "primary" }, "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", @@ -13511,7 +16107,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Reprehenderit atque aliquid." + "image": "Incidunt in quas totam." } }, "port": 0, @@ -13535,6 +16131,7 @@ "target_session_attrs": "primary" }, "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", @@ -13590,7 +16187,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Reprehenderit atque aliquid." + "image": "Incidunt in quas totam." } }, "port": 0, @@ -13614,6 +16211,7 @@ "target_session_attrs": "primary" }, "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", @@ -13669,49 +16267,106 @@ "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" - } - ] - }, - "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" + "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" - }, + "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", @@ -13786,20 +16441,7 @@ "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" @@ -13812,240 +16454,32 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": true, + "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" - }, - { - "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" - }, - { - "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" - }, + }, + { + "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", @@ -14171,7 +16605,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Reprehenderit atque aliquid." + "image": "Incidunt in quas totam." } }, "patroni_port": 8888, @@ -14244,29 +16678,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", @@ -14369,7 +16780,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Reprehenderit atque aliquid." + "image": "Incidunt in quas totam." } }, "patroni_port": 8888, @@ -14468,66 +16879,226 @@ "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" + ], + "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." + } }, - "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", @@ -14544,6 +17115,7 @@ "target_session_attrs": "primary" }, "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", @@ -14599,7 +17171,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Reprehenderit atque aliquid." + "image": "Incidunt in quas totam." } }, "port": 0, @@ -14623,6 +17195,7 @@ "target_session_attrs": "primary" }, "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", @@ -14678,7 +17251,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Reprehenderit atque aliquid." + "image": "Incidunt in quas totam." } }, "port": 0, @@ -14694,7 +17267,7 @@ "nodes" ] }, - "DatabaseSpec3": { + "DatabaseSpec4": { "type": "object", "properties": { "backup_config": { @@ -14771,7 +17344,7 @@ "nodes": { "type": "array", "items": { - "$ref": "#/components/schemas/DatabaseNodeSpec3" + "$ref": "#/components/schemas/DatabaseNodeSpec4" }, "description": "The Spock nodes for this database.", "example": [ @@ -15124,6 +17697,181 @@ "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" } ], "minItems": 1, @@ -15144,7 +17892,7 @@ "type": "array", "items": { "type": "string", - "example": "Quo perferendis et qui." + "example": "Tempora in veniam officia ratione minus." }, "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": [ @@ -15156,7 +17904,7 @@ "type": "array", "items": { "type": "string", - "example": "Quaerat rem." + "example": "Occaecati et et consequuntur." }, "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": [ @@ -15195,7 +17943,7 @@ "services": { "type": "array", "items": { - "$ref": "#/components/schemas/ServiceSpec3" + "$ref": "#/components/schemas/ServiceSpec4" }, "description": "Service instances to run alongside the database (e.g., MCP servers).", "example": [ @@ -15359,86 +18107,6 @@ "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", @@ -15990,6 +18658,181 @@ "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" } ], "orchestrator_opts": { @@ -16431,7 +19274,7 @@ "nodes" ] }, - "DatabaseSpec4": { + "DatabaseSpec5": { "type": "object", "properties": { "backup_config": { @@ -16463,7 +19306,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": false, + "db_owner": true, "password": "secret", "roles": [ "pgedge_superuser" @@ -16476,7 +19319,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": false, + "db_owner": true, "password": "secret", "roles": [ "pgedge_superuser" @@ -16489,7 +19332,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": false, + "db_owner": true, "password": "secret", "roles": [ "pgedge_superuser" @@ -16508,7 +19351,7 @@ "nodes": { "type": "array", "items": { - "$ref": "#/components/schemas/DatabaseNodeSpec4" + "$ref": "#/components/schemas/DatabaseNodeSpec5" }, "description": "The Spock nodes for this database.", "example": [ @@ -16538,158 +19381,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", @@ -16757,7 +19448,6 @@ }, "cpus": "500m", "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], @@ -16815,7 +19505,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Et odio." } }, "patroni_port": 8888, @@ -16888,6 +19578,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", @@ -16932,7 +19645,6 @@ }, "cpus": "500m", "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], @@ -16990,7 +19702,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Et odio." } }, "patroni_port": 8888, @@ -17056,7 +19768,7 @@ "type": "array", "items": { "type": "string", - "example": "Tempora in veniam officia ratione minus." + "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": [ @@ -17068,7 +19780,7 @@ "type": "array", "items": { "type": "string", - "example": "Occaecati et et consequuntur." + "example": "Nesciunt quia quis aut ducimus deserunt." }, "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": [ @@ -17107,7 +19819,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": [ @@ -17183,7 +19895,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Et odio." } }, "port": 0, @@ -17263,7 +19975,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Et odio." } }, "port": 0, @@ -17343,7 +20055,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Et odio." } }, "port": 0, @@ -17386,6 +20098,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", @@ -17437,7 +20172,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": false, + "db_owner": true, "password": "secret", "roles": [ "pgedge_superuser" @@ -17450,7 +20185,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": false, + "db_owner": true, "password": "secret", "roles": [ "pgedge_superuser" @@ -17463,7 +20198,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": false, + "db_owner": true, "password": "secret", "roles": [ "pgedge_superuser" @@ -17499,158 +20234,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", @@ -17718,7 +20301,6 @@ }, "cpus": "500m", "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], @@ -17776,7 +20358,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Et odio." } }, "patroni_port": 8888, @@ -17849,6 +20431,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", @@ -17893,7 +20498,6 @@ }, "cpus": "500m", "host_ids": [ - "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], @@ -17951,7 +20555,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Et odio." } }, "patroni_port": 8888, @@ -18051,7 +20655,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Et odio." } }, "patroni_port": 8888, @@ -18182,7 +20786,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Et odio." } }, "port": 0, @@ -18262,7 +20866,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Et odio." } }, "port": 0, @@ -18342,7 +20946,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Et odio." } }, "port": 0, @@ -18422,7 +21026,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Incidunt in quas totam." + "image": "Et odio." } }, "port": 0, @@ -18438,7 +21042,7 @@ "nodes" ] }, - "DatabaseSpec5": { + "DatabaseSpec6": { "type": "object", "properties": { "backup_config": { @@ -18470,7 +21074,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": true, + "db_owner": false, "password": "secret", "roles": [ "pgedge_superuser" @@ -18483,7 +21087,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": true, + "db_owner": false, "password": "secret", "roles": [ "pgedge_superuser" @@ -18496,7 +21100,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": true, + "db_owner": false, "password": "secret", "roles": [ "pgedge_superuser" @@ -18515,7 +21119,7 @@ "nodes": { "type": "array", "items": { - "$ref": "#/components/schemas/DatabaseNodeSpec5" + "$ref": "#/components/schemas/DatabaseNodeSpec6" }, "description": "The Spock nodes for this database.", "example": [ @@ -18545,29 +21149,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", @@ -18612,6 +21193,7 @@ }, "cpus": "500m", "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], @@ -18669,7 +21251,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Et odio." + "image": "Incidunt in quas totam." } }, "patroni_port": 8888, @@ -18742,29 +21324,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", @@ -18809,6 +21368,7 @@ }, "cpus": "500m", "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], @@ -18866,7 +21426,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Et odio." + "image": "Incidunt in quas totam." } }, "patroni_port": 8888, @@ -18932,7 +21492,7 @@ "type": "array", "items": { "type": "string", - "example": "Iure molestiae." + "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": [ @@ -18944,7 +21504,7 @@ "type": "array", "items": { "type": "string", - "example": "Nesciunt quia quis aut ducimus deserunt." + "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": [ @@ -18983,7 +21543,7 @@ "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": [ @@ -19059,7 +21619,87 @@ "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" + ], + "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, @@ -19139,7 +21779,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Et odio." + "image": "Incidunt in quas totam." } }, "port": 0, @@ -19219,7 +21859,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Et odio." + "image": "Incidunt in quas totam." } }, "port": 0, @@ -19262,29 +21902,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", @@ -19336,7 +21953,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": true, + "db_owner": false, "password": "secret", "roles": [ "pgedge_superuser" @@ -19349,7 +21966,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": true, + "db_owner": false, "password": "secret", "roles": [ "pgedge_superuser" @@ -19362,7 +21979,7 @@ "CREATEDB", "CREATEROLE" ], - "db_owner": true, + "db_owner": false, "password": "secret", "roles": [ "pgedge_superuser" @@ -19398,29 +22015,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", @@ -19465,6 +22059,7 @@ }, "cpus": "500m", "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], @@ -19522,7 +22117,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Et odio." + "image": "Incidunt in quas totam." } }, "patroni_port": 8888, @@ -19595,6 +22190,158 @@ "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", @@ -19662,6 +22409,7 @@ }, "cpus": "500m", "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], @@ -19719,7 +22467,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Et odio." + "image": "Incidunt in quas totam." } }, "patroni_port": 8888, @@ -19793,251 +22541,91 @@ "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": [ - "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": "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" - } + }, + { + "aliases": [ + "pg-db", + "db-alias" ], - "image": "Et odio." + "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" }, - "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", @@ -20110,7 +22698,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Et odio." + "image": "Incidunt in quas totam." } }, "port": 0, @@ -20190,7 +22778,7 @@ "host_path": "/Users/user/backups/host" } ], - "image": "Et odio." + "image": "Incidunt in quas totam." } }, "port": 0, @@ -20206,7 +22794,7 @@ "nodes" ] }, - "DatabaseSpec6": { + "DatabaseSpec7": { "type": "object", "properties": { "backup_config": { @@ -20283,7 +22871,7 @@ "nodes": { "type": "array", "items": { - "$ref": "#/components/schemas/DatabaseNodeSpec6" + "$ref": "#/components/schemas/DatabaseNodeSpec7" }, "description": "The Spock nodes for this database.", "example": [ @@ -20636,6 +23224,181 @@ "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" } ], "minItems": 1, @@ -20656,7 +23419,7 @@ "type": "array", "items": { "type": "string", - "example": "Modi facere est." + "example": "Odit placeat quod facere possimus sit." }, "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": [ @@ -20668,7 +23431,7 @@ "type": "array", "items": { "type": "string", - "example": "Qui excepturi debitis aperiam rerum at." + "example": "In dolor unde optio illo." }, "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": [ @@ -20707,7 +23470,7 @@ "services": { "type": "array", "items": { - "$ref": "#/components/schemas/ServiceSpec6" + "$ref": "#/components/schemas/ServiceSpec7" }, "description": "Service instances to run alongside the database (e.g., MCP servers).", "example": [ @@ -20871,86 +23634,6 @@ "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", @@ -21870,6 +24553,166 @@ "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", @@ -21958,7 +24801,7 @@ "nodes" ] }, - "DatabaseSpec7": { + "DatabaseSpec8": { "type": "object", "properties": { "backup_config": { @@ -22035,7 +24878,7 @@ "nodes": { "type": "array", "items": { - "$ref": "#/components/schemas/DatabaseNodeSpec7" + "$ref": "#/components/schemas/DatabaseNodeSpec8" }, "description": "The Spock nodes for this database.", "example": [ @@ -22213,83 +25056,101 @@ "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": [ { - "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" - } - ] + "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", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], - "memory": "500M", - "name": "n1", + "memory": "512M", "orchestrator_opts": { "swarm": { "extra_labels": { @@ -22345,124 +25206,91 @@ "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 + "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-..." }, - "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" + "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", - "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" + "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." + } }, - "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": "Possimus sit commodi in dolor unde." - }, - "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": "Illo ut sint cumque quia non enim." - }, - "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": [ + "port": 0, + "service_id": "76f9b8c0-4958-11f0-a489-3bb29577c696", + "service_type": "rag", + "version": "latest" + }, { "config": { "llm_model": "gpt-4", @@ -22720,206 +25548,31 @@ "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" + "CREATEROLE" ], - "pg_ident_conf": [ - "ssl_users CN=alice,O=example alice" + "db_owner": false, + "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": false, + "password": "secret", + "roles": [ + "pgedge_superuser" + ], + "username": "admin" + } + ], + "memory": "500M", + "nodes": [ { "backup_config": { "repositories": [ @@ -24272,7 +26925,7 @@ }, "example": { "candidate_instance_id": "68f50878-44d2-4524-a823-e31bd478706d-n1-689qacsi", - "skip_validation": false + "skip_validation": true } }, "FailoverDatabaseNodeResponse": { @@ -26658,7 +29311,7 @@ "type": "object", "properties": { "database": { - "$ref": "#/components/schemas/Database5" + "$ref": "#/components/schemas/Database6" }, "node_tasks": { "type": "array", @@ -26667,6 +29320,26 @@ }, "description": "The tasks that will restore each database node.", "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", @@ -28324,6 +30997,179 @@ }, "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", + "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", + "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" + }, + "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" ], "minItems": 1 @@ -28385,6 +31231,8 @@ "target_session_attrs": "primary" }, "host_ids": [ + "76f9b8c0-4958-11f0-a489-3bb29577c696", + "76f9b8c0-4958-11f0-a489-3bb29577c696", "76f9b8c0-4958-11f0-a489-3bb29577c696" ], "memory": "512M", diff --git a/api/apiv1/gen/http/openapi3.yaml b/api/apiv1/gen/http/openapi3.yaml index 4f028c03..c9e56044 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: Esse id natus aut omnis minus. + example: Tempora laboriosam aut. 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: Totam et et architecto voluptatem. + example: Est dolor consequatur. description: 'Optional fields to include in the response. Supported values: available_upgrades.' example: - available_upgrades @@ -1171,15 +1171,17 @@ paths: type: array items: type: string - example: Fuga qui id libero dignissimos. + example: Illo delectus dolorum. description: Host IDs to treat as removed during this update. Events targeting these hosts will be skipped. example: - - Numquam perspiciatis et exercitationem sequi saepe velit. - - Ex sint dolorum vel. - - Laboriosam aut dolorum est. + - Aut aut veritatis ut nulla. + - Earum distinctio qui qui dolores quibusdam officiis. + - Recusandae sequi vel aspernatur libero nihil sunt. example: - - Mollitia illo delectus. - - Aut ducimus aut aut veritatis ut. + - Quasi quo maiores minima velit. + - Sit rerum autem explicabo nemo et architecto. + - In cum enim est. + - Repudiandae in quis eum. - name: database_id in: path description: ID of the database to update. @@ -2796,6 +2798,97 @@ paths: example: message: A longer description of the error. name: error_name + /v1/databases/{database_id}/upgrade: + post: + tags: + - Database + summary: Apply database upgrade + description: 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. + operationId: apply-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/ApplyUpgradeRequest' + example: + image: ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.8-standard-1 + responses: + "200": + description: OK response. + content: + application/json: + schema: + $ref: '#/components/schemas/ApplyUpgradeResponse2' + 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 + "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: @@ -3739,6 +3832,62 @@ components: required: - name - message + 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: @@ -6140,70 +6289,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" - - 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: @@ -6270,36 +6355,6 @@ 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/DatabaseSpec7' state: @@ -6436,125 +6491,458 @@ components: - created_at - updated_at - state - DatabaseConnection: + Database6: type: object properties: - target_nodes: + available_upgrades: 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. + $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: - - n1 - - n2 - target_session_attrs: + - 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: '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 - - de3b1388-1f0c-42f1-a86c-59ab72f255ec - - 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: + 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. - 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. + $ref: '#/components/schemas/ServiceInstance' + description: Service instances running alongside this database. example: - max_connections: 1000 - additionalProperties: true - restore_config: - $ref: '#/components/schemas/RestoreConfigSpec' - source_node: + - 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: 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 + description: Current state of the database. + example: available + 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: 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: + 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 + - de3b1388-1f0c-42f1-a86c-59ab72f255ec + - 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: 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. + example: + - host example myapp_user 10.0.0.0/8 scram-sha-256 + pg_ident_conf: + 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. + 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 @@ -7816,7 +8204,7 @@ components: type: array items: type: string - example: Praesentium possimus id laudantium sed delectus. + 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 @@ -7824,7 +8212,7 @@ components: type: array items: type: string - example: Ut distinctio expedita. + example: Possimus id laudantium sed delectus. 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 @@ -7908,8 +8296,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: @@ -7983,11 +8369,224 @@ components: required: - name - host_ids - DatabaseScripts: + DatabaseNodeSpec8: type: object properties: - post_database_create: - $ref: '#/components/schemas/SQLScript' + 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 + 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: Id natus aut. + 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: Minus sint totam et et. + 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 + 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 + required: + - name + - host_ids + DatabaseScripts: + type: object + properties: + post_database_create: + $ref: '#/components/schemas/SQLScript' post_init: $ref: '#/components/schemas/SQLScript' example: @@ -9857,26 +10456,1148 @@ 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 + - 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 + - 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 + 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: + - 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 + 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: "5" + required: + - database_name + - nodes + DatabaseSpec3: + 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/DatabaseNodeSpec3' + 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 + - 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 + 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. + 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 + 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 @@ -9925,7 +11646,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Reprehenderit atque aliquid. + image: Incidunt in quas totam. patroni_port: 8888 pg_hba_conf: - host example myapp_user 10.0.0.0/8 scram-sha-256 @@ -10004,26 +11725,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 @@ -10072,7 +11773,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Reprehenderit atque aliquid. + image: Incidunt in quas totam. patroni_port: 8888 pg_hba_conf: - host example myapp_user 10.0.0.0/8 scram-sha-256 @@ -10140,7 +11841,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container host_path: /Users/user/backups/host - image: Reprehenderit atque aliquid. + image: Incidunt in quas totam. patroni_port: 8888 pg_hba_conf: - hostssl all myapp_user 203.0.113.0/24 scram-sha-256 @@ -10200,6 +11901,109 @@ components: 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: @@ -10232,7 +12036,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container 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 @@ -10250,6 +12054,7 @@ components: target_session_attrs: primary host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 memory: 512M orchestrator_opts: swarm: @@ -10282,7 +12087,7 @@ components: host_path: /Users/user/backups/host - destination_path: /backups/container 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 @@ -10291,7 +12096,7 @@ components: required: - database_name - nodes - DatabaseSpec3: + DatabaseSpec4: type: object properties: backup_config: @@ -10349,7 +12154,7 @@ components: nodes: type: array items: - $ref: '#/components/schemas/DatabaseNodeSpec3' + $ref: '#/components/schemas/DatabaseNodeSpec4' description: The Spock nodes for this database. example: - backup_config: @@ -10606,6 +12411,133 @@ 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 minItems: 1 maxItems: 9 orchestrator_opts: @@ -10621,7 +12553,7 @@ components: type: array items: type: string - example: Quo perferendis et qui. + example: Tempora in veniam officia ratione minus. 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 @@ -10630,7 +12562,7 @@ components: type: array items: type: string - example: Quaerat rem. + example: Occaecati et et consequuntur. 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 @@ -10660,7 +12592,7 @@ components: services: type: array items: - $ref: '#/components/schemas/ServiceSpec3' + $ref: '#/components/schemas/ServiceSpec4' description: Service instances to run alongside the database (e.g., MCP servers). example: - config: @@ -10816,57 +12748,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 spock_version: type: string description: The major version of the Spock extension. @@ -11211,6 +13092,133 @@ 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 orchestrator_opts: swarm: extra_labels: @@ -11497,194 +13505,67 @@ components: required: - database_name - nodes - DatabaseSpec4: + 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: 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 - 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 + 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 @@ -11727,6 +13608,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 @@ -11741,7 +13642,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: @@ -11775,7 +13675,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 @@ -11854,6 +13754,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 @@ -11868,7 +13788,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: @@ -11902,7 +13821,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 @@ -11954,7 +13873,7 @@ components: type: array items: type: string - example: Tempora in veniam officia ratione minus. + 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 @@ -11963,7 +13882,7 @@ components: type: array items: type: string - example: Occaecati et et consequuntur. + example: Nesciunt quia quis aut ducimus deserunt. 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 @@ -11993,7 +13912,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: @@ -12042,7 +13961,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 @@ -12093,7 +14012,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 @@ -12144,7 +14063,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 @@ -12197,6 +14116,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 @@ -12214,7 +14153,7 @@ components: - LOGIN - CREATEDB - CREATEROLE - db_owner: false + db_owner: true password: secret roles: - pgedge_superuser @@ -12223,7 +14162,7 @@ components: - LOGIN - CREATEDB - CREATEROLE - db_owner: false + db_owner: true password: secret roles: - pgedge_superuser @@ -12232,7 +14171,7 @@ components: - LOGIN - CREATEDB - CREATEROLE - db_owner: false + db_owner: true password: secret roles: - pgedge_superuser @@ -12252,122 +14191,15 @@ components: 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: + 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 @@ -12422,7 +14254,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: @@ -12456,7 +14287,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 @@ -12535,6 +14366,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 @@ -12549,7 +14400,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: @@ -12583,7 +14433,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 @@ -12651,7 +14501,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 @@ -12744,7 +14594,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 @@ -12795,7 +14645,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 @@ -12846,7 +14696,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 @@ -12897,7 +14747,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 @@ -12906,7 +14756,7 @@ components: required: - database_name - nodes - DatabaseSpec5: + DatabaseSpec6: type: object properties: backup_config: @@ -12932,7 +14782,7 @@ components: - LOGIN - CREATEDB - CREATEROLE - db_owner: true + db_owner: false password: secret roles: - pgedge_superuser @@ -12941,7 +14791,7 @@ components: - LOGIN - CREATEDB - CREATEROLE - db_owner: true + db_owner: false password: secret roles: - pgedge_superuser @@ -12950,7 +14800,7 @@ components: - LOGIN - CREATEDB - CREATEROLE - db_owner: true + db_owner: false password: secret roles: - pgedge_superuser @@ -12964,7 +14814,7 @@ components: nodes: type: array items: - $ref: '#/components/schemas/DatabaseNodeSpec5' + $ref: '#/components/schemas/DatabaseNodeSpec6' description: The Spock nodes for this database. example: - backup_config: @@ -13009,26 +14859,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 @@ -13043,6 +14873,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: @@ -13076,7 +14907,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 @@ -13155,26 +14986,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 @@ -13189,6 +15000,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: @@ -13222,7 +15034,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 @@ -13274,7 +15086,7 @@ components: type: array items: type: string - example: Iure molestiae. + 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 @@ -13283,7 +15095,7 @@ components: type: array items: type: string - example: Nesciunt quia quis aut ducimus deserunt. + 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 @@ -13313,7 +15125,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: @@ -13362,7 +15174,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 @@ -13413,7 +15225,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 @@ -13464,7 +15276,58 @@ 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 + 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 @@ -13517,26 +15380,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 @@ -13554,7 +15397,7 @@ components: - LOGIN - CREATEDB - CREATEROLE - db_owner: true + db_owner: false password: secret roles: - pgedge_superuser @@ -13563,7 +15406,7 @@ components: - LOGIN - CREATEDB - CREATEROLE - db_owner: true + db_owner: false password: secret roles: - pgedge_superuser @@ -13572,7 +15415,7 @@ components: - LOGIN - CREATEDB - CREATEROLE - db_owner: true + db_owner: false password: secret roles: - pgedge_superuser @@ -13621,26 +15464,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 @@ -13655,6 +15478,134 @@ components: 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 + 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: @@ -13688,7 +15639,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 @@ -13767,26 +15718,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 @@ -13801,6 +15732,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: @@ -13834,7 +15766,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 @@ -13902,155 +15834,53 @@ components: 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 - 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: 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 - version: latest + 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 @@ -14097,7 +15927,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 @@ -14148,7 +15978,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 @@ -14157,7 +15987,7 @@ components: required: - database_name - nodes - DatabaseSpec6: + DatabaseSpec7: type: object properties: backup_config: @@ -14215,7 +16045,7 @@ components: nodes: type: array items: - $ref: '#/components/schemas/DatabaseNodeSpec6' + $ref: '#/components/schemas/DatabaseNodeSpec7' description: The Spock nodes for this database. example: - backup_config: @@ -14472,6 +16302,133 @@ 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 minItems: 1 maxItems: 9 orchestrator_opts: @@ -14487,7 +16444,7 @@ components: type: array items: type: string - example: Modi facere est. + example: Odit placeat quod facere possimus sit. 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 @@ -14496,7 +16453,7 @@ components: type: array items: type: string - example: Qui excepturi debitis aperiam rerum at. + example: In dolor unde optio illo. 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 @@ -14526,7 +16483,7 @@ components: services: type: array items: - $ref: '#/components/schemas/ServiceSpec6' + $ref: '#/components/schemas/ServiceSpec7' description: Service instances to run alongside the database (e.g., MCP servers). example: - config: @@ -14682,57 +16639,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 spock_version: type: string description: The major version of the Spock extension. @@ -15384,11 +17290,113 @@ 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 - DatabaseSpec7: + DatabaseSpec8: type: object properties: backup_config: @@ -15446,7 +17454,7 @@ components: nodes: type: array items: - $ref: '#/components/schemas/DatabaseNodeSpec7' + $ref: '#/components/schemas/DatabaseNodeSpec8' description: The Spock nodes for this database. example: - backup_config: @@ -15576,133 +17584,6 @@ 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 minItems: 1 maxItems: 9 orchestrator_opts: @@ -15718,7 +17599,7 @@ components: type: array items: type: string - example: Possimus sit commodi in dolor unde. + 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 @@ -15727,7 +17608,7 @@ components: type: array items: type: string - example: Illo ut sint cumque quia non enim. + 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 @@ -15757,7 +17638,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: @@ -15862,223 +17743,198 @@ components: 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 + - 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 @@ -17038,7 +18894,7 @@ components: example: true example: candidate_instance_id: 68f50878-44d2-4524-a823-e31bd478706d-n1-689qacsi - skip_validation: false + skip_validation: true FailoverDatabaseNodeResponse: type: object properties: @@ -18733,7 +20589,7 @@ components: type: object properties: database: - $ref: '#/components/schemas/Database5' + $ref: '#/components/schemas/Database6' node_tasks: type: array items: @@ -18756,6 +20612,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 task: $ref: '#/components/schemas/Task' example: @@ -19967,6 +21839,133 @@ 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 + 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 + - 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 + 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 minItems: 1 memory: type: string @@ -20015,6 +22014,8 @@ components: target_session_attrs: primary host_ids: - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 + - 76f9b8c0-4958-11f0-a489-3bb29577c696 memory: 512M orchestrator_opts: swarm: diff --git a/server/internal/api/apiv1/errors.go b/server/internal/api/apiv1/errors.go index 72e05323..3218c6ab 100644 --- a/server/internal/api/apiv1/errors.go +++ b/server/internal/api/apiv1/errors.go @@ -78,6 +78,8 @@ func apiErr(err error) error { return ErrDatabaseAlreadyExists case errors.Is(err, database.ErrInvalidDatabaseUpdate): return makeInvalidInputErr(err) + case errors.Is(err, database.ErrUpgradeNotAvailable): + return makeInvalidInputErr(err) case errors.Is(err, etcd.ErrCannotRemoveSelf): return makeInvalidInputErr(err) case errors.Is(err, etcd.ErrMinimumClusterSize): diff --git a/server/internal/api/apiv1/post_init_handlers.go b/server/internal/api/apiv1/post_init_handlers.go index d5af351b..59d01858 100644 --- a/server/internal/api/apiv1/post_init_handlers.go +++ b/server/internal/api/apiv1/post_init_handlers.go @@ -436,6 +436,31 @@ func (s *PostInitHandlers) UpdateDatabase(ctx context.Context, req *api.UpdateDa }, nil } +func (s *PostInitHandlers) ApplyUpgrade(ctx context.Context, req *api.ApplyUpgradePayload) (*api.ApplyUpgradeResponse, error) { + databaseID, err := dbIdentToString(req.DatabaseID) + if err != nil { + return nil, err + } + + result, err := s.dbSvc.ApplyUpgrade(ctx, databaseID, req.Request.Image) + if err != nil { + return nil, apiErr(err) + } + + t, err := s.workflowSvc.UpgradeDatabase(ctx, result.Database) + if err != nil { + if rollbackErr := s.dbSvc.RollbackApplyUpgrade(ctx, result); rollbackErr != nil { + s.logger.Err(rollbackErr).Msg("failed to roll back upgrade after workflow trigger failure") + } + return nil, apiErr(err) + } + + return &api.ApplyUpgradeResponse{ + 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 8ef6b721..4698c43a 100644 --- a/server/internal/api/apiv1/pre_init_handlers.go +++ b/server/internal/api/apiv1/pre_init_handlers.go @@ -253,6 +253,10 @@ func (s *PreInitHandlers) StartInstance(ctx context.Context, req *api.StartInsta return nil, ErrUninitialized } +func (s *PreInitHandlers) ApplyUpgrade(ctx context.Context, req *api.ApplyUpgradePayload) (*api.ApplyUpgradeResponse, 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/database/apply_upgrade_test.go b/server/internal/database/apply_upgrade_test.go new file mode 100644 index 00000000..a08f1482 --- /dev/null +++ b/server/internal/database/apply_upgrade_test.go @@ -0,0 +1,221 @@ +package database_test + +import ( + "context" + "errors" + "fmt" + "io" + "testing" + + "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/ds" + "github.com/pgEdge/control-plane/server/internal/logging" + "github.com/pgEdge/control-plane/server/internal/pgbackrest" + "github.com/pgEdge/control-plane/server/internal/postgres" + "github.com/pgEdge/control-plane/server/internal/resource" + "github.com/pgEdge/control-plane/server/internal/storage/storagetest" +) + +// stubOrchestrator is a minimal Orchestrator for service-layer tests. +// Only FindUpgrade is configurable; all other methods return zero values. +type stubOrchestrator struct { + findUpgradeFn func(*ds.PgEdgeVersion, string) (*database.AvailableUpgrade, error) +} + +func (s *stubOrchestrator) FindUpgrade(cur *ds.PgEdgeVersion, img string) (*database.AvailableUpgrade, error) { + if s.findUpgradeFn != nil { + return s.findUpgradeFn(cur, img) + } + return nil, database.ErrUpgradeNotAvailable +} + +func (s *stubOrchestrator) GenerateInstanceResources(*database.InstanceSpec, database.Scripts) (*database.InstanceResources, error) { + return nil, nil +} +func (s *stubOrchestrator) GenerateInstanceRestoreResources(*database.InstanceSpec, uuid.UUID) (*database.InstanceResources, error) { + return nil, nil +} +func (s *stubOrchestrator) GenerateServiceInstanceResources(*database.ServiceInstanceSpec) (*database.ServiceInstanceResources, error) { + return nil, nil +} +func (s *stubOrchestrator) GetInstanceConnectionInfo(context.Context, string, string, *int, *int, *ds.PgEdgeVersion) (*database.ConnectionInfo, error) { + return nil, nil +} +func (s *stubOrchestrator) GetServiceInstanceStatus(context.Context, string) (*database.ServiceInstanceStatus, error) { + return nil, nil +} +func (s *stubOrchestrator) CreatePgBackRestBackup(context.Context, io.Writer, *database.InstanceSpec, *pgbackrest.BackupOptions) error { + return nil +} +func (s *stubOrchestrator) ExecuteInstanceCommand(context.Context, io.Writer, string, string, ...string) error { + return nil +} +func (s *stubOrchestrator) ValidateInstanceSpecs(context.Context, []*database.InstanceSpecChange) ([]*database.ValidationResult, error) { + return nil, nil +} +func (s *stubOrchestrator) StopInstance(context.Context, string) error { return nil } +func (s *stubOrchestrator) StartInstance(context.Context, string) error { return nil } +func (s *stubOrchestrator) NodeDSN(context.Context, *resource.Context, string, string, string) (*postgres.DSN, error) { + return nil, nil +} +func (s *stubOrchestrator) InstancePaths(*ds.Version, string) (database.InstancePaths, error) { + return database.InstancePaths{}, nil +} +func (s *stubOrchestrator) ReconcileInstanceSpec(_, _ *database.InstanceSpec) error { return nil } +func (s *stubOrchestrator) ReconcileServiceInstanceSpec(_, _ *database.ServiceInstanceSpec) error { + return nil +} +func (s *stubOrchestrator) AvailableUpgrades(*ds.PgEdgeVersion) []*database.AvailableUpgrade { + return nil +} + +// newTestService constructs a Service wired to an embedded test etcd. +func newTestService(t *testing.T, orch database.Orchestrator) *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) + // hostSvc and portsSvc are not used by ApplyUpgrade / RollbackApplyUpgrade. + return database.NewService(config.Config{}, orch, store, nil, nil, logFactory) +} + +// seedDatabase creates a minimal database record in the store and returns +// its ID. postgresVersion must be a full semver, e.g. "17.9". +func seedDatabase(t *testing.T, svc *database.Service, postgresVersion string) string { + t.Helper() + ctx := t.Context() + db, err := svc.CreateDatabase(ctx, &database.Spec{ + DatabaseName: "test", + PostgresVersion: postgresVersion, + SpockVersion: "5", + Nodes: []*database.Node{ + {Name: "n1", HostIDs: []string{"host-1"}}, + }, + DatabaseUsers: []*database.User{ + {Username: "admin", Attributes: []string{"SUPERUSER", "LOGIN"}}, + }, + }) + require.NoError(t, err) + // Transition to available so the state is modifiable. + require.NoError(t, svc.UpdateDatabaseState(ctx, db.DatabaseID, database.DatabaseStateCreating, database.DatabaseStateAvailable)) + return db.DatabaseID +} + +func TestService_ApplyUpgrade(t *testing.T) { + targetImage := "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.8-standard-1" + successfulUpgrade := &database.AvailableUpgrade{ + PostgresVersion: "17.10", + SpockVersion: "5.0.8", + Image: targetImage, + } + + t.Run("happy path: spec updated and state set to modifying", func(t *testing.T) { + orch := &stubOrchestrator{ + findUpgradeFn: func(_ *ds.PgEdgeVersion, _ string) (*database.AvailableUpgrade, error) { + return successfulUpgrade, nil + }, + } + svc := newTestService(t, orch) + dbID := seedDatabase(t, svc, "17.9") + + result, err := svc.ApplyUpgrade(t.Context(), dbID, targetImage) + require.NoError(t, err) + require.NotNil(t, result) + + assert.Equal(t, database.DatabaseStateModifying, result.Database.State) + assert.Equal(t, "17.10", result.Database.Spec.PostgresVersion) + assert.Equal(t, database.DatabaseStateAvailable, result.PrevState) + }) + + t.Run("returns ErrDatabaseNotFound for unknown id", func(t *testing.T) { + svc := newTestService(t, &stubOrchestrator{}) + _, err := svc.ApplyUpgrade(t.Context(), "no-such-db", targetImage) + assert.True(t, errors.Is(err, database.ErrDatabaseNotFound)) + }) + + t.Run("returns ErrDatabaseNotModifiable when not in modifiable state", func(t *testing.T) { + orch := &stubOrchestrator{} + svc := newTestService(t, orch) + dbID := seedDatabase(t, svc, "17.9") + require.NoError(t, svc.UpdateDatabaseState(t.Context(), dbID, database.DatabaseStateAvailable, database.DatabaseStateModifying)) + + _, err := svc.ApplyUpgrade(t.Context(), dbID, targetImage) + assert.True(t, errors.Is(err, database.ErrDatabaseNotModifiable)) + }) + + t.Run("propagates ErrUpgradeNotAvailable from orchestrator", func(t *testing.T) { + orch := &stubOrchestrator{ + findUpgradeFn: 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, "17.9") + + _, err := svc.ApplyUpgrade(t.Context(), dbID, targetImage) + assert.True(t, errors.Is(err, database.ErrUpgradeNotAvailable)) + }) + + t.Run("clears per-node version override matching old version", func(t *testing.T) { + orch := &stubOrchestrator{ + findUpgradeFn: 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: "17.9", + SpockVersion: "5", + Nodes: []*database.Node{ + {Name: "n1", HostIDs: []string{"host-1"}, PostgresVersion: "17.9"}, + }, + 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.ApplyUpgrade(ctx, db.DatabaseID, targetImage) + require.NoError(t, err) + for _, node := range result.Database.Spec.Nodes { + assert.Empty(t, node.PostgresVersion, "per-node override matching old version should be cleared") + } + }) +} + +func TestService_RollbackApplyUpgrade(t *testing.T) { + targetImage := "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.8-standard-1" + + t.Run("restores spec and state atomically", func(t *testing.T) { + orch := &stubOrchestrator{ + findUpgradeFn: func(_ *ds.PgEdgeVersion, _ string) (*database.AvailableUpgrade, error) { + return &database.AvailableUpgrade{PostgresVersion: "17.10", SpockVersion: "5.0.8", Image: targetImage}, nil + }, + } + svc := newTestService(t, orch) + dbID := seedDatabase(t, svc, "17.9") + + result, err := svc.ApplyUpgrade(t.Context(), dbID, targetImage) + require.NoError(t, err) + assert.Equal(t, "17.10", result.Database.Spec.PostgresVersion) + + require.NoError(t, svc.RollbackApplyUpgrade(t.Context(), result)) + + restored, err := svc.GetDatabase(t.Context(), dbID) + require.NoError(t, err) + assert.Equal(t, database.DatabaseStateAvailable, restored.State) + assert.Equal(t, "17.9", restored.Spec.PostgresVersion) + }) +} diff --git a/server/internal/database/orchestrator.go b/server/internal/database/orchestrator.go index 47518ce5..be247128 100644 --- a/server/internal/database/orchestrator.go +++ b/server/internal/database/orchestrator.go @@ -2,6 +2,7 @@ package database import ( "context" + "errors" "fmt" "io" "net" @@ -15,6 +16,8 @@ import ( "github.com/pgEdge/control-plane/server/internal/resource" ) +var ErrUpgradeNotAvailable = errors.New("upgrade not available") + const pgEdgeUser = "pgedge" // ResourceTypeServiceInstance is the resource type identifier for service instances. @@ -194,6 +197,11 @@ type Orchestrator interface { // (postgres_major, spock_major) bucket as current. Returns nil when // upgrade discovery is not applicable (e.g. systemd orchestrator). AvailableUpgrades(current *ds.PgEdgeVersion) []*AvailableUpgrade + // FindUpgrade validates that targetImage is a stable upgrade from current + // in the same (postgres_major, spock_major) bucket and strictly newer. + // Returns the validated upgrade descriptor on success, or + // ErrUpgradeNotAvailable (possibly wrapped) on any validation failure. + FindUpgrade(current *ds.PgEdgeVersion, 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 3195fa2c..29d10951 100644 --- a/server/internal/database/service.go +++ b/server/internal/database/service.go @@ -115,30 +115,7 @@ func (s *Service) UpdateDatabase(ctx context.Context, state DatabaseState, spec return nil, ErrDatabaseNotModifiable } - instances, err := s.GetInstances(ctx, spec.DatabaseID) - if err != nil { - return nil, fmt.Errorf("failed to get database instances: %w", err) - } - - serviceInstances, err := s.GetServiceInstances(ctx, spec.DatabaseID) - if err != nil { - return nil, fmt.Errorf("failed to get service instances: %w", err) - } - - currentSpec.Spec = spec - currentDB.UpdatedAt = time.Now() - currentDB.State = state - - if err := s.store.Txn( - s.store.Spec.Update(currentSpec), - s.store.Database.Update(currentDB), - ).Commit(ctx); err != nil { - return nil, fmt.Errorf("failed to persist database: %w", err) - } - - db := storedToDatabase(currentDB, currentSpec, instances, serviceInstances) - - return db, nil + return s.applySpecUpdate(ctx, currentSpec, currentDB, spec, state) } func (s *Service) DeleteDatabase(ctx context.Context, databaseID string) error { @@ -753,6 +730,146 @@ func (s *Service) AvailableUpgrades(current *ds.PgEdgeVersion) []*AvailableUpgra return s.orchestrator.AvailableUpgrades(current) } +// ApplyUpgradeResult is returned by ApplyUpgrade. It carries the information +// needed to roll back the upgrade if the workflow fails to start. +type ApplyUpgradeResult struct { + Database *Database + PrevState DatabaseState + prevSpec *Spec +} + +// ApplyUpgrade validates targetImage against the manifest, updates the +// database spec's PostgresVersion to the new version, and sets the database +// state to modifying. The workflow is responsible for updating instance specs +// and pinning ResolvedImage in etcd via ReconcileInstanceSpec. +func (s *Service) ApplyUpgrade(ctx context.Context, databaseID, targetImage string) (*ApplyUpgradeResult, 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.FindUpgrade(currentVersion, targetImage) + if err != nil { + return nil, err + } + + // Capture previous state and spec before mutation for rollback. + prevState := currentDB.State + prevSpec := currentSpec.Spec + + // Clone and update the spec with the new postgres version. + newSpec := currentSpec.Clone() + currentPG := currentSpec.PostgresVersion + newSpec.PostgresVersion = upgrade.PostgresVersion + // Clear per-node version overrides that match the old top-level version so + // all nodes pick up the new version uniformly. + for _, node := range newSpec.Nodes { + nodeVersion := node.PostgresVersion + if nodeVersion == "" { + nodeVersion = currentPG + } + if nodeVersion == currentPG { + node.PostgresVersion = "" + } + } + newSpec.NormalizePostgresVersions() + + db, err := s.applySpecUpdate(ctx, currentSpec, currentDB, newSpec, DatabaseStateModifying) + if err != nil { + return nil, err + } + + return &ApplyUpgradeResult{ + Database: db, + PrevState: prevState, + prevSpec: prevSpec, + }, nil +} + +// applySpecUpdate persists newSpec and newState atomically and returns the +// resulting Database. currentSpec and currentDB must already be fetched and +// validated by the caller. +func (s *Service) applySpecUpdate( + ctx context.Context, + currentSpec *StoredSpec, + currentDB *StoredDatabase, + newSpec *Spec, + newState DatabaseState, +) (*Database, error) { + instances, err := s.GetInstances(ctx, newSpec.DatabaseID) + if err != nil { + return nil, fmt.Errorf("failed to get instances: %w", err) + } + serviceInstances, err := s.GetServiceInstances(ctx, newSpec.DatabaseID) + if err != nil { + return nil, fmt.Errorf("failed to get service instances: %w", err) + } + + currentSpec.Spec = newSpec + currentDB.UpdatedAt = time.Now() + currentDB.State = newState + + if err := s.store.Txn( + s.store.Spec.Update(currentSpec), + s.store.Database.Update(currentDB), + ).Commit(ctx); err != nil { + return nil, fmt.Errorf("failed to persist database: %w", err) + } + + return storedToDatabase(currentDB, currentSpec, instances, serviceInstances), nil +} + +// RollbackApplyUpgrade atomically restores the database spec and state to +// their values before ApplyUpgrade was called. It is intended to be called +// when the workflow fails to start after ApplyUpgrade has already committed. +func (s *Service) RollbackApplyUpgrade(ctx context.Context, result *ApplyUpgradeResult) error { + databaseID := result.Database.DatabaseID + + currentStoredSpec, err := s.store.Spec.GetByKey(databaseID).Exec(ctx) + if errors.Is(err, storage.ErrNotFound) { + return ErrDatabaseNotFound + } else if err != nil { + return fmt.Errorf("failed to get database spec for rollback: %w", err) + } + + currentDB, err := s.store.Database.GetByKey(databaseID).Exec(ctx) + if errors.Is(err, storage.ErrNotFound) { + return ErrDatabaseNotFound + } else if err != nil { + return fmt.Errorf("failed to get database for rollback: %w", err) + } + + currentStoredSpec.Spec = result.prevSpec + currentDB.State = result.PrevState + currentDB.UpdatedAt = time.Now() + + if err := s.store.Txn( + s.store.Spec.Update(currentStoredSpec), + s.store.Database.Update(currentDB), + ).Commit(ctx); err != nil { + return fmt.Errorf("failed to roll back upgrade: %w", err) + } + + return nil +} + 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) diff --git a/server/internal/orchestrator/swarm/find_upgrade_test.go b/server/internal/orchestrator/swarm/find_upgrade_test.go new file mode 100644 index 00000000..57f2504f --- /dev/null +++ b/server/internal/orchestrator/swarm/find_upgrade_test.go @@ -0,0 +1,199 @@ +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" +) + +func testVersions(t *testing.T) *Versions { + t.Helper() + return NewVersions(config.Config{ + DockerSwarm: config.DockerSwarm{ + ImageRepositoryHost: "ghcr.io/pgedge", + }, + }) +} + +func testVersionsWithStability(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("17.9", "5"), &Images{ + PgEdgeImage: "ghcr.io/pgedge/pgedge-postgres:17.9-spock5.0.6-standard-2", + Stability: "stable", + }) + v.addImage(ds.MustParsePgEdgeVersion("17.10", "5"), &Images{ + PgEdgeImage: "ghcr.io/pgedge/pgedge-postgres:17.10-rc1-spock5.0.7-dev-1", + Stability: "dev", + }) + v.addImage(ds.MustParsePgEdgeVersion("18.1", "5"), &Images{ + PgEdgeImage: "ghcr.io/pgedge/pgedge-postgres:18.1-spock5.0.4-standard-4", + Stability: "stable", + }) + v.defaultVersion = ds.MustParsePgEdgeVersion("18.1", "5") + return v +} + +// ---- FindByImage ----------------------------------------------------------- + +func TestVersions_FindByImage(t *testing.T) { + v := testVersions(t) + + // Pick a known image from the manifest. + known := ds.MustParsePgEdgeVersion("17.9", "5") + img, err := v.GetImages(known) + require.NoError(t, err) + knownImage := img.PgEdgeImage + + t.Run("returns version and images for a known image", func(t *testing.T) { + ver, got, ok := v.FindByImage(knownImage) + require.True(t, ok) + require.NotNil(t, ver) + require.NotNil(t, got) + assert.Equal(t, knownImage, got.PgEdgeImage) + assert.True(t, ver.PostgresVersion.Compare(known.PostgresVersion) == 0) + }) + + t.Run("returns false for an unknown image", func(t *testing.T) { + ver, got, ok := v.FindByImage("ghcr.io/pgedge/pgedge-postgres:99.99-unknown") + assert.False(t, ok) + assert.Nil(t, ver) + assert.Nil(t, got) + }) + + t.Run("returns false for empty string", func(t *testing.T) { + _, _, ok := v.FindByImage("") + assert.False(t, ok) + }) + + t.Run("each supported version has a distinct findable image", func(t *testing.T) { + for _, ver := range v.supportedVersions { + img, err := v.GetImages(ver) + require.NoError(t, err) + _, _, ok := v.FindByImage(img.PgEdgeImage) + assert.True(t, ok, "could not find image %s back by value", img.PgEdgeImage) + } + }) +} + +// ---- Orchestrator.FindUpgrade ---------------------------------------------- + +func newOrchestratorWithVersions(versions *Versions) *Orchestrator { + return &Orchestrator{versions: versions} +} + +func TestOrchestrator_FindUpgrade(t *testing.T) { + v := testVersions(t) + o := newOrchestratorWithVersions(v) + + current := ds.MustParsePgEdgeVersion("17.9", "5") + newer := ds.MustParsePgEdgeVersion("17.10", "5") + + newerImg, err := v.GetImages(newer) + require.NoError(t, err) + newerImage := newerImg.PgEdgeImage + + currentImg, err := v.GetImages(current) + require.NoError(t, err) + currentImage := currentImg.PgEdgeImage + + pg18 := ds.MustParsePgEdgeVersion("18.1", "5") + pg18Img, err := v.GetImages(pg18) + require.NoError(t, err) + pg18Image := pg18Img.PgEdgeImage + + t.Run("happy path: returns upgrade for valid newer stable same-bucket image", func(t *testing.T) { + got, err := o.FindUpgrade(current, newerImage) + require.NoError(t, err) + require.NotNil(t, got) + assert.Equal(t, newerImage, got.Image) + assert.Equal(t, newer.PostgresVersion.String(), got.PostgresVersion) + assert.Equal(t, newer.SpockVersion.String(), got.SpockVersion) + }) + + t.Run("rejects image not in manifest", func(t *testing.T) { + _, err := o.FindUpgrade(current, "ghcr.io/pgedge/pgedge-postgres:99.99-unknown") + require.Error(t, err) + assert.True(t, errors.Is(err, database.ErrUpgradeNotAvailable)) + }) + + t.Run("rejects same version (not strictly newer)", func(t *testing.T) { + _, err := o.FindUpgrade(current, currentImage) + require.Error(t, err) + assert.True(t, errors.Is(err, database.ErrUpgradeNotAvailable)) + }) + + t.Run("rejects older version (downgrade 17.10 → 17.9)", func(t *testing.T) { + current1710 := ds.MustParsePgEdgeVersion("17.10", "5") + _, err := o.FindUpgrade(current1710, currentImage) // 17.9 < 17.10 + require.Error(t, err) + assert.True(t, errors.Is(err, database.ErrUpgradeNotAvailable)) + }) + + t.Run("rejects image in a different postgres major bucket", func(t *testing.T) { + _, err := o.FindUpgrade(current, pg18Image) + require.Error(t, err) + assert.True(t, errors.Is(err, database.ErrUpgradeNotAvailable)) + }) + + t.Run("dev stability is rejected", func(t *testing.T) { + vs := testVersionsWithStability(t) + od := newOrchestratorWithVersions(vs) + cur := ds.MustParsePgEdgeVersion("17.9", "5") + + devImage := "ghcr.io/pgedge/pgedge-postgres:17.10-rc1-spock5.0.7-dev-1" + _, err := od.FindUpgrade(cur, devImage) + require.Error(t, err) + assert.True(t, errors.Is(err, database.ErrUpgradeNotAvailable)) + }) + + t.Run("stable same-version is rejected", func(t *testing.T) { + vs := testVersionsWithStability(t) + od := newOrchestratorWithVersions(vs) + cur := ds.MustParsePgEdgeVersion("17.9", "5") + + stableImage17_9 := "ghcr.io/pgedge/pgedge-postgres:17.9-spock5.0.6-standard-2" + // 17.9 is the current, there is no newer 17.x stable entry — should reject + _, err := od.FindUpgrade(cur, stableImage17_9) + require.Error(t, err) + assert.True(t, errors.Is(err, database.ErrUpgradeNotAvailable), "same version should be rejected") + }) + + t.Run("rejects upgrade across different spock major buckets", func(t *testing.T) { + cfg := config.Config{DockerSwarm: config.DockerSwarm{ImageRepositoryHost: "ghcr.io/pgedge"}} + vs := &Versions{cfg: cfg, images: make(map[string]map[string]*Images)} + vs.addImage(ds.MustParsePgEdgeVersion("17.9", "4"), &Images{ + PgEdgeImage: "ghcr.io/pgedge/pgedge-postgres:17.9-spock4.0.0-standard-1", + Stability: "stable", + }) + vs.addImage(ds.MustParsePgEdgeVersion("17.10", "5"), &Images{ + PgEdgeImage: "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.0-standard-1", + Stability: "stable", + }) + vs.defaultVersion = ds.MustParsePgEdgeVersion("17.10", "5") + + od := newOrchestratorWithVersions(vs) + curSpock4 := ds.MustParsePgEdgeVersion("17.9", "4") + targetSpock5Image := "ghcr.io/pgedge/pgedge-postgres:17.10-spock5.0.0-standard-1" + + _, err := od.FindUpgrade(curSpock4, targetSpock5Image) + require.Error(t, err) + assert.True(t, errors.Is(err, database.ErrUpgradeNotAvailable)) + }) + + t.Run("returns correct fields in upgrade descriptor", func(t *testing.T) { + got, err := o.FindUpgrade(current, newerImage) + require.NoError(t, err) + assert.NotEmpty(t, got.PostgresVersion) + assert.NotEmpty(t, got.SpockVersion) + assert.NotEmpty(t, got.Image) + assert.Contains(t, got.Image, "ghcr.io/pgedge") + }) +} diff --git a/server/internal/orchestrator/swarm/images.go b/server/internal/orchestrator/swarm/images.go index 00edb0e3..554ac87f 100644 --- a/server/internal/orchestrator/swarm/images.go +++ b/server/internal/orchestrator/swarm/images.go @@ -124,6 +124,22 @@ func imageTag(cfg config.Config, tag string) string { return fmt.Sprintf("%s/pgedge-postgres:%s", cfg.DockerSwarm.ImageRepositoryHost, tag) } +// FindByImage returns the PgEdgeVersion and Images for the manifest entry +// whose PgEdgeImage matches image exactly. Returns (nil, nil, false) when no +// entry matches. +func (v *Versions) FindByImage(image string) (*ds.PgEdgeVersion, *Images, bool) { + for _, ver := range v.supportedVersions { + img, err := v.GetImages(ver) + if err != nil { + continue + } + if img.PgEdgeImage == image { + return ver, img, true + } + } + return nil, nil, false +} + // AvailableUpgrades returns all newer stable manifest entries in the same // (postgres_major, spock_major) bucket as current. Returns nil when current is // nil or no newer entries exist. diff --git a/server/internal/orchestrator/swarm/orchestrator.go b/server/internal/orchestrator/swarm/orchestrator.go index 5a1a0fc6..592e7bfd 100644 --- a/server/internal/orchestrator/swarm/orchestrator.go +++ b/server/internal/orchestrator/swarm/orchestrator.go @@ -310,6 +310,44 @@ func (o *Orchestrator) AvailableUpgrades(current *ds.PgEdgeVersion) []*database. return o.versions.AvailableUpgrades(current) } +func (o *Orchestrator) FindUpgrade(current *ds.PgEdgeVersion, targetImage string) (*database.AvailableUpgrade, error) { + ver, img, ok := o.versions.FindByImage(targetImage) + if !ok { + return nil, fmt.Errorf("%w: image not found in manifest: %s", database.ErrUpgradeNotAvailable, targetImage) + } + if img.Stability != "" && img.Stability != "stable" { + return nil, fmt.Errorf("%w: target image stability is %q, must be stable", database.ErrUpgradeNotAvailable, img.Stability) + } + + 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", database.ErrUpgradeNotAvailable, targetPGMajor, currentPGMajor) + } + + currentSpockMajor, ok := current.SpockVersion.Major() + if !ok { + return nil, fmt.Errorf("%w: cannot determine current spock major version", database.ErrUpgradeNotAvailable) + } + targetSpockMajor, ok2 := ver.SpockVersion.Major() + if !ok2 || targetSpockMajor != currentSpockMajor { + return nil, fmt.Errorf("%w: target spock major %d differs from current %d", database.ErrUpgradeNotAvailable, targetSpockMajor, currentSpockMajor) + } + + if ver.PostgresVersion.Compare(current.PostgresVersion) <= 0 { + return nil, fmt.Errorf("%w: target version %s is not newer than current %s", database.ErrUpgradeNotAvailable, ver.PostgresVersion, current.PostgresVersion) + } + + 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 635f361a..a38f540a 100644 --- a/server/internal/orchestrator/systemd/orchestrator.go +++ b/server/internal/orchestrator/systemd/orchestrator.go @@ -159,6 +159,10 @@ func (o *Orchestrator) AvailableUpgrades(_ *ds.PgEdgeVersion) []*database.Availa return nil } +func (o *Orchestrator) FindUpgrade(_ *ds.PgEdgeVersion, _ string) (*database.AvailableUpgrade, error) { + 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) 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 ff5bd90e..7c01077e 100644 --- a/server/internal/task/task.go +++ b/server/internal/task/task.go @@ -40,6 +40,7 @@ const ( TypeSwitchover Type = "switchover" TypeFailover Type = "failover" TypeRemoveHost Type = "remove_host" + TypeUpgrade Type = "upgrade" ) type Status string diff --git a/server/internal/workflows/service.go b/server/internal/workflows/service.go index c247b9ac..29a1cb67 100644 --- a/server/internal/workflows/service.go +++ b/server/internal/workflows/service.go @@ -97,6 +97,27 @@ func (s *Service) UpdateDatabase(ctx context.Context, db *database.Database, for return t, nil } +func (s *Service) UpgradeDatabase(ctx context.Context, db *database.Database) (*task.Task, error) { + databaseID := db.DatabaseID + t, err := s.taskSvc.CreateTask(ctx, task.Options{ + Scope: task.ScopeDatabase, + DatabaseID: databaseID, + Type: task.TypeUpgrade, + }) + if err != nil { + return nil, fmt.Errorf("failed to create upgrade task: %w", err) + } + input := &UpdateDatabaseInput{ + TaskID: t.TaskID, + Spec: db.Spec, + Variables: db.Variables(), + } + if err := s.createWorkflow(ctx, t, s.workflows.UpdateDatabase, 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,