From eff2355b95cae7bcc73e258a288dd4653517ea55 Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Tue, 16 Jun 2026 20:08:28 -0700 Subject: [PATCH 1/5] feat: document control plane --- docs/enterprise_edition/control_plane/.pages | 5 ++ .../control_plane/features/.pages | 3 ++ .../control_plane/features/alerts.md | 49 +++++++++++++++++++ .../control_plane/features/config.md | 0 .../control_plane/features/index.md | 15 ++++++ .../control_plane/features/instances.md | 0 .../control_plane/features/metrics.md | 0 .../control_plane/features/slack.md | 32 ++++++++++++ 8 files changed, 104 insertions(+) create mode 100644 docs/enterprise_edition/control_plane/.pages create mode 100644 docs/enterprise_edition/control_plane/features/.pages create mode 100644 docs/enterprise_edition/control_plane/features/alerts.md create mode 100644 docs/enterprise_edition/control_plane/features/config.md create mode 100644 docs/enterprise_edition/control_plane/features/index.md create mode 100644 docs/enterprise_edition/control_plane/features/instances.md create mode 100644 docs/enterprise_edition/control_plane/features/metrics.md create mode 100644 docs/enterprise_edition/control_plane/features/slack.md diff --git a/docs/enterprise_edition/control_plane/.pages b/docs/enterprise_edition/control_plane/.pages new file mode 100644 index 00000000..1697fd8d --- /dev/null +++ b/docs/enterprise_edition/control_plane/.pages @@ -0,0 +1,5 @@ +nav: + - index.md + - installation.md + - features + - ... diff --git a/docs/enterprise_edition/control_plane/features/.pages b/docs/enterprise_edition/control_plane/features/.pages new file mode 100644 index 00000000..8ae5ab46 --- /dev/null +++ b/docs/enterprise_edition/control_plane/features/.pages @@ -0,0 +1,3 @@ +nav: + - index.md + - ... diff --git a/docs/enterprise_edition/control_plane/features/alerts.md b/docs/enterprise_edition/control_plane/features/alerts.md new file mode 100644 index 00000000..e576e9be --- /dev/null +++ b/docs/enterprise_edition/control_plane/features/alerts.md @@ -0,0 +1,49 @@ +# Alerts + +Since the control plane has access to real-time PgDog [metrics](metrics.md), it can detect outliers and trigger automatic alerts. + +## How it works + +The control plane evaluates the metrics it receives from all PgDog instances on a continuous loop. When they exceed pre-configured thresholds, an incident +is created using one of configured integrations. + +### Integrations + +The following incident management providers are supported: + +| Provider | Description | +|-|-| +| [incident.io](https://incident.io/) | The control plane will create an incident with the highest available priority. | + +### Configuration + +Alerts are **disabled** by default. To enable them, configure a provider's API key and set thresholds for each supported metric you would like to monitor: + +```yaml title="values.yaml" +control: + config: + alerts: + evaluation_window_secs: 300 + thresholds: + clients_waiting: 10 + cpu: 90.0 + memory: 2048 + server_connections: 100 + incident_io: + api_key: inc_live_xxx +``` + +#### Parameters + +The following parameters are configurable via the [Helm chart](../installation.md): + +| Parameter | Description | Unit | +|-|-|-| +| `evaluation_window_secs` | The evaluation window for the metrics. Longer windows reduce the chance of false positives in spiky workloads. Shorter windows are quicker to notify in case of a real issue. | Seconds, e.g., `300` (5 minutes) | +| `thresholds.clients_waiting` | Average number of clients waiting for a connection from a pool. | Clients, e.g., `10` | +| `thresholds.cpu` | CPU utilization of each PgDog pod. | Percentage, e.g., `90.0` (90%) | +| `thresholds.memory` | Memory utilization of each PgDog pod. | MiB, e.g., `2048` (2048 MiB) | +| `thresholds.server_connections` | Number of open connections from PgDog to Postgres. | Connections, e.g., `100` | + +!!! note "Disabled by default" + Thresholds have no defaults. If not configured, a threshold will not trigger an alert. diff --git a/docs/enterprise_edition/control_plane/features/config.md b/docs/enterprise_edition/control_plane/features/config.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/enterprise_edition/control_plane/features/index.md b/docs/enterprise_edition/control_plane/features/index.md new file mode 100644 index 00000000..6775f2ee --- /dev/null +++ b/docs/enterprise_edition/control_plane/features/index.md @@ -0,0 +1,15 @@ +--- +icon: material/format-list-bulleted-type +--- + +# Features + +The control plane provides operational features for monitoring, configuring, and managing PgDog deployments. + +| Feature | Description | +|-|-| +| [Alerts](alerts.md) | Detect outliers in live PgDog metrics and send incidents to supported providers. | +| [Configuration](config.md) | Manage PgDog configuration across connected instances. | +| [Instances](instances.md) | View and manage PgDog instances connected to the control plane. | +| [Metrics](metrics.md) | Inspect metrics reported by PgDog instances. | +| [Slack integration](slack.md) | Send deployment and configuration notifications to a Slack channel. | diff --git a/docs/enterprise_edition/control_plane/features/instances.md b/docs/enterprise_edition/control_plane/features/instances.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/enterprise_edition/control_plane/features/metrics.md b/docs/enterprise_edition/control_plane/features/metrics.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/enterprise_edition/control_plane/features/slack.md b/docs/enterprise_edition/control_plane/features/slack.md new file mode 100644 index 00000000..04cbcd52 --- /dev/null +++ b/docs/enterprise_edition/control_plane/features/slack.md @@ -0,0 +1,32 @@ +# Slack integration + +The control plane can send notifications to a Slack channel. Notifications include changes to managed PgDog deployments, like Helm chart updates, configuration reloading, and updates to database topology. + +## Configuration + +Slack integration is **disabled** by default and can be enabled with configuration: + +```yaml title="values.yaml" +control: + config: + slack: + bot_token: "xoxb-[...]" + channel: "C0123456789" +``` + +The following parameters can be configured via the [Helm chart](../installation.md): + +| Parameters | Description | +|-|-| +| `bot_token` | The Slack API bot token. | +| `channel` | The slack channel ID where the Slack bot is allowed to post messages. | + +## Notifications + +If Slack integration is configured, the control plane will send the following notifications to a Slack channel: + +| Notification | Description | +|-|-| +| Helm install (start) | The control plane starts executing the `helm upgrade --install` command to modify/create a PgDog deployment. | +| Helm install (end) | The control plane is finished executing the `helm ugprade --install` command. If any errors occur, they are included in the notification. | +| Configuration reload | The control plane triggers a configuration reload on all PgDog instances in a deployment. | From 4ab6db7dfa6fa7c6c9274d9b858fd279ce23a17b Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Mon, 22 Jun 2026 12:26:26 -0700 Subject: [PATCH 2/5] save --- .../control_plane/features/alerts.md | 23 +++++++++++++------ .../control_plane/features/deployments.md | 3 +++ .../enterprise_edition/control_plane/index.md | 7 ++++++ main.py | 2 +- 4 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 docs/enterprise_edition/control_plane/features/deployments.md diff --git a/docs/enterprise_edition/control_plane/features/alerts.md b/docs/enterprise_edition/control_plane/features/alerts.md index e576e9be..ad507cc3 100644 --- a/docs/enterprise_edition/control_plane/features/alerts.md +++ b/docs/enterprise_edition/control_plane/features/alerts.md @@ -7,6 +7,10 @@ Since the control plane has access to real-time PgDog [metrics](metrics.md), it The control plane evaluates the metrics it receives from all PgDog instances on a continuous loop. When they exceed pre-configured thresholds, an incident is created using one of configured integrations. +
+ Alerts +
+ ### Integrations The following incident management providers are supported: @@ -35,15 +39,20 @@ control: #### Parameters +!!! note "Disabled by default" + Thresholds have no defaults. If a threshold is not configured, its metric will not be monitored. + + The following parameters are configurable via the [Helm chart](../installation.md): | Parameter | Description | Unit | |-|-|-| -| `evaluation_window_secs` | The evaluation window for the metrics. Longer windows reduce the chance of false positives in spiky workloads. Shorter windows are quicker to notify in case of a real issue. | Seconds, e.g., `300` (5 minutes) | -| `thresholds.clients_waiting` | Average number of clients waiting for a connection from a pool. | Clients, e.g., `10` | -| `thresholds.cpu` | CPU utilization of each PgDog pod. | Percentage, e.g., `90.0` (90%) | -| `thresholds.memory` | Memory utilization of each PgDog pod. | MiB, e.g., `2048` (2048 MiB) | -| `thresholds.server_connections` | Number of open connections from PgDog to Postgres. | Connections, e.g., `100` | +| `evaluation_window_secs` | The metrics evaluation window. Metrics are averaged over this period to produce an alert signal. | Seconds, e.g., `300` (5 minutes) | +| `clients_waiting` | Average number of clients waiting for a connection from a pool. | Clients, e.g., `10` | +| `cpu` | Average CPU utilization of each PgDog pod. | Percentage, e.g., `90.0` (90%) | +| `memory` | Average memory utilization of each PgDog pod. | MiB, e.g., `2048` (2048 MiB) | +| `server_connections` | Average Nnmber of open connections from PgDog to Postgres. | Connections, e.g., `100` | -!!! note "Disabled by default" - Thresholds have no defaults. If not configured, a threshold will not trigger an alert. +#### Evaluation window + +Longer evaluation windows reduce the chance of false positives in spiky workloads. Shorter windows will be evaluated quicker and will trigger faster notifications in case of an incident. diff --git a/docs/enterprise_edition/control_plane/features/deployments.md b/docs/enterprise_edition/control_plane/features/deployments.md new file mode 100644 index 00000000..e3f80186 --- /dev/null +++ b/docs/enterprise_edition/control_plane/features/deployments.md @@ -0,0 +1,3 @@ +# Deployments + +The control plane is primarily useful for monitoring and managing PgDog deployments. To make this work, it integrates with the Kubernetes API (for service discovery) and with PgDog directly, via an internal protocol, to read telemetry and control its behavior. diff --git a/docs/enterprise_edition/control_plane/index.md b/docs/enterprise_edition/control_plane/index.md index 2ccc934d..3e22c144 100644 --- a/docs/enterprise_edition/control_plane/index.md +++ b/docs/enterprise_edition/control_plane/index.md @@ -73,3 +73,10 @@ PgDog transmits the following information to the control plane: | Queries | Queries that are currently executing through each PgDog node. | | Query plans | Output of `EXPLAIN` for slow and sampled queries, collected in the background. | | Configuration | Current PgDog settings and database schema. | + +## Read more + +{{ next_steps_links([ + ("Installation", "installation.md", "Deploy the control plane alongside your PgDog nodes and connect them together."), + ("Features", "features/index.md", "Explore control plane features like alerts, configuration management, instances, metrics, and Slack integration."), +]) }} diff --git a/main.py b/main.py index 1e02e23b..e24a5b5f 100644 --- a/main.py +++ b/main.py @@ -10,7 +10,7 @@ # Latest released tag for the Enterprise Docker images. Update this in one # place; reference it in docs with {{ enterprise_tag }}. Can be overridden at # build time with the ENTERPRISE_TAG environment variable. -ENTERPRISE_TAG = os.environ.get("ENTERPRISE_TAG", "v2026-06-15") +ENTERPRISE_TAG = os.environ.get("ENTERPRISE_TAG", "v2026-06-17") def define_env(env): From d97c0279fa69188aee3e89e28796b590654fc844 Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Mon, 22 Jun 2026 13:11:47 -0700 Subject: [PATCH 3/5] Autoscaling --- .../control_plane/features/alerts.md | 4 + .../control_plane/features/autoscaling.md | 137 ++++++++++++++++++ .../control_plane/features/config.md | 3 + .../control_plane/features/deployments.md | 4 + .../control_plane/features/index.md | 1 + .../control_plane/features/instances.md | 3 + .../control_plane/features/metrics.md | 3 + .../control_plane/features/slack.md | 4 + .../control_plane/installation.md | 5 +- docs/images/ee/alerts.png | Bin 0 -> 36312 bytes 10 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 docs/enterprise_edition/control_plane/features/autoscaling.md create mode 100644 docs/images/ee/alerts.png diff --git a/docs/enterprise_edition/control_plane/features/alerts.md b/docs/enterprise_edition/control_plane/features/alerts.md index ad507cc3..5b1a9f71 100644 --- a/docs/enterprise_edition/control_plane/features/alerts.md +++ b/docs/enterprise_edition/control_plane/features/alerts.md @@ -1,3 +1,7 @@ +--- +icon: material/alert-circle-outline +--- + # Alerts Since the control plane has access to real-time PgDog [metrics](metrics.md), it can detect outliers and trigger automatic alerts. diff --git a/docs/enterprise_edition/control_plane/features/autoscaling.md b/docs/enterprise_edition/control_plane/features/autoscaling.md new file mode 100644 index 00000000..85ac8906 --- /dev/null +++ b/docs/enterprise_edition/control_plane/features/autoscaling.md @@ -0,0 +1,137 @@ +--- +icon: material/arrow-expand-all +--- + +# Autoscaling + +Autoscaling automatically adjusts PgDog settings when the number of processes (e.g. pods in Kubernetes) in the same deployment changes. This simplifies configuration: you no longer need to perform manual calculations to resize connection pools. + +## Configuration + +Autoscaling is **disabled** by default. To enable it, add the following settings to the [control plane](../installation.md) Helm [chart](https://github.com/pgdogdev/helm-ee): + +```yaml title="values.yaml" +control: + config: + autoscaling: + pool_size: true +``` + +## How it works + +When a PgDog process connects to the [control plane](../../control_plane/index.md), the control plane provides it with the total number of processes that are part of the same deployment. PgDog then automatically adjusts its configuration by dividing all pool-related configuration values by that number, for example: + +=== "Configuration" + ```toml title="pgdog.toml" + [general] + default_pool_size = 200 + + [[databases]] + name = "prod" + host = "10.0.0.1" + min_pool_size = 50 + ``` + + ```toml title="users.toml" + [[users]] + name = "postgres" + database = "prod" + pool_size = 100 + ``` + +=== "2 processes" + ```toml title="pgdog.toml" + [general] + default_pool_size = 100 + + [[databases]] + name = "prod" + host = "10.0.0.1" + min_pool_size = 25 + ``` + + ```toml title="users.toml" + [[users]] + name = "postgres" + database = "prod" + pool_size = 50 + ``` + +=== "4 processes" + ```toml title="pgdog.toml" + [general] + default_pool_size = 50 + + [[databases]] + name = "prod" + host = "10.0.0.1" + min_pool_size = 12 + ``` + + ```toml title="users.toml" + [[users]] + name = "postgres" + database = "prod" + pool_size = 25 + ``` + +=== "8 processes" + ```toml title="pgdog.toml" + [general] + default_pool_size = 25 + + [[databases]] + name = "prod" + host = "10.0.0.1" + min_pool_size = 6 + ``` + + ```toml title="users.toml" + [[users]] + name = "postgres" + database = "prod" + pool_size = 12 + ``` + +### Supported settings + +The following configuration options are supported for pool size autoscaling: + +| Section | Configuration | +|-|-| +| [`[general]`](../../../configuration/pgdog.toml/general.md) | [`default_pool_size`](../../../configuration/pgdog.toml/general.md#default_pool_size) (alias: `max_pool_size`) | +| [`[general]`](../../../configuration/pgdog.toml/general.md) | [`min_pool_size`](../../../configuration/pgdog.toml/general.md#min_pool_size) | +| [`[[databases]]`](../../../configuration/pgdog.toml/databases.md) | [`pool_size`](../../../configuration/pgdog.toml/databases.md#pool_size) | +| [`[[databases]]`](../../../configuration/pgdog.toml/databases.md) | [`min_pool_size`](../../../configuration/pgdog.toml/databases.md#min_pool_size) | +| [`[[users]]`](../../../configuration/users.toml/users.md) | [`pool_size`](../../../configuration/users.toml/users.md#pool_size) | +| [`[[users]]`](../../../configuration/users.toml/users.md) | [`min_pool_size`](../../../configuration/users.toml/users.md#min_pool_size) | + +## Orchestrator integration + +Autoscaling actions are performed entirely using the internal PgDog <-> control plane protocol and, therefore, will work with all orchestrators, including Kubernetes, ECS, and manual deployments. + +### Kubernetes + +If using autoscaling and deploying PgDog with our [Helm chart](../../../installation.md), make sure to set the pool-related settings to reflect the _total_ number of connections. For example, if deploying 3 replicas and the total pool size across the 3 pods is 600 connections, set it accordingly in `values.yaml`: + +```yaml title="values.yaml" +defaultPoolSize: 600 +replicas: 3 + +users: + - name: "postgres" + database: "prod" + minPoolSize: 300 # 50% of the pool +``` + +When PgDog pods are started, they will connect to the control plane and automatically adjust the pool settings to reflect the total number of pods in the deployment: + +| Configuration | Value | Autoscaled value | +|-|-|-| +| `defaultPoolSize` | `600` | `200` | +| `minPoolSize` | `300` | `100` | + +!!! note "Automatic adjustment" + The configuration adjustment happens inside the PgDog process. The control plane does not + mutate the `ConfigMap` resource, so GitOps tools like ArgoCD will not detect this drift + and continue to operate normally. diff --git a/docs/enterprise_edition/control_plane/features/config.md b/docs/enterprise_edition/control_plane/features/config.md index e69de29b..e4b4256a 100644 --- a/docs/enterprise_edition/control_plane/features/config.md +++ b/docs/enterprise_edition/control_plane/features/config.md @@ -0,0 +1,3 @@ +--- +icon: material/cog +--- diff --git a/docs/enterprise_edition/control_plane/features/deployments.md b/docs/enterprise_edition/control_plane/features/deployments.md index e3f80186..7132b579 100644 --- a/docs/enterprise_edition/control_plane/features/deployments.md +++ b/docs/enterprise_edition/control_plane/features/deployments.md @@ -1,3 +1,7 @@ +--- +icon: material/rocket-launch-outline +--- + # Deployments The control plane is primarily useful for monitoring and managing PgDog deployments. To make this work, it integrates with the Kubernetes API (for service discovery) and with PgDog directly, via an internal protocol, to read telemetry and control its behavior. diff --git a/docs/enterprise_edition/control_plane/features/index.md b/docs/enterprise_edition/control_plane/features/index.md index 6775f2ee..0a4cca80 100644 --- a/docs/enterprise_edition/control_plane/features/index.md +++ b/docs/enterprise_edition/control_plane/features/index.md @@ -9,6 +9,7 @@ The control plane provides operational features for monitoring, configuring, and | Feature | Description | |-|-| | [Alerts](alerts.md) | Detect outliers in live PgDog metrics and send incidents to supported providers. | +| [Autoscaling](autoscaling.md) | Automatically resize connection pools when PgDog nodes are added or removed. | | [Configuration](config.md) | Manage PgDog configuration across connected instances. | | [Instances](instances.md) | View and manage PgDog instances connected to the control plane. | | [Metrics](metrics.md) | Inspect metrics reported by PgDog instances. | diff --git a/docs/enterprise_edition/control_plane/features/instances.md b/docs/enterprise_edition/control_plane/features/instances.md index e69de29b..26be5ca1 100644 --- a/docs/enterprise_edition/control_plane/features/instances.md +++ b/docs/enterprise_edition/control_plane/features/instances.md @@ -0,0 +1,3 @@ +--- +icon: material/server-network +--- diff --git a/docs/enterprise_edition/control_plane/features/metrics.md b/docs/enterprise_edition/control_plane/features/metrics.md index e69de29b..0b981da2 100644 --- a/docs/enterprise_edition/control_plane/features/metrics.md +++ b/docs/enterprise_edition/control_plane/features/metrics.md @@ -0,0 +1,3 @@ +--- +icon: material/chart-line +--- diff --git a/docs/enterprise_edition/control_plane/features/slack.md b/docs/enterprise_edition/control_plane/features/slack.md index 04cbcd52..23977afc 100644 --- a/docs/enterprise_edition/control_plane/features/slack.md +++ b/docs/enterprise_edition/control_plane/features/slack.md @@ -1,3 +1,7 @@ +--- +icon: material/slack +--- + # Slack integration The control plane can send notifications to a Slack channel. Notifications include changes to managed PgDog deployments, like Helm chart updates, configuration reloading, and updates to database topology. diff --git a/docs/enterprise_edition/control_plane/installation.md b/docs/enterprise_edition/control_plane/installation.md index 5c31d9ed..c0a59f48 100644 --- a/docs/enterprise_edition/control_plane/installation.md +++ b/docs/enterprise_edition/control_plane/installation.md @@ -15,7 +15,7 @@ helm install control pgdogdev-ee/pgdog-control The chart has a few external requirements, [documented below](#requirements). -## Guided install +## Dependencies While the chart creates and manages several resources, including an `Ingress`, some of them have external dependencies which cannot be created by Helm. @@ -31,9 +31,6 @@ The script requires that you have both the `awscli` and `kubectl` installed, whi !!! note "Read-only actions" The guided installation script is strictly **read-only** and will never make any modifications to your environment. - -## Requirements - Since the chart creates an `Ingress` resource for the web dashboard, an ingress controller is required to access the web dashboard. The chart supports four Ingress settings out of the box: | Ingress | Description | diff --git a/docs/images/ee/alerts.png b/docs/images/ee/alerts.png new file mode 100644 index 0000000000000000000000000000000000000000..5339c487f11225ebfd9abf1b30a234e307eb790e GIT binary patch literal 36312 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 YVX88++xKT94EPcekl-)i)$;nk0M9xX`~Uy| literal 0 HcmV?d00001 From 82e530d55dfb897fa73847f496d483516c158529 Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Mon, 22 Jun 2026 14:20:59 -0700 Subject: [PATCH 4/5] save --- docs/enterprise_edition/control_plane/features/alerts.md | 6 +++--- docs/enterprise_edition/control_plane/features/config.md | 3 --- .../control_plane/features/deployments.md | 7 ------- docs/enterprise_edition/control_plane/features/index.md | 3 --- .../enterprise_edition/control_plane/features/instances.md | 3 --- docs/enterprise_edition/control_plane/features/metrics.md | 3 --- docs/enterprise_edition/control_plane/features/slack.md | 4 ++-- docs/enterprise_edition/control_plane/installation.md | 2 +- 8 files changed, 6 insertions(+), 25 deletions(-) delete mode 100644 docs/enterprise_edition/control_plane/features/config.md delete mode 100644 docs/enterprise_edition/control_plane/features/deployments.md delete mode 100644 docs/enterprise_edition/control_plane/features/instances.md delete mode 100644 docs/enterprise_edition/control_plane/features/metrics.md diff --git a/docs/enterprise_edition/control_plane/features/alerts.md b/docs/enterprise_edition/control_plane/features/alerts.md index 5b1a9f71..7e61e886 100644 --- a/docs/enterprise_edition/control_plane/features/alerts.md +++ b/docs/enterprise_edition/control_plane/features/alerts.md @@ -4,12 +4,12 @@ icon: material/alert-circle-outline # Alerts -Since the control plane has access to real-time PgDog [metrics](metrics.md), it can detect outliers and trigger automatic alerts. +Since the control plane has access to real-time PgDog [metrics](../../../features/metrics.md), it can detect outliers and trigger automatic alerts. ## How it works The control plane evaluates the metrics it receives from all PgDog instances on a continuous loop. When they exceed pre-configured thresholds, an incident -is created using one of configured integrations. +is created using one of the configured integrations.
Alerts @@ -55,7 +55,7 @@ The following parameters are configurable via the [Helm chart](../installation.m | `clients_waiting` | Average number of clients waiting for a connection from a pool. | Clients, e.g., `10` | | `cpu` | Average CPU utilization of each PgDog pod. | Percentage, e.g., `90.0` (90%) | | `memory` | Average memory utilization of each PgDog pod. | MiB, e.g., `2048` (2048 MiB) | -| `server_connections` | Average Nnmber of open connections from PgDog to Postgres. | Connections, e.g., `100` | +| `server_connections` | Average number of open connections from PgDog to Postgres. | Connections, e.g., `100` | #### Evaluation window diff --git a/docs/enterprise_edition/control_plane/features/config.md b/docs/enterprise_edition/control_plane/features/config.md deleted file mode 100644 index e4b4256a..00000000 --- a/docs/enterprise_edition/control_plane/features/config.md +++ /dev/null @@ -1,3 +0,0 @@ ---- -icon: material/cog ---- diff --git a/docs/enterprise_edition/control_plane/features/deployments.md b/docs/enterprise_edition/control_plane/features/deployments.md deleted file mode 100644 index 7132b579..00000000 --- a/docs/enterprise_edition/control_plane/features/deployments.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -icon: material/rocket-launch-outline ---- - -# Deployments - -The control plane is primarily useful for monitoring and managing PgDog deployments. To make this work, it integrates with the Kubernetes API (for service discovery) and with PgDog directly, via an internal protocol, to read telemetry and control its behavior. diff --git a/docs/enterprise_edition/control_plane/features/index.md b/docs/enterprise_edition/control_plane/features/index.md index 0a4cca80..f33d33ed 100644 --- a/docs/enterprise_edition/control_plane/features/index.md +++ b/docs/enterprise_edition/control_plane/features/index.md @@ -10,7 +10,4 @@ The control plane provides operational features for monitoring, configuring, and |-|-| | [Alerts](alerts.md) | Detect outliers in live PgDog metrics and send incidents to supported providers. | | [Autoscaling](autoscaling.md) | Automatically resize connection pools when PgDog nodes are added or removed. | -| [Configuration](config.md) | Manage PgDog configuration across connected instances. | -| [Instances](instances.md) | View and manage PgDog instances connected to the control plane. | -| [Metrics](metrics.md) | Inspect metrics reported by PgDog instances. | | [Slack integration](slack.md) | Send deployment and configuration notifications to a Slack channel. | diff --git a/docs/enterprise_edition/control_plane/features/instances.md b/docs/enterprise_edition/control_plane/features/instances.md deleted file mode 100644 index 26be5ca1..00000000 --- a/docs/enterprise_edition/control_plane/features/instances.md +++ /dev/null @@ -1,3 +0,0 @@ ---- -icon: material/server-network ---- diff --git a/docs/enterprise_edition/control_plane/features/metrics.md b/docs/enterprise_edition/control_plane/features/metrics.md deleted file mode 100644 index 0b981da2..00000000 --- a/docs/enterprise_edition/control_plane/features/metrics.md +++ /dev/null @@ -1,3 +0,0 @@ ---- -icon: material/chart-line ---- diff --git a/docs/enterprise_edition/control_plane/features/slack.md b/docs/enterprise_edition/control_plane/features/slack.md index 23977afc..5e77da79 100644 --- a/docs/enterprise_edition/control_plane/features/slack.md +++ b/docs/enterprise_edition/control_plane/features/slack.md @@ -23,7 +23,7 @@ The following parameters can be configured via the [Helm chart](../installation. | Parameters | Description | |-|-| | `bot_token` | The Slack API bot token. | -| `channel` | The slack channel ID where the Slack bot is allowed to post messages. | +| `channel` | The Slack channel ID where the Slack bot is allowed to post messages. | ## Notifications @@ -32,5 +32,5 @@ If Slack integration is configured, the control plane will send the following no | Notification | Description | |-|-| | Helm install (start) | The control plane starts executing the `helm upgrade --install` command to modify/create a PgDog deployment. | -| Helm install (end) | The control plane is finished executing the `helm ugprade --install` command. If any errors occur, they are included in the notification. | +| Helm install (end) | The control plane is finished executing the `helm upgrade --install` command. If any errors occur, they are included in the notification. | | Configuration reload | The control plane triggers a configuration reload on all PgDog instances in a deployment. | diff --git a/docs/enterprise_edition/control_plane/installation.md b/docs/enterprise_edition/control_plane/installation.md index c0a59f48..51701643 100644 --- a/docs/enterprise_edition/control_plane/installation.md +++ b/docs/enterprise_edition/control_plane/installation.md @@ -46,7 +46,7 @@ If deploying the dashboard with access to the Internet, make sure to configure a ## Ingress -Most of the settings that need to be provided are around the Ingress and OAuth authentication. The [guided install](#guided-install) will configure them automatically. However, if you're installing manually, they are documented below: +Most of the settings that need to be provided are around the Ingress and OAuth authentication. The [guided install](#dependencies) will configure them automatically. However, if you're installing manually, they are documented below: | Setting | Description | Example | |-|-|-| From 790fde1984e154f38f515e31386b75bf3f8b7c71 Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Mon, 22 Jun 2026 14:25:30 -0700 Subject: [PATCH 5/5] speedup ci --- .github/workflows/ci.yaml | 26 +++++--------------------- tests/pgdog-docker.sh | 9 +++++++++ 2 files changed, 14 insertions(+), 21 deletions(-) create mode 100755 tests/pgdog-docker.sh diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index bd1e4227..f24b3ce9 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -8,30 +8,14 @@ jobs: verify-tomls: runs-on: blacksmith-4vcpu-ubuntu-2404 timeout-minutes: 30 + env: + PGDOG_IMAGE: ghcr.io/pgdogdev/pgdog-enterprise:main-ent steps: - name: Checkout code uses: actions/checkout@v4 - - name: Checkout pgdog-enterprise - uses: actions/checkout@v4 - with: - repository: pgdogdev/pgdog-enterprise - ref: main-ent - path: pgdog-source - token: ${{ secrets.PGDOG_ENTERPRISE_TOKEN }} - - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - override: true - - name: Install CMake 3.31 - run: | - sudo apt update && sudo apt install mold -y - sudo apt remove cmake - sudo pip3 install cmake==3.31.6 - cmake --version - - name: Build - run: cargo build - working-directory: pgdog-source + - name: Pull PgDog Enterprise image + run: docker pull "$PGDOG_IMAGE" - name: Install test dependencies run: sudo pip3 install -r tests/requirements.txt - name: Run tests - run: python3 tests/test_code_blocks.py pgdog-source/target/debug/pgdog + run: python3 tests/test_code_blocks.py tests/pgdog-docker.sh diff --git a/tests/pgdog-docker.sh b/tests/pgdog-docker.sh new file mode 100755 index 00000000..0cadfcd2 --- /dev/null +++ b/tests/pgdog-docker.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -eo pipefail + +PGDOG_IMAGE="${PGDOG_IMAGE:-ghcr.io/pgdogdev/pgdog-enterprise:main-ent}" + +docker run --rm \ + -v /tmp:/tmp \ + "$PGDOG_IMAGE" \ + /usr/local/bin/pgdog "$@"