Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 214 additions & 0 deletions .github/workflows/publish-coroot-checkpoint-hotfix.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
name: Publish Coroot Checkpoint Hotfix

on:
pull_request:
branches: [main]
paths:
- .github/workflows/publish-coroot-checkpoint-hotfix.yaml
- k8s/bases/infrastructure/coroot/coroot-v1.28.1-checkpoint-record.patch
- k8s/bases/infrastructure/coroot/CorootCheckpoint.Dockerfile
- k8s/bases/infrastructure/coroot/cluster-agent-v1.11.7-checkpoint-record.patch
- k8s/bases/infrastructure/coroot/CorootClusterAgentCheckpoint.Dockerfile
push:
branches: [main]
paths:
- .github/workflows/publish-coroot-checkpoint-hotfix.yaml
- k8s/bases/infrastructure/coroot/coroot-v1.28.1-checkpoint-record.patch
- k8s/bases/infrastructure/coroot/CorootCheckpoint.Dockerfile
- k8s/bases/infrastructure/coroot/cluster-agent-v1.11.7-checkpoint-record.patch
- k8s/bases/infrastructure/coroot/CorootClusterAgentCheckpoint.Dockerfile
workflow_dispatch:

permissions: {}

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false

jobs:
verify:
name: Verify ${{ matrix.component }}
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- component: server
repository: coroot/coroot
source: 15137ef2f43e01d0a87245e44b937b25515e0afe
patch: coroot-v1.28.1-checkpoint-record.patch
dockerfile: CorootCheckpoint.Dockerfile
image: platform-coroot
version: v1.28.1-checkpoints.1
- component: collector
repository: coroot/coroot-cluster-agent
source: 4291458563fa8ea55615e23e0f11412db79742b6
patch: cluster-agent-v1.11.7-checkpoint-record.patch
dockerfile: CorootClusterAgentCheckpoint.Dockerfile
image: platform-coroot-cluster-agent
version: v1.11.7-checkpoints.1
env:
IMAGE: ghcr.io/devantler-tech/${{ matrix.image }}
IMAGE_TAG: ${{ matrix.version }}-${{ github.sha }}
steps:
- name: Harden runner
uses: step-security/harden-runner@dc2769abcc0fcfbadfc1df54081c1608579ef6b2 # v2.22.2
with:
egress-policy: audit

- name: Check out platform contract
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Check out exact upstream release source
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: ${{ matrix.repository }}
ref: ${{ matrix.source }}
path: upstream
persist-credentials: false

- name: Apply reviewed release patch
working-directory: upstream
env:
EXPECTED_SOURCE_COMMIT: ${{ matrix.source }}
HOTFIX_PATCH: ${{ github.workspace }}/k8s/bases/infrastructure/coroot/${{ matrix.patch }}
run: |
set -euo pipefail
test "$(git rev-parse HEAD)" = "${EXPECTED_SOURCE_COMMIT}"
git apply --check "${HOTFIX_PATCH}"
git apply "${HOTFIX_PATCH}"
git diff --check

- name: Set up Buildx container driver
uses: docker/setup-buildx-action@594f3bf4285d9ea8dc53c9a0c9c4092420091003 # v4.4.0
with:
driver: docker-container

- name: Build without publishing tested release image
id: build
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
context: ./upstream
file: ./k8s/bases/infrastructure/coroot/${{ matrix.dockerfile }}
platforms: linux/amd64
push: false
tags: ${{ env.IMAGE }}:${{ env.IMAGE_TAG }}
build-args: VERSION=${{ env.IMAGE_TAG }}
provenance: mode=max
sbom: true
labels: |
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.version=${{ env.IMAGE_TAG }}
io.devantler.coroot-checkpoint.upstream-revision=${{ matrix.source }}

publish:
name: Publish and sign ${{ matrix.component }}
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs: verify
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write
strategy:
fail-fast: false
matrix:
include:
- component: server
repository: coroot/coroot
source: 15137ef2f43e01d0a87245e44b937b25515e0afe
patch: coroot-v1.28.1-checkpoint-record.patch
dockerfile: CorootCheckpoint.Dockerfile
image: platform-coroot
version: v1.28.1-checkpoints.1
- component: collector
repository: coroot/coroot-cluster-agent
source: 4291458563fa8ea55615e23e0f11412db79742b6
patch: cluster-agent-v1.11.7-checkpoint-record.patch
dockerfile: CorootClusterAgentCheckpoint.Dockerfile
image: platform-coroot-cluster-agent
version: v1.11.7-checkpoints.1
env:
IMAGE: ghcr.io/devantler-tech/${{ matrix.image }}
IMAGE_TAG: ${{ matrix.version }}-${{ github.sha }}
steps:
- name: Harden runner
uses: step-security/harden-runner@dc2769abcc0fcfbadfc1df54081c1608579ef6b2 # v2.22.2
with:
egress-policy: audit

- name: Check out platform contract
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Check out exact upstream release source
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: ${{ matrix.repository }}
ref: ${{ matrix.source }}
path: upstream
persist-credentials: false

- name: Apply reviewed release patch
working-directory: upstream
env:
EXPECTED_SOURCE_COMMIT: ${{ matrix.source }}
HOTFIX_PATCH: ${{ github.workspace }}/k8s/bases/infrastructure/coroot/${{ matrix.patch }}
run: |
set -euo pipefail
test "$(git rev-parse HEAD)" = "${EXPECTED_SOURCE_COMMIT}"
git apply --check "${HOTFIX_PATCH}"
git apply "${HOTFIX_PATCH}"
git diff --check

- name: Set up Buildx container driver
uses: docker/setup-buildx-action@594f3bf4285d9ea8dc53c9a0c9c4092420091003 # v4.4.0
with:
driver: docker-container

- name: Log in to GHCR
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push tested release image
id: build
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
context: ./upstream
file: ./k8s/bases/infrastructure/coroot/${{ matrix.dockerfile }}
platforms: linux/amd64
push: true
tags: ${{ env.IMAGE }}:${{ env.IMAGE_TAG }}
build-args: VERSION=${{ env.IMAGE_TAG }}
provenance: mode=max
sbom: true
labels: |
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.version=${{ env.IMAGE_TAG }}
io.devantler.coroot-checkpoint.upstream-revision=${{ matrix.source }}

- name: Install checksum-verified supply-chain tools
run: bash .github/scripts/setup-supply-chain-tools.sh

- name: Sign and verify published digest
env:
DIGEST: ${{ steps.build.outputs.digest }}
run: |
set -euo pipefail
test -n "${DIGEST}"
cosign sign --yes "${IMAGE}@${DIGEST}"
cosign verify \
--certificate-identity "https://github.com/devantler-tech/platform/.github/workflows/publish-coroot-checkpoint-hotfix.yaml@refs/heads/main" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
"${IMAGE}@${DIGEST}"
printf 'Published signed image: %s@%s\n' "${IMAGE}" "${DIGEST}"
21 changes: 21 additions & 0 deletions k8s/bases/infrastructure/coroot/CorootCheckpoint.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
FROM docker.io/library/node:24-bookworm@sha256:f9b3548b20b15b705b66aeecaeac7dd690c73d5e4661357aac02e60e3d38c88a AS frontend
WORKDIR /src/front
COPY front/package.json front/package-lock.json ./
RUN npm ci
COPY front/ ./
RUN npm run build-prod

FROM docker.io/library/golang:1.27.3-bookworm@sha256:fea12ba16096adec0f699ce1c4da2154d320450e56c1f63671f95d2a3551c77b AS builder
RUN apt-get update && apt-get install --yes --no-install-recommends liblz4-dev && rm -rf /var/lib/apt/lists/*
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
COPY --from=frontend /src/static ./static
RUN go test ./...
ARG VERSION=unknown
RUN go build -mod=readonly -ldflags "-X main.version=$VERSION" -o /out/coroot .

FROM ghcr.io/coroot/coroot:1.28.1@sha256:1b908030e1cce068ce6fb907cd02c41552e27aab382e61f1bbb523ceb50a0913
COPY --from=builder --chmod=0755 /out/coroot /usr/bin/coroot
RUN ["/usr/bin/coroot", "--help"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM docker.io/library/golang:1.27.3-bookworm@sha256:fea12ba16096adec0f699ce1c4da2154d320450e56c1f63671f95d2a3551c77b AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go test ./...
ARG VERSION=unknown
RUN go build -mod=readonly -ldflags "-X main.version=$VERSION" -o /out/coroot-cluster-agent .

FROM ghcr.io/coroot/coroot-cluster-agent:1.11.7@sha256:851015f822ca6c8b2934ef98c6a20312a1ea9823045737ac3cdd141efc63d7a8
COPY --from=builder --chmod=0755 /out/coroot-cluster-agent /usr/bin/coroot-cluster-agent
RUN ["/usr/bin/coroot-cluster-agent", "--help"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
diff --git a/metrics/postgres/collector.go b/metrics/postgres/collector.go
index db1f1da..d94c33d 100644
--- a/metrics/postgres/collector.go
+++ b/metrics/postgres/collector.go
@@ -52,21 +52,22 @@ var (
dWalReceiveLsn = desc("pg_wal_receive_lsn", "WAL sequence number that has been received and synced to disk by streaming replication")
dWalReplyLsn = desc("pg_wal_reply_lsn", "WAL sequence number that has been replayed during recovery")

- dCheckpointsScheduled = desc("pg_checkpoints_scheduled_total", "Number of scheduled checkpoints, including skipped ones", "type")
- dCheckpoints = desc("pg_checkpoints_total", "Number of checkpoints that have been completed")
- dRestartpoints = desc("pg_restartpoints_total", "Number of restartpoints that have been completed on a standby")
- dBuffersWritten = desc("pg_buffers_written_total", "Total number of dirty buffers flushed to disk", "source")
- dTimeSinceLastCheckpoint = desc("pg_time_since_last_checkpoint_seconds", "Seconds since the last checkpoint observed by the agent")
- dWalSinceLastCheckpoint = desc("pg_wal_since_last_checkpoint_bytes", "Amount of WAL written since the last completed checkpoint (to be replayed in the case of a crash)")
- dWalSize = desc("pg_wal_size_bytes", "Size of the WAL directory")
- dReplicationSlotRetained = desc("pg_replication_slot_retained_wal_bytes", "Amount of WAL retained for the replication slot", "slot", "active", "wal_status")
- dXidAge = desc("pg_xid_age", "Transactions since the oldest unfrozen transaction ID (age of datfrozenxid)", "db")
- dMultixactAge = desc("pg_multixact_age", "Multixacts since the oldest unfrozen multixact ID (age of datminmxid)", "db")
- dOldestXminAge = desc("pg_oldest_xmin_age", "Age, in transactions, of the oldest transaction ID held back from freezing, by holder", "holder")
- dTransactionSeconds = desc("pg_transaction_seconds", "Age of the longest-running transaction, by query", "db", "user", "query")
- dWalArchivedSegments = desc("pg_wal_archived_segments_total", "Number of WAL files successfully archived")
- dWalArchiveFailures = desc("pg_wal_archive_failures_total", "Number of failed attempts to archive WAL files")
- dWalArchivingStatus = desc("pg_wal_archiving_status", "1 if the last WAL archive attempt succeeded, 0 if it failed")
+ dCheckpointsScheduled = desc("pg_checkpoints_scheduled_total", "Number of scheduled checkpoints, including skipped ones", "type")
+ dCheckpoints = desc("pg_checkpoints_total", "Number of checkpoints that have been completed")
+ dRestartpoints = desc("pg_restartpoints_total", "Number of restartpoints that have been completed on a standby")
+ dBuffersWritten = desc("pg_buffers_written_total", "Total number of dirty buffers flushed to disk", "source")
+ dTimeSinceLastCheckpoint = desc("pg_time_since_last_checkpoint_seconds", "Seconds since the last checkpoint observed by the agent")
+ dWalSinceLastCheckpoint = desc("pg_wal_since_last_checkpoint_bytes", "Amount of WAL written since the last completed checkpoint (to be replayed in the case of a crash)")
+ dWalSinceLastCheckpointRecord = desc("pg_wal_since_last_checkpoint_record_bytes", "Amount of WAL inserted or replayed after the last completed checkpoint or restartpoint record")
+ dWalSize = desc("pg_wal_size_bytes", "Size of the WAL directory")
+ dReplicationSlotRetained = desc("pg_replication_slot_retained_wal_bytes", "Amount of WAL retained for the replication slot", "slot", "active", "wal_status")
+ dXidAge = desc("pg_xid_age", "Transactions since the oldest unfrozen transaction ID (age of datfrozenxid)", "db")
+ dMultixactAge = desc("pg_multixact_age", "Multixacts since the oldest unfrozen multixact ID (age of datminmxid)", "db")
+ dOldestXminAge = desc("pg_oldest_xmin_age", "Age, in transactions, of the oldest transaction ID held back from freezing, by holder", "holder")
+ dTransactionSeconds = desc("pg_transaction_seconds", "Age of the longest-running transaction, by query", "db", "user", "query")
+ dWalArchivedSegments = desc("pg_wal_archived_segments_total", "Number of WAL files successfully archived")
+ dWalArchiveFailures = desc("pg_wal_archive_failures_total", "Number of failed attempts to archive WAL files")
+ dWalArchivingStatus = desc("pg_wal_archiving_status", "1 if the last WAL archive attempt succeeded, 0 if it failed")

dDbSize = desc("pg_database_size_bytes", "Total size of the database in bytes", "db")
dTableSize = desc("pg_table_size_bytes", "Total size of the table in bytes including indexes and TOAST", "db", "schema", "table")
@@ -139,6 +140,7 @@ type Collector struct {
cpRestartsDone float64
cpBuffers float64
cpWalBytes sql.Null[float64]
+ cpWalAfterRecord sql.Null[float64]
lastCheckpointAt time.Time

walSize sql.Null[float64]
@@ -582,6 +584,9 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) {
if c.cpWalBytes.Valid {
ch <- gauge(dWalSinceLastCheckpoint, c.cpWalBytes.V)
}
+ if c.cpWalAfterRecord.Valid {
+ ch <- gauge(dWalSinceLastCheckpointRecord, c.cpWalAfterRecord.V)
+ }
if c.walSize.Valid {
ch <- gauge(dWalSize, c.walSize.V)
}
@@ -645,6 +650,7 @@ func (c *Collector) Describe(ch chan<- *prometheus.Desc) {
ch <- dBuffersWritten
ch <- dTimeSinceLastCheckpoint
ch <- dWalSinceLastCheckpoint
+ ch <- dWalSinceLastCheckpointRecord
ch <- dWalSize
ch <- dReplicationSlotRetained
ch <- dWalArchivedSegments
diff --git a/metrics/postgres/pg_checkpointer.go b/metrics/postgres/pg_checkpointer.go
index aec0470..af1dc0d 100644
--- a/metrics/postgres/pg_checkpointer.go
+++ b/metrics/postgres/pg_checkpointer.go
@@ -46,9 +46,12 @@ func (c *Collector) getCheckpointStats(ctx context.Context, version semver.Versi
return err
}
if err := c.db.QueryRowContext(ctx,
- `SELECT pg_wal_lsn_diff(CASE WHEN pg_is_in_recovery() THEN pg_last_wal_replay_lsn() ELSE pg_current_wal_lsn() END, redo_lsn) FROM pg_control_checkpoint()`,
- ).Scan(&c.cpWalBytes); err != nil {
+ `SELECT pg_wal_lsn_diff(lsn, redo_lsn), pg_wal_lsn_diff(lsn, checkpoint_lsn)
+ FROM pg_control_checkpoint(),
+ (SELECT CASE WHEN pg_is_in_recovery() THEN pg_last_wal_replay_lsn() ELSE pg_current_wal_lsn() END AS lsn) wal`,
+ ).Scan(&c.cpWalBytes, &c.cpWalAfterRecord); err != nil {
c.cpWalBytes = sql.Null[float64]{}
+ c.cpWalAfterRecord = sql.Null[float64]{}
c.logger.Warning(err)
}
if c.cpPrev != nil {
Loading
Loading