mirror of
https://github.com/neondatabase/neon.git
synced 2026-05-23 16:10:37 +00:00
Compare commits
3 Commits
problame/s
...
devin/1742
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8edf6d326c | ||
|
|
1cae803c28 | ||
|
|
4360e0d4c7 |
12
.github/workflows/_benchmarking_preparation.yml
vendored
12
.github/workflows/_benchmarking_preparation.yml
vendored
@@ -8,9 +8,6 @@ defaults:
|
||||
run:
|
||||
shell: bash -euxo pipefail {0}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
setup-databases:
|
||||
permissions:
|
||||
@@ -37,11 +34,6 @@ jobs:
|
||||
options: --init
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Set up Connection String
|
||||
id: set-up-prep-connstr
|
||||
run: |
|
||||
@@ -66,10 +58,10 @@ jobs:
|
||||
|
||||
echo "connstr=${CONNSTR}" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: eu-central-1
|
||||
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||
|
||||
27
.github/workflows/_build-and-test-locally.yml
vendored
27
.github/workflows/_build-and-test-locally.yml
vendored
@@ -37,9 +37,6 @@ env:
|
||||
RUST_BACKTRACE: 1
|
||||
COPT: '-Werror'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build-neon:
|
||||
runs-on: ${{ fromJSON(format('["self-hosted", "{0}"]', inputs.arch == 'arm64' && 'large-arm64' || 'large')) }}
|
||||
@@ -62,12 +59,7 @@ jobs:
|
||||
BUILD_TAG: ${{ inputs.build-tag }}
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@@ -128,28 +120,28 @@ jobs:
|
||||
|
||||
- name: Cache postgres v14 build
|
||||
id: cache_pg_14
|
||||
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: pg_install/v14
|
||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ inputs.build-type }}-pg-${{ steps.pg_v14_rev.outputs.pg_rev }}-bookworm-${{ hashFiles('Makefile', 'build-tools.Dockerfile') }}
|
||||
|
||||
- name: Cache postgres v15 build
|
||||
id: cache_pg_15
|
||||
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: pg_install/v15
|
||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ inputs.build-type }}-pg-${{ steps.pg_v15_rev.outputs.pg_rev }}-bookworm-${{ hashFiles('Makefile', 'build-tools.Dockerfile') }}
|
||||
|
||||
- name: Cache postgres v16 build
|
||||
id: cache_pg_16
|
||||
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: pg_install/v16
|
||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ inputs.build-type }}-pg-${{ steps.pg_v16_rev.outputs.pg_rev }}-bookworm-${{ hashFiles('Makefile', 'build-tools.Dockerfile') }}
|
||||
|
||||
- name: Cache postgres v17 build
|
||||
id: cache_pg_17
|
||||
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: pg_install/v17
|
||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ inputs.build-type }}-pg-${{ steps.pg_v17_rev.outputs.pg_rev }}-bookworm-${{ hashFiles('Makefile', 'build-tools.Dockerfile') }}
|
||||
@@ -229,7 +221,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: eu-central-1
|
||||
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||
@@ -338,12 +330,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJSON(format('{{"include":{0}}}', inputs.test-cfg)) }}
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
|
||||
12
.github/workflows/_check-codestyle-python.yml
vendored
12
.github/workflows/_check-codestyle-python.yml
vendored
@@ -12,9 +12,6 @@ defaults:
|
||||
run:
|
||||
shell: bash -euxo pipefail {0}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
check-codestyle-python:
|
||||
runs-on: [ self-hosted, small ]
|
||||
@@ -30,14 +27,9 @@ jobs:
|
||||
options: --init
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pypoetry/virtualenvs
|
||||
key: v2-${{ runner.os }}-${{ runner.arch }}-python-deps-bookworm-${{ hashFiles('poetry.lock') }}
|
||||
|
||||
9
.github/workflows/_check-codestyle-rust.yml
vendored
9
.github/workflows/_check-codestyle-rust.yml
vendored
@@ -37,18 +37,13 @@ jobs:
|
||||
options: --init
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Cache cargo deps
|
||||
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
|
||||
10
.github/workflows/_create-release-pr.yml
vendored
10
.github/workflows/_create-release-pr.yml
vendored
@@ -20,9 +20,6 @@ defaults:
|
||||
run:
|
||||
shell: bash -euo pipefail {0}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
create-release-branch:
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -31,12 +28,7 @@ jobs:
|
||||
contents: write # for `git push`
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.source-branch }}
|
||||
fetch-depth: 0
|
||||
|
||||
36
.github/workflows/_meta.yml
vendored
36
.github/workflows/_meta.yml
vendored
@@ -9,9 +9,6 @@ on:
|
||||
build-tag:
|
||||
description: "Tag for the current workflow run"
|
||||
value: ${{ jobs.tags.outputs.build-tag }}
|
||||
release-tag:
|
||||
description: "Tag for the release if this is an RC PR run"
|
||||
value: ${{ jobs.tags.outputs.release-tag }}
|
||||
previous-storage-release:
|
||||
description: "Tag of the last storage release"
|
||||
value: ${{ jobs.tags.outputs.storage }}
|
||||
@@ -38,8 +35,7 @@ jobs:
|
||||
tags:
|
||||
runs-on: ubuntu-22.04
|
||||
outputs:
|
||||
build-tag: ${{ steps.build-tag.outputs.build-tag }}
|
||||
release-tag: ${{ steps.build-tag.outputs.release-tag }}
|
||||
build-tag: ${{ steps.build-tag.outputs.tag }}
|
||||
compute: ${{ steps.previous-releases.outputs.compute }}
|
||||
proxy: ${{ steps.previous-releases.outputs.proxy }}
|
||||
storage: ${{ steps.previous-releases.outputs.storage }}
|
||||
@@ -49,12 +45,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
# Need `fetch-depth: 0` to count the number of commits in the branch
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -88,16 +79,16 @@ jobs:
|
||||
run: |
|
||||
case $RUN_KIND in
|
||||
push-main)
|
||||
echo "build-tag=$(git rev-list --count HEAD)" | tee -a $GITHUB_OUTPUT
|
||||
echo "tag=$(git rev-list --count HEAD)" | tee -a $GITHUB_OUTPUT
|
||||
;;
|
||||
storage-release)
|
||||
echo "build-tag=release-$(git rev-list --count HEAD)" | tee -a $GITHUB_OUTPUT
|
||||
echo "tag=release-$(git rev-list --count HEAD)" | tee -a $GITHUB_OUTPUT
|
||||
;;
|
||||
proxy-release)
|
||||
echo "build-tag=release-proxy-$(git rev-list --count HEAD)" | tee -a $GITHUB_OUTPUT
|
||||
echo "tag=release-proxy-$(git rev-list --count HEAD)" | tee -a $GITHUB_OUTPUT
|
||||
;;
|
||||
compute-release)
|
||||
echo "build-tag=release-compute-$(git rev-list --count HEAD)" | tee -a $GITHUB_OUTPUT
|
||||
echo "tag=release-compute-$(git rev-list --count HEAD)" | tee -a $GITHUB_OUTPUT
|
||||
;;
|
||||
pr|storage-rc-pr|compute-rc-pr|proxy-rc-pr)
|
||||
BUILD_AND_TEST_RUN_ID=$(gh api --paginate \
|
||||
@@ -105,21 +96,10 @@ jobs:
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"/repos/${GITHUB_REPOSITORY}/actions/runs?head_sha=${CURRENT_SHA}&branch=${CURRENT_BRANCH}" \
|
||||
| jq '[.workflow_runs[] | select(.name == "Build and Test")][0].id // ("Error: No matching workflow run found." | halt_error(1))')
|
||||
echo "build-tag=$BUILD_AND_TEST_RUN_ID" | tee -a $GITHUB_OUTPUT
|
||||
case $RUN_KIND in
|
||||
storage-rc-pr)
|
||||
echo "release-tag=release-$(git rev-list --count HEAD)" | tee -a $GITHUB_OUTPUT
|
||||
;;
|
||||
proxy-rc-pr)
|
||||
echo "release-tag=release-proxy-$(git rev-list --count HEAD)" | tee -a $GITHUB_OUTPUT
|
||||
;;
|
||||
compute-rc-pr)
|
||||
echo "release-tag=release-compute-$(git rev-list --count HEAD)" | tee -a $GITHUB_OUTPUT
|
||||
;;
|
||||
esac
|
||||
echo "tag=$BUILD_AND_TEST_RUN_ID" | tee -a $GITHUB_OUTPUT
|
||||
;;
|
||||
workflow-dispatch)
|
||||
echo "build-tag=$GITHUB_RUN_ID" | tee -a $GITHUB_OUTPUT
|
||||
echo "tag=$GITHUB_RUN_ID" | tee -a $GITHUB_OUTPUT
|
||||
;;
|
||||
*)
|
||||
echo "Unexpected RUN_KIND ('${RUN_KIND}'), failing to assign build-tag!"
|
||||
|
||||
@@ -49,12 +49,7 @@ jobs:
|
||||
id-token: write # Required for aws/azure login
|
||||
packages: write # required for pushing to GHCR
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: .github/scripts/push_with_image_map.py
|
||||
sparse-checkout-cone-mode: false
|
||||
@@ -64,7 +59,7 @@ jobs:
|
||||
|
||||
- name: Configure AWS credentials
|
||||
if: contains(inputs.image-map, 'amazonaws.com/')
|
||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: "${{ inputs.aws-region }}"
|
||||
role-to-assume: "arn:aws:iam::${{ inputs.aws-account-id }}:role/${{ inputs.aws-role-to-assume }}"
|
||||
@@ -72,7 +67,7 @@ jobs:
|
||||
|
||||
- name: Login to ECR
|
||||
if: contains(inputs.image-map, 'amazonaws.com/')
|
||||
uses: aws-actions/amazon-ecr-login@062b18b96a7aff071d4dc91bc00c4c1a7945b076 # v2.0.1
|
||||
uses: aws-actions/amazon-ecr-login@v2
|
||||
with:
|
||||
registries: "${{ inputs.aws-account-id }}"
|
||||
|
||||
@@ -91,14 +86,14 @@ jobs:
|
||||
|
||||
- name: Login to GHCR
|
||||
if: contains(inputs.image-map, 'ghcr.io/')
|
||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.NEON_DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.NEON_DOCKERHUB_PASSWORD }}
|
||||
|
||||
9
.github/workflows/actionlint.yml
vendored
9
.github/workflows/actionlint.yml
vendored
@@ -26,13 +26,8 @@ jobs:
|
||||
needs: [ check-permissions ]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: reviewdog/action-actionlint@a5524e1c19e62881d79c1f1b9b6f09f16356e281 # v1.65.2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: reviewdog/action-actionlint@v1
|
||||
env:
|
||||
# SC2046 - Quote this to prevent word splitting. - https://www.shellcheck.net/wiki/SC2046
|
||||
# SC2086 - Double quote to prevent globbing and word splitting. - https://www.shellcheck.net/wiki/SC2086
|
||||
|
||||
17
.github/workflows/approved-for-ci-run.yml
vendored
17
.github/workflows/approved-for-ci-run.yml
vendored
@@ -47,11 +47,6 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- run: gh pr --repo "${GITHUB_REPOSITORY}" edit "${PR_NUMBER}" --remove-label "approved-for-ci-run"
|
||||
|
||||
create-or-update-pr-for-ci-run:
|
||||
@@ -68,14 +63,9 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- run: gh pr --repo "${GITHUB_REPOSITORY}" edit "${PR_NUMBER}" --remove-label "approved-for-ci-run"
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
token: ${{ secrets.CI_ACCESS_TOKEN }}
|
||||
@@ -163,11 +153,6 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Close PR and delete `ci-run/pr-${{ env.PR_NUMBER }}` branch
|
||||
run: |
|
||||
CLOSED="$(gh pr --repo ${GITHUB_REPOSITORY} list --head ${BRANCH} --json 'closed' --jq '.[].closed')"
|
||||
|
||||
91
.github/workflows/benchmarking.yml
vendored
91
.github/workflows/benchmarking.yml
vendored
@@ -94,15 +94,10 @@ jobs:
|
||||
options: --init
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Configure AWS credentials # necessary on Azure runners
|
||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: eu-central-1
|
||||
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||
@@ -169,7 +164,7 @@ jobs:
|
||||
|
||||
- name: Post to a Slack channel
|
||||
if: ${{ github.event.schedule && failure() }}
|
||||
uses: slackapi/slack-github-action@fcfb566f8b0aab22203f066d80ca1d7e4b5d05b3 # v1.27.1
|
||||
uses: slackapi/slack-github-action@v1
|
||||
with:
|
||||
channel-id: "C06KHQVQ7U3" # on-call-qa-staging-stream
|
||||
slack-message: |
|
||||
@@ -202,15 +197,10 @@ jobs:
|
||||
options: --init
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: eu-central-1
|
||||
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||
@@ -262,15 +252,10 @@ jobs:
|
||||
options: --init
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: eu-central-1
|
||||
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||
@@ -329,7 +314,7 @@ jobs:
|
||||
# Post both success and failure to the Slack channel
|
||||
- name: Post to a Slack channel
|
||||
if: ${{ github.event.schedule && !cancelled() }}
|
||||
uses: slackapi/slack-github-action@fcfb566f8b0aab22203f066d80ca1d7e4b5d05b3 # v1.27.1
|
||||
uses: slackapi/slack-github-action@v1
|
||||
with:
|
||||
channel-id: "C06T9AMNDQQ" # on-call-compute-staging-stream
|
||||
slack-message: |
|
||||
@@ -361,11 +346,6 @@ jobs:
|
||||
tpch-compare-matrix: ${{ steps.tpch-compare-matrix.outputs.matrix }}
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Generate matrix for pgbench benchmark
|
||||
id: pgbench-compare-matrix
|
||||
run: |
|
||||
@@ -485,15 +465,10 @@ jobs:
|
||||
timeout-minutes: 480
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: eu-central-1
|
||||
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||
@@ -625,7 +600,7 @@ jobs:
|
||||
|
||||
- name: Post to a Slack channel
|
||||
if: ${{ github.event.schedule && failure() }}
|
||||
uses: slackapi/slack-github-action@fcfb566f8b0aab22203f066d80ca1d7e4b5d05b3 # v1.27.1
|
||||
uses: slackapi/slack-github-action@v1
|
||||
with:
|
||||
channel-id: "C06KHQVQ7U3" # on-call-qa-staging-stream
|
||||
slack-message: |
|
||||
@@ -674,15 +649,10 @@ jobs:
|
||||
options: --init
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: eu-central-1
|
||||
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||
@@ -756,7 +726,7 @@ jobs:
|
||||
|
||||
- name: Post to a Slack channel
|
||||
if: ${{ github.event.schedule && failure() }}
|
||||
uses: slackapi/slack-github-action@fcfb566f8b0aab22203f066d80ca1d7e4b5d05b3 # v1.27.1
|
||||
uses: slackapi/slack-github-action@v1
|
||||
with:
|
||||
channel-id: "C06KHQVQ7U3" # on-call-qa-staging-stream
|
||||
slack-message: |
|
||||
@@ -808,15 +778,10 @@ jobs:
|
||||
timeout-minutes: 720
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: eu-central-1
|
||||
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||
@@ -889,7 +854,7 @@ jobs:
|
||||
|
||||
- name: Post to a Slack channel
|
||||
if: ${{ github.event.schedule && failure() }}
|
||||
uses: slackapi/slack-github-action@fcfb566f8b0aab22203f066d80ca1d7e4b5d05b3 # v1.27.1
|
||||
uses: slackapi/slack-github-action@v1
|
||||
with:
|
||||
channel-id: "C06KHQVQ7U3" # on-call-qa-staging-stream
|
||||
slack-message: |
|
||||
@@ -934,15 +899,10 @@ jobs:
|
||||
options: --init
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: eu-central-1
|
||||
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||
@@ -1019,7 +979,7 @@ jobs:
|
||||
|
||||
- name: Post to a Slack channel
|
||||
if: ${{ github.event.schedule && failure() }}
|
||||
uses: slackapi/slack-github-action@fcfb566f8b0aab22203f066d80ca1d7e4b5d05b3 # v1.27.1
|
||||
uses: slackapi/slack-github-action@v1
|
||||
with:
|
||||
channel-id: "C06KHQVQ7U3" # on-call-qa-staging-stream
|
||||
slack-message: |
|
||||
@@ -1058,15 +1018,10 @@ jobs:
|
||||
options: --init
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: eu-central-1
|
||||
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||
@@ -1136,7 +1091,7 @@ jobs:
|
||||
|
||||
- name: Post to a Slack channel
|
||||
if: ${{ github.event.schedule && failure() }}
|
||||
uses: slackapi/slack-github-action@fcfb566f8b0aab22203f066d80ca1d7e4b5d05b3 # v1.27.1
|
||||
uses: slackapi/slack-github-action@v1
|
||||
with:
|
||||
channel-id: "C06KHQVQ7U3" # on-call-qa-staging-stream
|
||||
slack-message: |
|
||||
|
||||
35
.github/workflows/build-build-tools-image.yml
vendored
35
.github/workflows/build-build-tools-image.yml
vendored
@@ -53,14 +53,9 @@ jobs:
|
||||
packages: read
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -113,36 +108,31 @@ jobs:
|
||||
runs-on: ${{ fromJSON(format('["self-hosted", "{0}"]', matrix.arch == 'arm64' && 'large-arm64' || 'large')) }}
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: neondatabase/dev-actions/set-docker-config-dir@6094485bf440001c94a94a3f9e221e81ff6b6193
|
||||
- uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
cache-binary: false
|
||||
|
||||
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.NEON_DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.NEON_DOCKERHUB_PASSWORD }}
|
||||
|
||||
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: cache.neon.build
|
||||
username: ${{ secrets.NEON_CI_DOCKERCACHE_USERNAME }}
|
||||
password: ${{ secrets.NEON_CI_DOCKERCACHE_PASSWORD }}
|
||||
|
||||
- uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
|
||||
- uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: build-tools.Dockerfile
|
||||
context: .
|
||||
@@ -164,17 +154,12 @@ jobs:
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.NEON_DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.NEON_DOCKERHUB_PASSWORD }}
|
||||
|
||||
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
|
||||
42
.github/workflows/build-macos.yml
vendored
42
.github/workflows/build-macos.yml
vendored
@@ -28,9 +28,6 @@ env:
|
||||
# - You can connect up to four levels of workflows
|
||||
# - You can call a maximum of 20 unique reusable workflows from a single workflow file.
|
||||
# https://docs.github.com/en/actions/sharing-automations/reusing-workflows#limitations
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build-pgxn:
|
||||
if: |
|
||||
@@ -49,13 +46,8 @@ jobs:
|
||||
# Hence keeping target/ (and general cache size) smaller
|
||||
BUILD_TYPE: release
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout main repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set pg ${{ matrix.postgres-version }} for caching
|
||||
id: pg_rev
|
||||
@@ -63,7 +55,7 @@ jobs:
|
||||
|
||||
- name: Cache postgres ${{ matrix.postgres-version }} build
|
||||
id: cache_pg
|
||||
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: pg_install/${{ matrix.postgres-version }}
|
||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ env.BUILD_TYPE }}-pg-${{ matrix.postgres-version }}-${{ steps.pg_rev.outputs.pg_rev }}-${{ hashFiles('Makefile') }}
|
||||
@@ -115,13 +107,8 @@ jobs:
|
||||
# Hence keeping target/ (and general cache size) smaller
|
||||
BUILD_TYPE: release
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout main repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set pg v17 for caching
|
||||
id: pg_rev
|
||||
@@ -129,14 +116,14 @@ jobs:
|
||||
|
||||
- name: Cache postgres v17 build
|
||||
id: cache_pg
|
||||
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: pg_install/v17
|
||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ env.BUILD_TYPE }}-pg-v17-${{ steps.pg_rev.outputs.pg_rev }}-${{ hashFiles('Makefile') }}
|
||||
|
||||
- name: Cache walproposer-lib
|
||||
id: cache_walproposer_lib
|
||||
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: pg_install/build/walproposer-lib
|
||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ env.BUILD_TYPE }}-walproposer_lib-v17-${{ steps.pg_rev.outputs.pg_rev }}-${{ hashFiles('Makefile') }}
|
||||
@@ -178,13 +165,8 @@ jobs:
|
||||
# Hence keeping target/ (and general cache size) smaller
|
||||
BUILD_TYPE: release
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout main repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@@ -203,31 +185,31 @@ jobs:
|
||||
|
||||
- name: Cache postgres v14 build
|
||||
id: cache_pg
|
||||
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: pg_install/v14
|
||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ env.BUILD_TYPE }}-pg-v14-${{ steps.pg_rev_v14.outputs.pg_rev }}-${{ hashFiles('Makefile') }}
|
||||
- name: Cache postgres v15 build
|
||||
id: cache_pg_v15
|
||||
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: pg_install/v15
|
||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ env.BUILD_TYPE }}-pg-v15-${{ steps.pg_rev_v15.outputs.pg_rev }}-${{ hashFiles('Makefile') }}
|
||||
- name: Cache postgres v16 build
|
||||
id: cache_pg_v16
|
||||
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: pg_install/v16
|
||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ env.BUILD_TYPE }}-pg-v16-${{ steps.pg_rev_v16.outputs.pg_rev }}-${{ hashFiles('Makefile') }}
|
||||
- name: Cache postgres v17 build
|
||||
id: cache_pg_v17
|
||||
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: pg_install/v17
|
||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ env.BUILD_TYPE }}-pg-v17-${{ steps.pg_rev_v17.outputs.pg_rev }}-${{ hashFiles('Makefile') }}
|
||||
|
||||
- name: Cache cargo deps (only for v17)
|
||||
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
@@ -238,7 +220,7 @@ jobs:
|
||||
|
||||
- name: Cache walproposer-lib
|
||||
id: cache_walproposer_lib
|
||||
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: pg_install/build/walproposer-lib
|
||||
key: v1-${{ runner.os }}-${{ runner.arch }}-${{ env.BUILD_TYPE }}-walproposer_lib-v17-${{ steps.pg_rev_v17.outputs.pg_rev }}-${{ hashFiles('Makefile') }}
|
||||
|
||||
200
.github/workflows/build_and_test.yml
vendored
200
.github/workflows/build_and_test.yml
vendored
@@ -37,11 +37,6 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Cancel previous e2e-tests runs for this PR
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.CI_ACCESS_TOKEN }}
|
||||
@@ -58,13 +53,8 @@ jobs:
|
||||
check-rust-dependencies: ${{ steps.files-changed.outputs.rust_dependencies }}
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@@ -107,13 +97,8 @@ jobs:
|
||||
options: --init
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Check Jsonnet code formatting
|
||||
run: |
|
||||
@@ -125,17 +110,12 @@ jobs:
|
||||
needs: [ check-permissions ]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: check-if-submodules-changed
|
||||
with:
|
||||
filters: |
|
||||
@@ -144,7 +124,7 @@ jobs:
|
||||
|
||||
- name: Check vendor/postgres-v14 submodule reference
|
||||
if: steps.check-if-submodules-changed.outputs.vendor == 'true'
|
||||
uses: jtmullen/submodule-branch-check-action@ab0d3a69278e3fa0a2d4f3be3199d2514b676e13 # v1.3.0
|
||||
uses: jtmullen/submodule-branch-check-action@v1
|
||||
with:
|
||||
path: "vendor/postgres-v14"
|
||||
fetch_depth: "50"
|
||||
@@ -153,7 +133,7 @@ jobs:
|
||||
|
||||
- name: Check vendor/postgres-v15 submodule reference
|
||||
if: steps.check-if-submodules-changed.outputs.vendor == 'true'
|
||||
uses: jtmullen/submodule-branch-check-action@ab0d3a69278e3fa0a2d4f3be3199d2514b676e13 # v1.3.0
|
||||
uses: jtmullen/submodule-branch-check-action@v1
|
||||
with:
|
||||
path: "vendor/postgres-v15"
|
||||
fetch_depth: "50"
|
||||
@@ -162,7 +142,7 @@ jobs:
|
||||
|
||||
- name: Check vendor/postgres-v16 submodule reference
|
||||
if: steps.check-if-submodules-changed.outputs.vendor == 'true'
|
||||
uses: jtmullen/submodule-branch-check-action@ab0d3a69278e3fa0a2d4f3be3199d2514b676e13 # v1.3.0
|
||||
uses: jtmullen/submodule-branch-check-action@v1
|
||||
with:
|
||||
path: "vendor/postgres-v16"
|
||||
fetch_depth: "50"
|
||||
@@ -171,7 +151,7 @@ jobs:
|
||||
|
||||
- name: Check vendor/postgres-v17 submodule reference
|
||||
if: steps.check-if-submodules-changed.outputs.vendor == 'true'
|
||||
uses: jtmullen/submodule-branch-check-action@ab0d3a69278e3fa0a2d4f3be3199d2514b676e13 # v1.3.0
|
||||
uses: jtmullen/submodule-branch-check-action@v1
|
||||
with:
|
||||
path: "vendor/postgres-v17"
|
||||
fetch_depth: "50"
|
||||
@@ -239,16 +219,11 @@ jobs:
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
options: --init
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Cache poetry deps
|
||||
uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pypoetry/virtualenvs
|
||||
key: v2-${{ runner.os }}-${{ runner.arch }}-python-deps-bookworm-${{ hashFiles('poetry.lock') }}
|
||||
@@ -290,13 +265,8 @@ jobs:
|
||||
pytest_split_group: [ 1, 2, 3, 4, 5 ]
|
||||
build_type: [ release ]
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Pytest benchmarks
|
||||
uses: ./.github/actions/run-python-test-set
|
||||
@@ -324,12 +294,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: slackapi/slack-github-action@485a9d42d3a73031f12ec201c457e2162c45d02d # v2.0.0
|
||||
- uses: slackapi/slack-github-action@v2
|
||||
with:
|
||||
method: chat.postMessage
|
||||
token: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
@@ -360,12 +325,7 @@ jobs:
|
||||
options: --init
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create Allure report
|
||||
if: ${{ !cancelled() }}
|
||||
@@ -377,7 +337,7 @@ jobs:
|
||||
env:
|
||||
REGRESS_TEST_RESULT_CONNSTR_NEW: ${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}
|
||||
|
||||
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||
- uses: actions/github-script@v7
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
# Retry script for 5XX server errors: https://github.com/actions/github-script#retries
|
||||
@@ -425,12 +385,7 @@ jobs:
|
||||
coverage-json: ${{ steps.upload-coverage-report-new.outputs.summary-json }}
|
||||
steps:
|
||||
# Need `fetch-depth: 0` for differential coverage (to get diff between two commits)
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
@@ -501,7 +456,7 @@ jobs:
|
||||
REPORT_URL=https://${BUCKET}.s3.amazonaws.com/code-coverage/${COMMIT_SHA}/lcov/summary.json
|
||||
echo "summary-json=${REPORT_URL}" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||
- uses: actions/github-script@v7
|
||||
env:
|
||||
REPORT_URL_NEW: ${{ steps.upload-coverage-report-new.outputs.report-url }}
|
||||
COMMIT_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
@@ -555,38 +510,33 @@ jobs:
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- uses: neondatabase/dev-actions/set-docker-config-dir@6094485bf440001c94a94a3f9e221e81ff6b6193
|
||||
- uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
cache-binary: false
|
||||
|
||||
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.NEON_DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.NEON_DOCKERHUB_PASSWORD }}
|
||||
|
||||
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: cache.neon.build
|
||||
username: ${{ secrets.NEON_CI_DOCKERCACHE_USERNAME }}
|
||||
password: ${{ secrets.NEON_CI_DOCKERCACHE_PASSWORD }}
|
||||
|
||||
- uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
|
||||
- uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
# ARM-specific flags are recommended for Graviton ≥ 2, these flags are also supported by Ampere Altra (Azure)
|
||||
@@ -594,7 +544,7 @@ jobs:
|
||||
build-args: |
|
||||
ADDITIONAL_RUSTFLAGS=${{ matrix.arch == 'arm64' && '-Ctarget-feature=+lse -Ctarget-cpu=neoverse-n1' || '' }}
|
||||
GIT_VERSION=${{ github.event.pull_request.head.sha || github.sha }}
|
||||
BUILD_TAG=${{ needs.meta.outputs.release-tag || needs.meta.outputs.build-tag }}
|
||||
BUILD_TAG=${{ needs.meta.outputs.build-tag }}
|
||||
TAG=${{ needs.build-build-tools-image.outputs.image-tag }}-bookworm
|
||||
DEBIAN_VERSION=bookworm
|
||||
provenance: false
|
||||
@@ -617,12 +567,7 @@ jobs:
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -664,17 +609,12 @@ jobs:
|
||||
runs-on: ${{ fromJSON(format('["self-hosted", "{0}"]', matrix.arch == 'arm64' && 'large-arm64' || 'large')) }}
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- uses: neondatabase/dev-actions/set-docker-config-dir@6094485bf440001c94a94a3f9e221e81ff6b6193
|
||||
- uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
cache-binary: false
|
||||
# Disable parallelism for docker buildkit.
|
||||
@@ -683,31 +623,31 @@ jobs:
|
||||
[worker.oci]
|
||||
max-parallelism = 1
|
||||
|
||||
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.NEON_DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.NEON_DOCKERHUB_PASSWORD }}
|
||||
|
||||
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: cache.neon.build
|
||||
username: ${{ secrets.NEON_CI_DOCKERCACHE_USERNAME }}
|
||||
password: ${{ secrets.NEON_CI_DOCKERCACHE_PASSWORD }}
|
||||
|
||||
- name: Build compute-node image
|
||||
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
build-args: |
|
||||
GIT_VERSION=${{ github.event.pull_request.head.sha || github.sha }}
|
||||
PG_VERSION=${{ matrix.version.pg }}
|
||||
BUILD_TAG=${{ needs.meta.outputs.release-tag || needs.meta.outputs.build-tag }}
|
||||
BUILD_TAG=${{ needs.meta.outputs.build-tag }}
|
||||
TAG=${{ needs.build-build-tools-image.outputs.image-tag }}-${{ matrix.version.debian }}
|
||||
DEBIAN_VERSION=${{ matrix.version.debian }}
|
||||
provenance: false
|
||||
@@ -721,13 +661,13 @@ jobs:
|
||||
|
||||
- name: Build neon extensions test image
|
||||
if: matrix.version.pg >= 'v16'
|
||||
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
build-args: |
|
||||
GIT_VERSION=${{ github.event.pull_request.head.sha || github.sha }}
|
||||
PG_VERSION=${{ matrix.version.pg }}
|
||||
BUILD_TAG=${{ needs.meta.outputs.release-tag || needs.meta.outputs.build-tag }}
|
||||
BUILD_TAG=${{ needs.meta.outputs.build-tag }}
|
||||
TAG=${{ needs.build-build-tools-image.outputs.image-tag }}-${{ matrix.version.debian }}
|
||||
DEBIAN_VERSION=${{ matrix.version.debian }}
|
||||
provenance: false
|
||||
@@ -763,12 +703,7 @@ jobs:
|
||||
debian: bookworm
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -813,12 +748,7 @@ jobs:
|
||||
VM_BUILDER_VERSION: v0.42.2
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Downloading vm-builder
|
||||
run: |
|
||||
@@ -826,7 +756,7 @@ jobs:
|
||||
chmod +x vm-builder
|
||||
|
||||
- uses: neondatabase/dev-actions/set-docker-config-dir@6094485bf440001c94a94a3f9e221e81ff6b6193
|
||||
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -866,12 +796,7 @@ jobs:
|
||||
- pg: v16
|
||||
- pg: v17
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -905,21 +830,16 @@ jobs:
|
||||
runs-on: ${{ fromJSON(format('["self-hosted", "{0}"]', matrix.arch == 'arm64' && 'small-arm64' || 'small')) }}
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: neondatabase/dev-actions/set-docker-config-dir@6094485bf440001c94a94a3f9e221e81ff6b6193
|
||||
|
||||
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.NEON_DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.NEON_DOCKERHUB_PASSWORD }}
|
||||
|
||||
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -1010,12 +930,7 @@ jobs:
|
||||
compute-dev: ${{ steps.generate.outputs.compute-dev }}
|
||||
compute-prod: ${{ steps.generate.outputs.compute-prod }}
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: .github/scripts/generate_image_maps.py
|
||||
sparse-checkout-cone-mode: false
|
||||
@@ -1183,11 +1098,6 @@ jobs:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Set PR's status to pending and request a remote CI test
|
||||
run: |
|
||||
COMMIT_SHA=${{ github.event.pull_request.head.sha || github.sha }}
|
||||
@@ -1269,16 +1179,11 @@ jobs:
|
||||
runs-on: [ self-hosted, small ]
|
||||
container: ${{ vars.NEON_DEV_AWS_ACCOUNT_ID }}.dkr.ecr.${{ vars.AWS_ECR_REGION }}.amazonaws.com/ansible:latest
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create git tag and GitHub release
|
||||
if: ${{ contains(fromJSON('["storage-release", "proxy-release", "compute-release"]'), needs.meta.outputs.run-kind) }}
|
||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
TAG: "${{ needs.meta.outputs.build-tag }}"
|
||||
BRANCH: "${{ github.ref_name }}"
|
||||
@@ -1426,13 +1331,8 @@ jobs:
|
||||
if: github.ref_name == 'release' && needs.deploy.result != 'success' && always()
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Post release-deploy failure to team-storage slack channel
|
||||
uses: slackapi/slack-github-action@485a9d42d3a73031f12ec201c457e2162c45d02d # v2.0.0
|
||||
uses: slackapi/slack-github-action@v2
|
||||
with:
|
||||
method: chat.postMessage
|
||||
token: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
@@ -1453,12 +1353,7 @@ jobs:
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||
- uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: eu-central-1
|
||||
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||
@@ -1546,11 +1441,6 @@ jobs:
|
||||
steps:
|
||||
# The list of possible results:
|
||||
# https://docs.github.com/en/actions/learn-github-actions/contexts#needs-context
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Fail the job if any of the dependencies do not succeed
|
||||
run: exit 1
|
||||
if: |
|
||||
|
||||
@@ -33,12 +33,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
# Need `fetch-depth: 0` to count the number of commits in the branch
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -104,12 +99,7 @@ jobs:
|
||||
options: --init
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Create Allure report
|
||||
if: ${{ !cancelled() }}
|
||||
@@ -121,7 +111,7 @@ jobs:
|
||||
env:
|
||||
REGRESS_TEST_RESULT_CONNSTR_NEW: ${{ secrets.REGRESS_TEST_RESULT_CONNSTR_NEW }}
|
||||
|
||||
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||
- uses: actions/github-script@v7
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
# Retry script for 5XX server errors: https://github.com/actions/github-script#retries
|
||||
|
||||
12
.github/workflows/cargo-deny.yml
vendored
12
.github/workflows/cargo-deny.yml
vendored
@@ -9,9 +9,6 @@ on:
|
||||
schedule:
|
||||
- cron: '0 10 * * *'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
cargo-deny:
|
||||
strategy:
|
||||
@@ -38,13 +35,8 @@ jobs:
|
||||
options: --init
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ matrix.ref }}
|
||||
|
||||
@@ -56,7 +48,7 @@ jobs:
|
||||
|
||||
- name: Post to a Slack channel
|
||||
if: ${{ github.event_name == 'schedule' && failure() }}
|
||||
uses: slackapi/slack-github-action@485a9d42d3a73031f12ec201c457e2162c45d02d # v2.0.0
|
||||
uses: slackapi/slack-github-action@v2
|
||||
with:
|
||||
method: chat.postMessage
|
||||
token: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
|
||||
5
.github/workflows/check-permissions.yml
vendored
5
.github/workflows/check-permissions.yml
vendored
@@ -18,11 +18,6 @@ jobs:
|
||||
check-permissions:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@v2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Disallow CI runs on PRs from forks
|
||||
if: |
|
||||
inputs.github-event-name == 'pull_request' &&
|
||||
|
||||
@@ -11,11 +11,6 @@ jobs:
|
||||
cleanup:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@v2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Cleanup
|
||||
run: |
|
||||
gh extension install actions/gh-actions-cache
|
||||
|
||||
9
.github/workflows/cloud-regress.yml
vendored
9
.github/workflows/cloud-regress.yml
vendored
@@ -44,12 +44,7 @@ jobs:
|
||||
options: --init
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@@ -126,7 +121,7 @@ jobs:
|
||||
|
||||
- name: Post to a Slack channel
|
||||
if: ${{ github.event.schedule && failure() }}
|
||||
uses: slackapi/slack-github-action@fcfb566f8b0aab22203f066d80ca1d7e4b5d05b3 # v1.27.1
|
||||
uses: slackapi/slack-github-action@v1
|
||||
with:
|
||||
channel-id: ${{ vars.SLACK_ON_CALL_QA_STAGING_STREAM }}
|
||||
slack-message: |
|
||||
|
||||
5
.github/workflows/fast-forward.yml
vendored
5
.github/workflows/fast-forward.yml
vendored
@@ -13,11 +13,6 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@v2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Remove fast-forward label to PR
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.CI_ACCESS_TOKEN }}
|
||||
|
||||
@@ -34,12 +34,7 @@ jobs:
|
||||
runs-on: small
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: false
|
||||
|
||||
@@ -72,7 +67,7 @@ jobs:
|
||||
|
||||
- name: Post to the Slack channel
|
||||
if: ${{ github.event.schedule && failure() }}
|
||||
uses: slackapi/slack-github-action@fcfb566f8b0aab22203f066d80ca1d7e4b5d05b3 # v1.27.1
|
||||
uses: slackapi/slack-github-action@v1
|
||||
with:
|
||||
channel-id: ${{ vars.SLACK_ON_CALL_QA_STAGING_STREAM }}
|
||||
slack-message: |
|
||||
|
||||
12
.github/workflows/ingest_benchmark.yml
vendored
12
.github/workflows/ingest_benchmark.yml
vendored
@@ -23,9 +23,6 @@ concurrency:
|
||||
group: ingest-bench-workflow
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
ingest:
|
||||
strategy:
|
||||
@@ -78,15 +75,10 @@ jobs:
|
||||
timeout-minutes: 1440
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Configure AWS credentials # necessary to download artefacts
|
||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: eu-central-1
|
||||
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||
|
||||
10
.github/workflows/label-for-external-users.yml
vendored
10
.github/workflows/label-for-external-users.yml
vendored
@@ -27,11 +27,6 @@ jobs:
|
||||
is-member: ${{ steps.check-user.outputs.is-member }}
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@v2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Check whether `${{ github.actor }}` is a member of `${{ github.repository_owner }}`
|
||||
id: check-user
|
||||
env:
|
||||
@@ -74,11 +69,6 @@ jobs:
|
||||
issues: write # for `gh issue edit`
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@v2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Add `${{ env.LABEL }}` label
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
16
.github/workflows/large_oltp_benchmark.yml
vendored
16
.github/workflows/large_oltp_benchmark.yml
vendored
@@ -24,9 +24,6 @@ concurrency:
|
||||
group: large-oltp-bench-workflow
|
||||
cancel-in-progress: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
oltp:
|
||||
strategy:
|
||||
@@ -65,15 +62,10 @@ jobs:
|
||||
timeout-minutes: 2880
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Configure AWS credentials # necessary to download artefacts
|
||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: eu-central-1
|
||||
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||
@@ -168,7 +160,7 @@ jobs:
|
||||
api_key: ${{ secrets.NEON_STAGING_API_KEY }}
|
||||
|
||||
- name: Configure AWS credentials # again because prior steps could have exceeded 5 hours
|
||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: eu-central-1
|
||||
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||
@@ -183,7 +175,7 @@ jobs:
|
||||
|
||||
- name: Post to a Slack channel
|
||||
if: ${{ github.event.schedule && failure() }}
|
||||
uses: slackapi/slack-github-action@fcfb566f8b0aab22203f066d80ca1d7e4b5d05b3 # v1.27.1
|
||||
uses: slackapi/slack-github-action@v1
|
||||
with:
|
||||
channel-id: "C06KHQVQ7U3" # on-call-qa-staging-stream
|
||||
slack-message: |
|
||||
|
||||
10
.github/workflows/lint-release-pr.yml
vendored
10
.github/workflows/lint-release-pr.yml
vendored
@@ -7,20 +7,12 @@ on:
|
||||
- release-proxy
|
||||
- release-compute
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
lint-release-pr:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout PR branch
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # Fetch full history for git operations
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
|
||||
18
.github/workflows/neon_extra_builds.yml
vendored
18
.github/workflows/neon_extra_builds.yml
vendored
@@ -42,13 +42,8 @@ jobs:
|
||||
rebuild_everything: ${{ steps.files_changed.outputs.rebuild_neon_extra || steps.files_changed.outputs.rebuild_macos }}
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@@ -106,13 +101,8 @@ jobs:
|
||||
CARGO_INCREMENTAL: 0
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@@ -127,7 +117,7 @@ jobs:
|
||||
run: cargo build --all --release --timings -j$(nproc)
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: eu-central-1
|
||||
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_ARN }}
|
||||
@@ -144,7 +134,7 @@ jobs:
|
||||
echo "report-url=${REPORT_URL}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Publish build stats report
|
||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
REPORT_URL: ${{ steps.upload-stats.outputs.report-url }}
|
||||
SHA: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
16
.github/workflows/periodic_pagebench.yml
vendored
16
.github/workflows/periodic_pagebench.yml
vendored
@@ -25,9 +25,6 @@ concurrency:
|
||||
group: ${{ github.workflow }}
|
||||
cancel-in-progress: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
trigger_bench_on_ec2_machine_in_eu_central_1:
|
||||
permissions:
|
||||
@@ -51,18 +48,13 @@ jobs:
|
||||
steps:
|
||||
# we don't need the neon source code because we run everything remotely
|
||||
# however we still need the local github actions to run the allure step below
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Show my own (github runner) external IP address - usefull for IP allowlisting
|
||||
run: curl https://ifconfig.me
|
||||
|
||||
- name: Assume AWS OIDC role that allows to manage (start/stop/describe... EC machine)
|
||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: eu-central-1
|
||||
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_MANAGE_BENCHMARK_EC2_VMS_ARN }}
|
||||
@@ -151,7 +143,7 @@ jobs:
|
||||
|
||||
- name: Post to a Slack channel
|
||||
if: ${{ github.event.schedule && failure() }}
|
||||
uses: slackapi/slack-github-action@fcfb566f8b0aab22203f066d80ca1d7e4b5d05b3 # v1.27.1
|
||||
uses: slackapi/slack-github-action@v1
|
||||
with:
|
||||
channel-id: "C06KHQVQ7U3" # on-call-qa-staging-stream
|
||||
slack-message: "Periodic pagebench testing on dedicated hardware: ${{ job.status }}\n${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
||||
@@ -169,7 +161,7 @@ jobs:
|
||||
|
||||
- name: Assume AWS OIDC role that allows to manage (start/stop/describe... EC machine)
|
||||
if: always() && steps.poll_step.outputs.too_many_runs != 'true'
|
||||
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-region: eu-central-1
|
||||
role-to-assume: ${{ vars.DEV_AWS_OIDC_ROLE_MANAGE_BENCHMARK_EC2_VMS_ARN }}
|
||||
|
||||
18
.github/workflows/pg-clients.yml
vendored
18
.github/workflows/pg-clients.yml
vendored
@@ -88,12 +88,7 @@ jobs:
|
||||
ports:
|
||||
- 8083:8083
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Download Neon artifact
|
||||
uses: ./.github/actions/download
|
||||
@@ -143,7 +138,7 @@ jobs:
|
||||
|
||||
- name: Post to a Slack channel
|
||||
if: github.event.schedule && failure()
|
||||
uses: slackapi/slack-github-action@fcfb566f8b0aab22203f066d80ca1d7e4b5d05b3 # v1.27.1
|
||||
uses: slackapi/slack-github-action@v1
|
||||
with:
|
||||
channel-id: "C06KHQVQ7U3" # on-call-qa-staging-stream
|
||||
slack-message: |
|
||||
@@ -163,12 +158,7 @@ jobs:
|
||||
options: --init --user root
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Download Neon artifact
|
||||
uses: ./.github/actions/download
|
||||
@@ -216,7 +206,7 @@ jobs:
|
||||
|
||||
- name: Post to a Slack channel
|
||||
if: github.event.schedule && failure()
|
||||
uses: slackapi/slack-github-action@fcfb566f8b0aab22203f066d80ca1d7e4b5d05b3 # v1.27.1
|
||||
uses: slackapi/slack-github-action@v1
|
||||
with:
|
||||
channel-id: "C06KHQVQ7U3" # on-call-qa-staging-stream
|
||||
slack-message: |
|
||||
|
||||
5
.github/workflows/pin-build-tools-image.yml
vendored
5
.github/workflows/pin-build-tools-image.yml
vendored
@@ -40,11 +40,6 @@ jobs:
|
||||
skip: ${{ steps.check-manifests.outputs.skip }}
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@v2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Check if we really need to pin the image
|
||||
id: check-manifests
|
||||
env:
|
||||
|
||||
14
.github/workflows/pre-merge-checks.yml
vendored
14
.github/workflows/pre-merge-checks.yml
vendored
@@ -27,12 +27,7 @@ jobs:
|
||||
branch: ${{ steps.group-metadata.outputs.branch }}
|
||||
pr-number: ${{ steps.group-metadata.outputs.pr-number }}
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: step-security/changed-files@3dbe17c78367e7d60f00d78ae6781a35be47b4a1 # v45.0.1
|
||||
id: python-src
|
||||
@@ -130,13 +125,8 @@ jobs:
|
||||
- check-codestyle-rust
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Create fake `neon-cloud-e2e` check
|
||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
# Retry script for 5XX server errors: https://github.com/actions/github-script#retries
|
||||
retries: 5
|
||||
|
||||
7
.github/workflows/regenerate-pg-setting.yml
vendored
7
.github/workflows/regenerate-pg-setting.yml
vendored
@@ -23,13 +23,8 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Add comment
|
||||
uses: thollander/actions-comment-pull-request@65f9e5c9a1f2cd378bd74b2e057c9736982a8e74 # v3
|
||||
uses: thollander/actions-comment-pull-request@v3
|
||||
with:
|
||||
comment-tag: ${{ github.job }}
|
||||
pr-number: ${{ github.event.number }}
|
||||
|
||||
7
.github/workflows/release-notify.yml
vendored
7
.github/workflows/release-notify.yml
vendored
@@ -22,12 +22,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- uses: neondatabase/dev-actions/release-pr-notify@483a843f2a8bcfbdc4c69d27630528a3ddc4e14b # main
|
||||
- uses: neondatabase/dev-actions/release-pr-notify@main
|
||||
with:
|
||||
slack-token: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
slack-channel-id: ${{ vars.SLACK_UPCOMING_RELEASE_CHANNEL_ID || 'C05QQ9J1BRC' }} # if not set, then `#test-release-notifications`
|
||||
|
||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -3,7 +3,7 @@ name: Create Release Branch
|
||||
on:
|
||||
schedule:
|
||||
# It should be kept in sync with if-condition in jobs
|
||||
- cron: '0 6 * * TUE' # Proxy release
|
||||
- cron: '0 6 * * THU' # Proxy release
|
||||
- cron: '0 6 * * FRI' # Storage release
|
||||
- cron: '0 7 * * FRI' # Compute release
|
||||
workflow_dispatch:
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
ci-access-token: ${{ secrets.CI_ACCESS_TOKEN }}
|
||||
|
||||
create-proxy-release-branch:
|
||||
if: ${{ github.event.schedule == '0 6 * * TUE' || inputs.create-proxy-release-branch }}
|
||||
if: ${{ github.event.schedule == '0 6 * * THU' || inputs.create-proxy-release-branch }}
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
@@ -6,9 +6,6 @@ on:
|
||||
- cron: '25 0 * * *'
|
||||
- cron: '25 1 * * 6'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
gh-workflow-stats-batch-2h:
|
||||
name: GitHub Workflow Stats Batch 2 hours
|
||||
@@ -17,13 +14,8 @@ jobs:
|
||||
permissions:
|
||||
actions: read
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Export Workflow Run for the past 2 hours
|
||||
uses: neondatabase/gh-workflow-stats-action@4c998b25ab5cc6588b52a610b749531f6a566b6b # v0.2.1
|
||||
uses: neondatabase/gh-workflow-stats-action@v0.2.1
|
||||
with:
|
||||
db_uri: ${{ secrets.GH_REPORT_STATS_DB_RW_CONNSTR }}
|
||||
db_table: "gh_workflow_stats_neon"
|
||||
@@ -37,13 +29,8 @@ jobs:
|
||||
permissions:
|
||||
actions: read
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Export Workflow Run for the past 48 hours
|
||||
uses: neondatabase/gh-workflow-stats-action@4c998b25ab5cc6588b52a610b749531f6a566b6b # v0.2.1
|
||||
uses: neondatabase/gh-workflow-stats-action@v0.2.1
|
||||
with:
|
||||
db_uri: ${{ secrets.GH_REPORT_STATS_DB_RW_CONNSTR }}
|
||||
db_table: "gh_workflow_stats_neon"
|
||||
@@ -57,13 +44,8 @@ jobs:
|
||||
permissions:
|
||||
actions: read
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Export Workflow Run for the past 30 days
|
||||
uses: neondatabase/gh-workflow-stats-action@4c998b25ab5cc6588b52a610b749531f6a566b6b # v0.2.1
|
||||
uses: neondatabase/gh-workflow-stats-action@v0.2.1
|
||||
with:
|
||||
db_uri: ${{ secrets.GH_REPORT_STATS_DB_RW_CONNSTR }}
|
||||
db_table: "gh_workflow_stats_neon"
|
||||
|
||||
10
.github/workflows/trigger-e2e-tests.yml
vendored
10
.github/workflows/trigger-e2e-tests.yml
vendored
@@ -31,11 +31,6 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@v2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Cancel previous e2e-tests runs for this PR
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.CI_ACCESS_TOKEN }}
|
||||
@@ -68,11 +63,6 @@ jobs:
|
||||
|| needs.meta.outputs.build-tag
|
||||
}}
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@v2
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Wait for `push-{neon,compute}-image-dev` job to finish
|
||||
# It's important to have a timeout here, the script in the step can run infinitely
|
||||
timeout-minutes: 60
|
||||
|
||||
16
Cargo.lock
generated
16
Cargo.lock
generated
@@ -4270,7 +4270,6 @@ dependencies = [
|
||||
"scopeguard",
|
||||
"send-future",
|
||||
"serde",
|
||||
"serde_ignored",
|
||||
"serde_json",
|
||||
"serde_path_to_error",
|
||||
"serde_with",
|
||||
@@ -4693,7 +4692,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "postgres-protocol"
|
||||
version = "0.6.6"
|
||||
source = "git+https://github.com/neondatabase/rust-postgres.git?branch=neon#394851e467755562b4173ff68f9eb0e7f737be13"
|
||||
source = "git+https://github.com/neondatabase/rust-postgres.git?branch=neon#1f21e7959a96a34dcfbfce1b14b73286cdadffe9"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"byteorder",
|
||||
@@ -4727,7 +4726,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "postgres-types"
|
||||
version = "0.2.6"
|
||||
source = "git+https://github.com/neondatabase/rust-postgres.git?branch=neon#394851e467755562b4173ff68f9eb0e7f737be13"
|
||||
source = "git+https://github.com/neondatabase/rust-postgres.git?branch=neon#1f21e7959a96a34dcfbfce1b14b73286cdadffe9"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"chrono",
|
||||
@@ -6288,15 +6287,6 @@ dependencies = [
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_ignored"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "566da67d80e92e009728b3731ff0e5360cb181432b8ca73ea30bb1d170700d76"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.125"
|
||||
@@ -7180,7 +7170,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "tokio-postgres"
|
||||
version = "0.7.10"
|
||||
source = "git+https://github.com/neondatabase/rust-postgres.git?branch=neon#394851e467755562b4173ff68f9eb0e7f737be13"
|
||||
source = "git+https://github.com/neondatabase/rust-postgres.git?branch=neon#1f21e7959a96a34dcfbfce1b14b73286cdadffe9"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"byteorder",
|
||||
|
||||
@@ -164,7 +164,6 @@ sd-notify = "0.4.1"
|
||||
send-future = "0.1.0"
|
||||
sentry = { version = "0.32", default-features = false, features = ["backtrace", "contexts", "panic", "rustls", "reqwest" ] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_ignored = "0.1.11"
|
||||
serde_json = "1"
|
||||
serde_path_to_error = "0.1"
|
||||
serde_with = { version = "2.0", features = [ "base64" ] }
|
||||
|
||||
@@ -67,14 +67,6 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ${PG_VERSION} -ge 17 ]]; then
|
||||
ulid_extension=pgx_ulid
|
||||
else
|
||||
ulid_extension=ulid
|
||||
fi
|
||||
echo "Adding pgx_ulid"
|
||||
shared_libraries=$(jq -r '.cluster.settings[] | select(.name=="shared_preload_libraries").value' ${SPEC_FILE})
|
||||
sed -i "s/${shared_libraries}/${shared_libraries},${ulid_extension}/" ${SPEC_FILE}
|
||||
echo "Overwrite tenant id and timeline id in spec file"
|
||||
sed -i "s/TENANT_ID/${tenant_id}/" ${SPEC_FILE}
|
||||
sed -i "s/TIMELINE_ID/${timeline_id}/" ${SPEC_FILE}
|
||||
|
||||
@@ -69,7 +69,7 @@ for pg_version in ${TEST_VERSION_ONLY-14 15 16 17}; do
|
||||
cat ../compute/patches/contrib_pg${pg_version}.patch | docker exec -i $TEST_CONTAINER_NAME bash -c "(cd /postgres && patch -p1)"
|
||||
# We are running tests now
|
||||
rm -f testout.txt testout_contrib.txt
|
||||
docker exec -e USE_PGXS=1 -e SKIP=timescaledb-src,rdkit-src,postgis-src,pg_jsonschema-src,kq_imcx-src,wal2json_2_5-src,rag_jina_reranker_v1_tiny_en-src,rag_bge_small_en_v15-src \
|
||||
docker exec -e USE_PGXS=1 -e SKIP=timescaledb-src,rdkit-src,postgis-src,pgx_ulid-src,pg_tiktoken-src,pg_jsonschema-src,kq_imcx-src,wal2json_2_5-src \
|
||||
$TEST_CONTAINER_NAME /run-tests.sh /ext-src | tee testout.txt && EXT_SUCCESS=1 || EXT_SUCCESS=0
|
||||
docker exec -e SKIP=start-scripts,postgres_fdw,ltree_plpython,jsonb_plpython,jsonb_plperl,hstore_plpython,hstore_plperl,dblink,bool_plperl \
|
||||
$TEST_CONTAINER_NAME /run-tests.sh /postgres/contrib | tee testout_contrib.txt && CONTRIB_SUCCESS=1 || CONTRIB_SUCCESS=0
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
PG_CONFIG ?= pg_config
|
||||
PG_REGRESS = $(shell dirname $$($(PG_CONFIG) --pgxs))/../../src/test/regress/pg_regress
|
||||
REGRESS = pg_tiktoken
|
||||
|
||||
installcheck: regression-test
|
||||
|
||||
regression-test:
|
||||
$(PG_REGRESS) --inputdir=. --outputdir=. --dbname=contrib_regression $(REGRESS)
|
||||
@@ -1,53 +0,0 @@
|
||||
-- Load the extension
|
||||
CREATE EXTENSION IF NOT EXISTS pg_tiktoken;
|
||||
-- Test encoding function
|
||||
SELECT tiktoken_encode('cl100k_base', 'Hello world!');
|
||||
tiktoken_encode
|
||||
-----------------
|
||||
{9906,1917,0}
|
||||
(1 row)
|
||||
|
||||
-- Test token count function
|
||||
SELECT tiktoken_count('cl100k_base', 'Hello world!');
|
||||
tiktoken_count
|
||||
----------------
|
||||
3
|
||||
(1 row)
|
||||
|
||||
-- Test encoding function with a different model
|
||||
SELECT tiktoken_encode('r50k_base', 'PostgreSQL is amazing!');
|
||||
tiktoken_encode
|
||||
-------------------------
|
||||
{6307,47701,318,4998,0}
|
||||
(1 row)
|
||||
|
||||
-- Test token count function with the same model
|
||||
SELECT tiktoken_count('r50k_base', 'PostgreSQL is amazing!');
|
||||
tiktoken_count
|
||||
----------------
|
||||
5
|
||||
(1 row)
|
||||
|
||||
-- Edge cases: Empty string
|
||||
SELECT tiktoken_encode('cl100k_base', '');
|
||||
tiktoken_encode
|
||||
-----------------
|
||||
{}
|
||||
(1 row)
|
||||
|
||||
SELECT tiktoken_count('cl100k_base', '');
|
||||
tiktoken_count
|
||||
----------------
|
||||
0
|
||||
(1 row)
|
||||
|
||||
-- Edge cases: Long text
|
||||
SELECT tiktoken_count('cl100k_base', repeat('word ', 100));
|
||||
tiktoken_count
|
||||
----------------
|
||||
101
|
||||
(1 row)
|
||||
|
||||
-- Edge case: Invalid encoding
|
||||
SELECT tiktoken_encode('invalid_model', 'Test') AS should_fail;
|
||||
ERROR: 'invalid_model': unknown model or encoder
|
||||
@@ -1,24 +0,0 @@
|
||||
-- Load the extension
|
||||
CREATE EXTENSION IF NOT EXISTS pg_tiktoken;
|
||||
|
||||
-- Test encoding function
|
||||
SELECT tiktoken_encode('cl100k_base', 'Hello world!');
|
||||
|
||||
-- Test token count function
|
||||
SELECT tiktoken_count('cl100k_base', 'Hello world!');
|
||||
|
||||
-- Test encoding function with a different model
|
||||
SELECT tiktoken_encode('r50k_base', 'PostgreSQL is amazing!');
|
||||
|
||||
-- Test token count function with the same model
|
||||
SELECT tiktoken_count('r50k_base', 'PostgreSQL is amazing!');
|
||||
|
||||
-- Edge cases: Empty string
|
||||
SELECT tiktoken_encode('cl100k_base', '');
|
||||
SELECT tiktoken_count('cl100k_base', '');
|
||||
|
||||
-- Edge cases: Long text
|
||||
SELECT tiktoken_count('cl100k_base', repeat('word ', 100));
|
||||
|
||||
-- Edge case: Invalid encoding
|
||||
SELECT tiktoken_encode('invalid_model', 'Test') AS should_fail;
|
||||
@@ -1,10 +0,0 @@
|
||||
EXTENSION = rag
|
||||
MODULE_big = rag
|
||||
OBJS = $(patsubst %.rs,%.o,$(wildcard src/*.rs))
|
||||
|
||||
REGRESS = basic_functions text_processing api_keys chunking_functions document_processing embedding_api_functions voyageai_functions
|
||||
REGRESS_OPTS = --load-extension=vector --load-extension=rag
|
||||
|
||||
PG_CONFIG = pg_config
|
||||
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
||||
include $(PGXS)
|
||||
@@ -1,49 +0,0 @@
|
||||
-- API key function tests
|
||||
SELECT rag.anthropic_set_api_key('test_key');
|
||||
anthropic_set_api_key
|
||||
-----------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT rag.anthropic_get_api_key();
|
||||
anthropic_get_api_key
|
||||
-----------------------
|
||||
test_key
|
||||
(1 row)
|
||||
|
||||
SELECT rag.openai_set_api_key('test_key');
|
||||
openai_set_api_key
|
||||
--------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT rag.openai_get_api_key();
|
||||
openai_get_api_key
|
||||
--------------------
|
||||
test_key
|
||||
(1 row)
|
||||
|
||||
SELECT rag.fireworks_set_api_key('test_key');
|
||||
fireworks_set_api_key
|
||||
-----------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT rag.fireworks_get_api_key();
|
||||
fireworks_get_api_key
|
||||
-----------------------
|
||||
test_key
|
||||
(1 row)
|
||||
|
||||
SELECT rag.voyageai_set_api_key('test_key');
|
||||
voyageai_set_api_key
|
||||
----------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT rag.voyageai_get_api_key();
|
||||
voyageai_get_api_key
|
||||
----------------------
|
||||
test_key
|
||||
(1 row)
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
-- Basic function tests
|
||||
SELECT rag.markdown_from_html('<p>Hello</p>');
|
||||
markdown_from_html
|
||||
--------------------
|
||||
Hello
|
||||
(1 row)
|
||||
|
||||
SELECT array_length(rag.chunks_by_character_count('the cat sat on the mat', 10, 5), 1);
|
||||
array_length
|
||||
--------------
|
||||
3
|
||||
(1 row)
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
-- Chunking function tests
|
||||
SELECT rag.chunks_by_character_count('the cat sat on the mat', 10, 5);
|
||||
chunks_by_character_count
|
||||
---------------------------------------
|
||||
{"the cat","cat sat on","on the mat"}
|
||||
(1 row)
|
||||
|
||||
SELECT rag.chunks_by_character_count('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 20, 10);
|
||||
chunks_by_character_count
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
{"Lorem ipsum dolor","dolor sit amet,","amet, consectetur","adipiscing elit.","Sed do eiusmod","do eiusmod tempor","tempor incididunt ut","ut labore et dolore","et dolore magna","magna aliqua."}
|
||||
(1 row)
|
||||
|
||||
SELECT (rag.chunks_by_character_count('the cat', 10, 0))[1];
|
||||
chunks_by_character_count
|
||||
---------------------------
|
||||
the cat
|
||||
(1 row)
|
||||
|
||||
SELECT rag.chunks_by_character_count('', 10, 5);
|
||||
chunks_by_character_count
|
||||
---------------------------
|
||||
{}
|
||||
(1 row)
|
||||
|
||||
SELECT rag.chunks_by_character_count('a b c d e f g h i j k l m n o p', 5, 2);
|
||||
chunks_by_character_count
|
||||
-----------------------------------------------------------------
|
||||
{"a b c","c d e","e f g","g h i","i j k","k l m","m n o","o p"}
|
||||
(1 row)
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
-- HTML to Markdown conversion tests
|
||||
SELECT rag.markdown_from_html('<p>Hello</p>');
|
||||
markdown_from_html
|
||||
--------------------
|
||||
Hello
|
||||
(1 row)
|
||||
|
||||
SELECT rag.markdown_from_html('<p>Hello <i>world</i></p>');
|
||||
markdown_from_html
|
||||
--------------------
|
||||
Hello _world_
|
||||
(1 row)
|
||||
|
||||
SELECT rag.markdown_from_html('<h1>Title</h1><p>Paragraph</p>');
|
||||
markdown_from_html
|
||||
--------------------
|
||||
# Title +
|
||||
+
|
||||
Paragraph
|
||||
(1 row)
|
||||
|
||||
SELECT rag.markdown_from_html('<ul><li>Item 1</li><li>Item 2</li></ul>');
|
||||
markdown_from_html
|
||||
--------------------
|
||||
* Item 1 +
|
||||
* Item 2
|
||||
(1 row)
|
||||
|
||||
SELECT rag.markdown_from_html('<a href="https://example.com">Link</a>');
|
||||
markdown_from_html
|
||||
-----------------------------
|
||||
[Link](https://example.com)
|
||||
(1 row)
|
||||
|
||||
-- Note: text_from_pdf and text_from_docx require binary input which is harder to test in regression tests
|
||||
-- We'll test that the functions exist and have the right signature
|
||||
SELECT 'text_from_pdf_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'text_from_pdf'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
----------------------+--------
|
||||
text_from_pdf_exists | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'text_from_docx_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'text_from_docx'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
-----------------------+--------
|
||||
text_from_docx_exists | t
|
||||
(1 row)
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
-- Test embedding functions exist with correct signatures
|
||||
-- OpenAI embedding functions
|
||||
SELECT 'openai_text_embedding_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'openai_text_embedding'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
------------------------------+--------
|
||||
openai_text_embedding_exists | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'openai_text_embedding_3_small_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'openai_text_embedding_3_small'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
--------------------------------------+--------
|
||||
openai_text_embedding_3_small_exists | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'openai_text_embedding_3_large_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'openai_text_embedding_3_large'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
--------------------------------------+--------
|
||||
openai_text_embedding_3_large_exists | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'openai_text_embedding_ada_002_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'openai_text_embedding_ada_002'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
--------------------------------------+--------
|
||||
openai_text_embedding_ada_002_exists | t
|
||||
(1 row)
|
||||
|
||||
-- Fireworks embedding functions
|
||||
SELECT 'fireworks_nomic_embed_text_v1_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'fireworks_nomic_embed_text_v1'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
--------------------------------------+--------
|
||||
fireworks_nomic_embed_text_v1_exists | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'fireworks_nomic_embed_text_v15_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'fireworks_nomic_embed_text_v15'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
---------------------------------------+--------
|
||||
fireworks_nomic_embed_text_v15_exists | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'fireworks_text_embedding_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'fireworks_text_embedding'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
---------------------------------+--------
|
||||
fireworks_text_embedding_exists | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'fireworks_text_embedding_thenlper_gte_base_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'fireworks_text_embedding_thenlper_gte_base'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
---------------------------------------------------+--------
|
||||
fireworks_text_embedding_thenlper_gte_base_exists | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'fireworks_text_embedding_thenlper_gte_large_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'fireworks_text_embedding_thenlper_gte_large'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
----------------------------------------------------+--------
|
||||
fireworks_text_embedding_thenlper_gte_large_exists | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'fireworks_text_embedding_whereisai_uae_large_v1_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'fireworks_text_embedding_whereisai_uae_large_v1'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
--------------------------------------------------------+--------
|
||||
fireworks_text_embedding_whereisai_uae_large_v1_exists | t
|
||||
(1 row)
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
BEGIN
|
||||
CREATE EXTENSION IF NOT EXISTS vector;
|
||||
DROP EXTENSION IF EXISTS rag CASCADE;
|
||||
CREATE EXTENSION rag CASCADE;
|
||||
test_name|result
|
||||
openai_embedding_dimensions_test|t
|
||||
test_name|result
|
||||
fireworks_embedding_dimensions_test|t
|
||||
COMMIT
|
||||
@@ -1,13 +0,0 @@
|
||||
-- Text processing function tests
|
||||
SELECT rag.markdown_from_html('<p>Hello <i>world</i></p>');
|
||||
markdown_from_html
|
||||
--------------------
|
||||
Hello _world_
|
||||
(1 row)
|
||||
|
||||
SELECT rag.chunks_by_character_count('the cat sat on the mat', 10, 5);
|
||||
chunks_by_character_count
|
||||
---------------------------------------
|
||||
{"the cat","cat sat on","on the mat"}
|
||||
(1 row)
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
-- Test VoyageAI API key functions
|
||||
SELECT 'voyageai_api_key_test' AS test_name,
|
||||
(SELECT rag.voyageai_set_api_key('test_key') IS NULL) AS result;
|
||||
test_name | result
|
||||
-----------------------+--------
|
||||
voyageai_api_key_test | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'voyageai_get_api_key_test' AS test_name,
|
||||
(SELECT rag.voyageai_get_api_key() = 'test_key') AS result;
|
||||
test_name | result
|
||||
---------------------------+--------
|
||||
voyageai_get_api_key_test | t
|
||||
(1 row)
|
||||
|
||||
-- Test VoyageAI embedding functions exist
|
||||
SELECT 'voyageai_embedding_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_embedding'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
---------------------------+--------
|
||||
voyageai_embedding_exists | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'voyageai_embedding_3_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_embedding_3'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
-----------------------------+--------
|
||||
voyageai_embedding_3_exists | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'voyageai_embedding_3_lite_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_embedding_3_lite'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
----------------------------------+--------
|
||||
voyageai_embedding_3_lite_exists | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'voyageai_embedding_code_2_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_embedding_code_2'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
----------------------------------+--------
|
||||
voyageai_embedding_code_2_exists | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'voyageai_embedding_finance_2_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_embedding_finance_2'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
-------------------------------------+--------
|
||||
voyageai_embedding_finance_2_exists | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'voyageai_embedding_law_2_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_embedding_law_2'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
---------------------------------+--------
|
||||
voyageai_embedding_law_2_exists | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'voyageai_embedding_multilingual_2_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_embedding_multilingual_2'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
------------------------------------------+--------
|
||||
voyageai_embedding_multilingual_2_exists | t
|
||||
(1 row)
|
||||
|
||||
-- Test VoyageAI reranking functions exist
|
||||
SELECT 'voyageai_rerank_distance_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_rerank_distance'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
---------------------------------+--------
|
||||
voyageai_rerank_distance_exists | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'voyageai_rerank_score_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_rerank_score'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
test_name | result
|
||||
------------------------------+--------
|
||||
voyageai_rerank_score_exists | t
|
||||
(1 row)
|
||||
|
||||
-- Test VoyageAI function signatures
|
||||
SELECT 'voyageai_embedding_signature' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_embedding'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag')
|
||||
AND pronargs = 3;
|
||||
test_name | result
|
||||
------------------------------+--------
|
||||
voyageai_embedding_signature | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'voyageai_rerank_distance_signature' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_rerank_distance'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag')
|
||||
AND pronargs IN (3, 4);
|
||||
test_name | result
|
||||
------------------------------------+--------
|
||||
voyageai_rerank_distance_signature | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'voyageai_rerank_score_signature' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_rerank_score'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag')
|
||||
AND pronargs IN (3, 4);
|
||||
test_name | result
|
||||
---------------------------------+--------
|
||||
voyageai_rerank_score_signature | t
|
||||
(1 row)
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
-- API key function tests
|
||||
SELECT rag.anthropic_set_api_key('test_key');
|
||||
|
||||
SELECT rag.anthropic_get_api_key();
|
||||
|
||||
SELECT rag.openai_set_api_key('test_key');
|
||||
|
||||
SELECT rag.openai_get_api_key();
|
||||
|
||||
SELECT rag.fireworks_set_api_key('test_key');
|
||||
|
||||
SELECT rag.fireworks_get_api_key();
|
||||
|
||||
SELECT rag.voyageai_set_api_key('test_key');
|
||||
|
||||
SELECT rag.voyageai_get_api_key();
|
||||
@@ -1,4 +0,0 @@
|
||||
-- Basic function tests
|
||||
SELECT rag.markdown_from_html('<p>Hello</p>');
|
||||
|
||||
SELECT array_length(rag.chunks_by_character_count('the cat sat on the mat', 10, 5), 1);
|
||||
@@ -1,11 +0,0 @@
|
||||
-- Chunking function tests
|
||||
SELECT rag.chunks_by_character_count('the cat sat on the mat', 10, 5);
|
||||
|
||||
SELECT rag.chunks_by_character_count('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 20, 10);
|
||||
|
||||
SELECT (rag.chunks_by_character_count('the cat', 10, 0))[1];
|
||||
|
||||
SELECT rag.chunks_by_character_count('', 10, 5);
|
||||
|
||||
SELECT rag.chunks_by_character_count('a b c d e f g h i j k l m n o p', 5, 2);
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
-- HTML to Markdown conversion tests
|
||||
SELECT rag.markdown_from_html('<p>Hello</p>');
|
||||
|
||||
SELECT rag.markdown_from_html('<p>Hello <i>world</i></p>');
|
||||
|
||||
SELECT rag.markdown_from_html('<h1>Title</h1><p>Paragraph</p>');
|
||||
|
||||
SELECT rag.markdown_from_html('<ul><li>Item 1</li><li>Item 2</li></ul>');
|
||||
|
||||
SELECT rag.markdown_from_html('<a href="https://example.com">Link</a>');
|
||||
|
||||
-- Note: text_from_pdf and text_from_docx require binary input which is harder to test in regression tests
|
||||
-- We'll test that the functions exist and have the right signature
|
||||
SELECT 'text_from_pdf_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'text_from_pdf'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
|
||||
SELECT 'text_from_docx_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'text_from_docx'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
@@ -1,62 +0,0 @@
|
||||
-- Test embedding functions exist with correct signatures
|
||||
-- OpenAI embedding functions
|
||||
SELECT 'openai_text_embedding_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'openai_text_embedding'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
|
||||
SELECT 'openai_text_embedding_3_small_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'openai_text_embedding_3_small'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
|
||||
SELECT 'openai_text_embedding_3_large_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'openai_text_embedding_3_large'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
|
||||
SELECT 'openai_text_embedding_ada_002_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'openai_text_embedding_ada_002'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
|
||||
-- Fireworks embedding functions
|
||||
SELECT 'fireworks_nomic_embed_text_v1_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'fireworks_nomic_embed_text_v1'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
|
||||
SELECT 'fireworks_nomic_embed_text_v15_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'fireworks_nomic_embed_text_v15'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
|
||||
SELECT 'fireworks_text_embedding_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'fireworks_text_embedding'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
|
||||
SELECT 'fireworks_text_embedding_thenlper_gte_base_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'fireworks_text_embedding_thenlper_gte_base'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
|
||||
SELECT 'fireworks_text_embedding_thenlper_gte_large_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'fireworks_text_embedding_thenlper_gte_large'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
|
||||
SELECT 'fireworks_text_embedding_whereisai_uae_large_v1_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'fireworks_text_embedding_whereisai_uae_large_v1'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
@@ -1,4 +0,0 @@
|
||||
-- Text processing function tests
|
||||
SELECT rag.markdown_from_html('<p>Hello <i>world</i></p>');
|
||||
|
||||
SELECT rag.chunks_by_character_count('the cat sat on the mat', 10, 5);
|
||||
@@ -1,84 +0,0 @@
|
||||
-- Test VoyageAI API key functions
|
||||
SELECT 'voyageai_api_key_test' AS test_name,
|
||||
(SELECT rag.voyageai_set_api_key('test_key') IS NULL) AS result;
|
||||
|
||||
SELECT 'voyageai_get_api_key_test' AS test_name,
|
||||
(SELECT rag.voyageai_get_api_key() = 'test_key') AS result;
|
||||
|
||||
-- Test VoyageAI embedding functions exist
|
||||
SELECT 'voyageai_embedding_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_embedding'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
|
||||
SELECT 'voyageai_embedding_3_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_embedding_3'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
|
||||
SELECT 'voyageai_embedding_3_lite_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_embedding_3_lite'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
|
||||
SELECT 'voyageai_embedding_code_2_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_embedding_code_2'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
|
||||
SELECT 'voyageai_embedding_finance_2_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_embedding_finance_2'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
|
||||
SELECT 'voyageai_embedding_law_2_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_embedding_law_2'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
|
||||
SELECT 'voyageai_embedding_multilingual_2_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_embedding_multilingual_2'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
|
||||
-- Test VoyageAI reranking functions exist
|
||||
SELECT 'voyageai_rerank_distance_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_rerank_distance'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
|
||||
SELECT 'voyageai_rerank_score_exists' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_rerank_score'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag');
|
||||
|
||||
-- Test VoyageAI function signatures
|
||||
SELECT 'voyageai_embedding_signature' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_embedding'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag')
|
||||
AND pronargs = 3;
|
||||
|
||||
SELECT 'voyageai_rerank_distance_signature' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_rerank_distance'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag')
|
||||
AND pronargs IN (3, 4);
|
||||
|
||||
SELECT 'voyageai_rerank_score_signature' AS test_name,
|
||||
count(*) > 0 AS result
|
||||
FROM pg_proc
|
||||
WHERE proname = 'voyageai_rerank_score'
|
||||
AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'rag')
|
||||
AND pronargs IN (3, 4);
|
||||
@@ -1,16 +0,0 @@
|
||||
EXTENSION = pgx_ulid
|
||||
|
||||
PGFILEDESC = "pgx_ulid - ULID type for PostgreSQL"
|
||||
|
||||
PG_CONFIG ?= pg_config
|
||||
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
||||
PG_MAJOR_VERSION := $(word 2, $(subst ., , $(shell $(PG_CONFIG) --version)))
|
||||
ifeq ($(shell test $(PG_MAJOR_VERSION) -lt 17; echo $$?),0)
|
||||
REGRESS_OPTS = --load-extension=ulid
|
||||
REGRESS = 00_ulid_generation 01_ulid_conversions 03_ulid_errors
|
||||
else
|
||||
REGRESS_OPTS = --load-extension=pgx_ulid
|
||||
REGRESS = 00_ulid_generation 01_ulid_conversions 02_ulid_conversions 03_ulid_errors
|
||||
endif
|
||||
|
||||
include $(PGXS)
|
||||
@@ -1,60 +0,0 @@
|
||||
-- Test basic ULID generation
|
||||
-- Test gen_ulid() function
|
||||
SELECT 'gen_ulid() returns a non-null value' as test_name,
|
||||
gen_ulid() IS NOT NULL as result;
|
||||
test_name | result
|
||||
-------------------------------------+--------
|
||||
gen_ulid() returns a non-null value | t
|
||||
(1 row)
|
||||
|
||||
-- Test that multiple calls to gen_ulid() return different values
|
||||
SELECT 'gen_ulid() returns unique values' as test_name,
|
||||
gen_ulid() != gen_ulid() as result;
|
||||
test_name | result
|
||||
----------------------------------+--------
|
||||
gen_ulid() returns unique values | t
|
||||
(1 row)
|
||||
|
||||
-- Test that gen_ulid() returns a value with the correct format
|
||||
SELECT 'gen_ulid() returns correctly formatted value' as test_name,
|
||||
length(gen_ulid()::text) = 26 as result;
|
||||
test_name | result
|
||||
----------------------------------------------+--------
|
||||
gen_ulid() returns correctly formatted value | t
|
||||
(1 row)
|
||||
|
||||
-- Test monotonic ULID generation
|
||||
SELECT 'gen_monotonic_ulid() returns a non-null value' as test_name,
|
||||
gen_monotonic_ulid() IS NOT NULL as result;
|
||||
test_name | result
|
||||
-----------------------------------------------+--------
|
||||
gen_monotonic_ulid() returns a non-null value | t
|
||||
(1 row)
|
||||
|
||||
-- Test that multiple calls to gen_monotonic_ulid() return different values
|
||||
SELECT 'gen_monotonic_ulid() returns unique values' as test_name,
|
||||
gen_monotonic_ulid() != gen_monotonic_ulid() as result;
|
||||
test_name | result
|
||||
--------------------------------------------+--------
|
||||
gen_monotonic_ulid() returns unique values | t
|
||||
(1 row)
|
||||
|
||||
-- Test that gen_monotonic_ulid() returns a value with the correct format
|
||||
SELECT 'gen_monotonic_ulid() returns correctly formatted value' as test_name,
|
||||
length(gen_monotonic_ulid()::text) = 26 as result;
|
||||
test_name | result
|
||||
--------------------------------------------------------+--------
|
||||
gen_monotonic_ulid() returns correctly formatted value | t
|
||||
(1 row)
|
||||
|
||||
-- Test that monotonic ULIDs are ordered correctly
|
||||
SELECT 'gen_monotonic_ulid() returns ordered values' as test_name,
|
||||
u1 < u2 as result
|
||||
FROM (
|
||||
SELECT gen_monotonic_ulid() as u1, gen_monotonic_ulid() as u2
|
||||
) subq;
|
||||
test_name | result
|
||||
---------------------------------------------+--------
|
||||
gen_monotonic_ulid() returns ordered values | t
|
||||
(1 row)
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
-- Create a test ULID value
|
||||
CREATE TEMP TABLE test_ulids AS
|
||||
SELECT '01GV5PA9EQG7D82Q3Y4PKBZSYV'::ulid as test_ulid;
|
||||
-- Test conversion to text
|
||||
SELECT 'ulid to text conversion' as test_name,
|
||||
test_ulid::text = '01GV5PA9EQG7D82Q3Y4PKBZSYV' as result
|
||||
FROM test_ulids;
|
||||
test_name | result
|
||||
-------------------------+--------
|
||||
ulid to text conversion | t
|
||||
(1 row)
|
||||
|
||||
-- Test conversion to UUID
|
||||
SELECT 'ulid to UUID conversion' as test_name,
|
||||
test_ulid::uuid::text = '0186cb65-25d7-81da-815c-7e25a6bfe7db' as result
|
||||
FROM test_ulids;
|
||||
test_name | result
|
||||
-------------------------+--------
|
||||
ulid to UUID conversion | t
|
||||
(1 row)
|
||||
|
||||
-- Test conversion to bytea
|
||||
SELECT 'ulid to bytea conversion' as test_name,
|
||||
length(test_ulid::bytea) = 16 as result
|
||||
FROM test_ulids;
|
||||
test_name | result
|
||||
--------------------------+--------
|
||||
ulid to bytea conversion | t
|
||||
(1 row)
|
||||
|
||||
-- Test conversion to timestamp
|
||||
SELECT 'ulid to timestamp conversion' as test_name,
|
||||
to_char(test_ulid::timestamp, 'YYYY-MM-DD HH24:MI:SS.MS') = '2023-03-10 04:00:49.111' as result
|
||||
FROM test_ulids;
|
||||
test_name | result
|
||||
------------------------------+--------
|
||||
ulid to timestamp conversion | t
|
||||
(1 row)
|
||||
|
||||
-- Test conversion from UUID
|
||||
SELECT 'UUID to ulid conversion' as test_name,
|
||||
'0186cb65-25d7-81da-815c-7e25a6bfe7db'::uuid::ulid::text = '01GV5PA9EQG7D82Q3Y4PKBZSYV' as result;
|
||||
test_name | result
|
||||
-------------------------+--------
|
||||
UUID to ulid conversion | t
|
||||
(1 row)
|
||||
|
||||
-- Test conversion from timestamp
|
||||
SELECT 'timestamp to ulid conversion' as test_name,
|
||||
'2023-03-10 12:00:49.111'::timestamp::ulid::text = '01GV5PA9EQ0000000000000000' as result;
|
||||
test_name | result
|
||||
------------------------------+--------
|
||||
timestamp to ulid conversion | t
|
||||
(1 row)
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
-- Test conversion from timestamptz
|
||||
SELECT 'timestamptz to ulid conversion' as test_name,
|
||||
'2023-03-10 04:00:49.111'::timestamptz::ulid::text = '01GV5PA9EQ0000000000000000' as result;
|
||||
test_name | result
|
||||
--------------------------------+--------
|
||||
timestamptz to ulid conversion | t
|
||||
(1 row)
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
-- Test ULID error handling
|
||||
-- Test invalid ULID string (too short)
|
||||
SELECT '01GV5PA9EQG7D82Q3Y4PKBZSY'::ulid;
|
||||
ERROR: invalid input syntax for type ulid: "01GV5PA9EQG7D82Q3Y4PKBZSY": invalid length
|
||||
LINE 1: SELECT '01GV5PA9EQG7D82Q3Y4PKBZSY'::ulid;
|
||||
^
|
||||
-- Test invalid ULID string (invalid character)
|
||||
SELECT '01GV5PA9EQG7D82Q3Y4PKBZSYU'::ulid;
|
||||
ERROR: invalid input syntax for type ulid: "01GV5PA9EQG7D82Q3Y4PKBZSYU": invalid character
|
||||
LINE 1: SELECT '01GV5PA9EQG7D82Q3Y4PKBZSYU'::ulid;
|
||||
^
|
||||
-- Test NULL handling
|
||||
SELECT 'NULL to ulid conversion returns NULL' as test_name,
|
||||
NULL::ulid IS NULL as result;
|
||||
test_name | result
|
||||
--------------------------------------+--------
|
||||
NULL to ulid conversion returns NULL | t
|
||||
(1 row)
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
-- Test basic ULID generation
|
||||
|
||||
-- Test gen_ulid() function
|
||||
SELECT 'gen_ulid() returns a non-null value' as test_name,
|
||||
gen_ulid() IS NOT NULL as result;
|
||||
|
||||
-- Test that multiple calls to gen_ulid() return different values
|
||||
SELECT 'gen_ulid() returns unique values' as test_name,
|
||||
gen_ulid() != gen_ulid() as result;
|
||||
|
||||
-- Test that gen_ulid() returns a value with the correct format
|
||||
SELECT 'gen_ulid() returns correctly formatted value' as test_name,
|
||||
length(gen_ulid()::text) = 26 as result;
|
||||
|
||||
-- Test monotonic ULID generation
|
||||
SELECT 'gen_monotonic_ulid() returns a non-null value' as test_name,
|
||||
gen_monotonic_ulid() IS NOT NULL as result;
|
||||
|
||||
-- Test that multiple calls to gen_monotonic_ulid() return different values
|
||||
SELECT 'gen_monotonic_ulid() returns unique values' as test_name,
|
||||
gen_monotonic_ulid() != gen_monotonic_ulid() as result;
|
||||
|
||||
-- Test that gen_monotonic_ulid() returns a value with the correct format
|
||||
SELECT 'gen_monotonic_ulid() returns correctly formatted value' as test_name,
|
||||
length(gen_monotonic_ulid()::text) = 26 as result;
|
||||
|
||||
-- Test that monotonic ULIDs are ordered correctly
|
||||
SELECT 'gen_monotonic_ulid() returns ordered values' as test_name,
|
||||
u1 < u2 as result
|
||||
FROM (
|
||||
SELECT gen_monotonic_ulid() as u1, gen_monotonic_ulid() as u2
|
||||
) subq;
|
||||
@@ -1,32 +0,0 @@
|
||||
-- Create a test ULID value
|
||||
CREATE TEMP TABLE test_ulids AS
|
||||
SELECT '01GV5PA9EQG7D82Q3Y4PKBZSYV'::ulid as test_ulid;
|
||||
|
||||
-- Test conversion to text
|
||||
SELECT 'ulid to text conversion' as test_name,
|
||||
test_ulid::text = '01GV5PA9EQG7D82Q3Y4PKBZSYV' as result
|
||||
FROM test_ulids;
|
||||
|
||||
-- Test conversion to UUID
|
||||
SELECT 'ulid to UUID conversion' as test_name,
|
||||
test_ulid::uuid::text = '0186cb65-25d7-81da-815c-7e25a6bfe7db' as result
|
||||
FROM test_ulids;
|
||||
|
||||
-- Test conversion to bytea
|
||||
SELECT 'ulid to bytea conversion' as test_name,
|
||||
length(test_ulid::bytea) = 16 as result
|
||||
FROM test_ulids;
|
||||
|
||||
-- Test conversion to timestamp
|
||||
SELECT 'ulid to timestamp conversion' as test_name,
|
||||
to_char(test_ulid::timestamp, 'YYYY-MM-DD HH24:MI:SS.MS') = '2023-03-10 04:00:49.111' as result
|
||||
FROM test_ulids;
|
||||
|
||||
-- Test conversion from UUID
|
||||
SELECT 'UUID to ulid conversion' as test_name,
|
||||
'0186cb65-25d7-81da-815c-7e25a6bfe7db'::uuid::ulid::text = '01GV5PA9EQG7D82Q3Y4PKBZSYV' as result;
|
||||
|
||||
-- Test conversion from timestamp
|
||||
SELECT 'timestamp to ulid conversion' as test_name,
|
||||
'2023-03-10 12:00:49.111'::timestamp::ulid::text = '01GV5PA9EQ0000000000000000' as result;
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
-- Test conversion from timestamptz
|
||||
SELECT 'timestamptz to ulid conversion' as test_name,
|
||||
'2023-03-10 04:00:49.111'::timestamptz::ulid::text = '01GV5PA9EQ0000000000000000' as result;
|
||||
@@ -1,12 +0,0 @@
|
||||
-- Test ULID error handling
|
||||
|
||||
-- Test invalid ULID string (too short)
|
||||
SELECT '01GV5PA9EQG7D82Q3Y4PKBZSY'::ulid;
|
||||
|
||||
-- Test invalid ULID string (invalid character)
|
||||
SELECT '01GV5PA9EQG7D82Q3Y4PKBZSYU'::ulid;
|
||||
|
||||
-- Test NULL handling
|
||||
SELECT 'NULL to ulid conversion returns NULL' as test_name,
|
||||
NULL::ulid IS NULL as result;
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
EXTENSION = rag_bge_small_en_v15
|
||||
MODULE_big = rag_bge_small_en_v15
|
||||
OBJS = $(patsubst %.rs,%.o,$(wildcard src/*.rs))
|
||||
|
||||
REGRESS = basic_functions embedding_functions basic_functions_enhanced embedding_functions_enhanced
|
||||
REGRESS_OPTS = --load-extension=vector --load-extension=rag_bge_small_en_v15
|
||||
|
||||
PG_CONFIG = pg_config
|
||||
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
||||
include $(PGXS)
|
||||
@@ -1,7 +0,0 @@
|
||||
-- Basic function tests
|
||||
SELECT rag_bge_small_en_v15.chunks_by_token_count('the cat sat on the mat', 3, 2);
|
||||
chunks_by_token_count
|
||||
--------------------------------------------------------
|
||||
{"the cat sat","cat sat on","sat on the","on the mat"}
|
||||
(1 row)
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
-- Basic function tests for chunks_by_token_count
|
||||
SELECT rag_bge_small_en_v15.chunks_by_token_count('the cat sat on the mat', 3, 2);
|
||||
chunks_by_token_count
|
||||
--------------------------------------------------------
|
||||
{"the cat sat","cat sat on","sat on the","on the mat"}
|
||||
(1 row)
|
||||
|
||||
SELECT rag_bge_small_en_v15.chunks_by_token_count('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 5, 2);
|
||||
chunks_by_token_count
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
{"Lorem ipsum","ipsum dolor sit","sit amet,",consectetur,"adipiscing elit",elit.,"Sed do","do eiusmod",tempor,"incididunt ut","ut labore et","et dolore magna","magna aliqua."}
|
||||
(1 row)
|
||||
|
||||
SELECT (rag_bge_small_en_v15.chunks_by_token_count('the cat', 5, 0))[1];
|
||||
chunks_by_token_count
|
||||
-----------------------
|
||||
the cat
|
||||
(1 row)
|
||||
|
||||
SELECT rag_bge_small_en_v15.chunks_by_token_count('', 5, 2);
|
||||
chunks_by_token_count
|
||||
-----------------------
|
||||
{}
|
||||
(1 row)
|
||||
|
||||
SELECT rag_bge_small_en_v15.chunks_by_token_count('a b c d e f g h i j k l m n o p', 3, 1);
|
||||
chunks_by_token_count
|
||||
-----------------------------------------------------------------
|
||||
{"a b c","c d e","e f g","g h i","i j k","k l m","m n o","o p"}
|
||||
(1 row)
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
-- Embedding function tests
|
||||
SELECT 'embedding_for_passage_test' AS test_name,
|
||||
vector_dims(rag_bge_small_en_v15.embedding_for_passage('the cat sat on the mat')) > 0 AS result;
|
||||
test_name | result
|
||||
----------------------------+--------
|
||||
embedding_for_passage_test | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'embedding_for_query_test' AS test_name,
|
||||
vector_dims(rag_bge_small_en_v15.embedding_for_query('the cat sat on the mat')) > 0 AS result;
|
||||
test_name | result
|
||||
--------------------------+--------
|
||||
embedding_for_query_test | t
|
||||
(1 row)
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
-- Embedding function tests
|
||||
SELECT 'embedding_for_passage_test_1' AS test_name,
|
||||
vector_dims(rag_bge_small_en_v15.embedding_for_passage('the cat sat on the mat')) > 0 AS result;
|
||||
test_name | result
|
||||
------------------------------+--------
|
||||
embedding_for_passage_test_1 | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'embedding_for_passage_test_2' AS test_name,
|
||||
vector_dims(rag_bge_small_en_v15.embedding_for_passage('Lorem ipsum dolor sit amet')) > 0 AS result;
|
||||
test_name | result
|
||||
------------------------------+--------
|
||||
embedding_for_passage_test_2 | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'embedding_for_passage_test_3' AS test_name,
|
||||
vector_dims(rag_bge_small_en_v15.embedding_for_passage('')) > 0 AS result;
|
||||
test_name | result
|
||||
------------------------------+--------
|
||||
embedding_for_passage_test_3 | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'embedding_for_query_test_1' AS test_name,
|
||||
vector_dims(rag_bge_small_en_v15.embedding_for_query('the cat sat on the mat')) > 0 AS result;
|
||||
test_name | result
|
||||
----------------------------+--------
|
||||
embedding_for_query_test_1 | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'embedding_for_query_test_2' AS test_name,
|
||||
vector_dims(rag_bge_small_en_v15.embedding_for_query('Lorem ipsum dolor sit amet')) > 0 AS result;
|
||||
test_name | result
|
||||
----------------------------+--------
|
||||
embedding_for_query_test_2 | t
|
||||
(1 row)
|
||||
|
||||
SELECT 'embedding_for_query_test_3' AS test_name,
|
||||
vector_dims(rag_bge_small_en_v15.embedding_for_query('')) > 0 AS result;
|
||||
test_name | result
|
||||
----------------------------+--------
|
||||
embedding_for_query_test_3 | t
|
||||
(1 row)
|
||||
|
||||
-- Test that passage and query embeddings have the same dimensions
|
||||
SELECT 'embedding_dimensions_match' AS test_name,
|
||||
vector_dims(rag_bge_small_en_v15.embedding_for_passage('test')) =
|
||||
vector_dims(rag_bge_small_en_v15.embedding_for_query('test')) AS result;
|
||||
test_name | result
|
||||
----------------------------+--------
|
||||
embedding_dimensions_match | t
|
||||
(1 row)
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
-- Basic function tests
|
||||
SELECT rag_bge_small_en_v15.chunks_by_token_count('the cat sat on the mat', 3, 2);
|
||||
@@ -1,10 +0,0 @@
|
||||
-- Basic function tests for chunks_by_token_count
|
||||
SELECT rag_bge_small_en_v15.chunks_by_token_count('the cat sat on the mat', 3, 2);
|
||||
|
||||
SELECT rag_bge_small_en_v15.chunks_by_token_count('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 5, 2);
|
||||
|
||||
SELECT (rag_bge_small_en_v15.chunks_by_token_count('the cat', 5, 0))[1];
|
||||
|
||||
SELECT rag_bge_small_en_v15.chunks_by_token_count('', 5, 2);
|
||||
|
||||
SELECT rag_bge_small_en_v15.chunks_by_token_count('a b c d e f g h i j k l m n o p', 3, 1);
|
||||
@@ -1,6 +0,0 @@
|
||||
-- Embedding function tests
|
||||
SELECT 'embedding_for_passage_test' AS test_name,
|
||||
vector_dims(rag_bge_small_en_v15.embedding_for_passage('the cat sat on the mat')) > 0 AS result;
|
||||
|
||||
SELECT 'embedding_for_query_test' AS test_name,
|
||||
vector_dims(rag_bge_small_en_v15.embedding_for_query('the cat sat on the mat')) > 0 AS result;
|
||||
@@ -1,23 +0,0 @@
|
||||
-- Embedding function tests
|
||||
SELECT 'embedding_for_passage_test_1' AS test_name,
|
||||
vector_dims(rag_bge_small_en_v15.embedding_for_passage('the cat sat on the mat')) > 0 AS result;
|
||||
|
||||
SELECT 'embedding_for_passage_test_2' AS test_name,
|
||||
vector_dims(rag_bge_small_en_v15.embedding_for_passage('Lorem ipsum dolor sit amet')) > 0 AS result;
|
||||
|
||||
SELECT 'embedding_for_passage_test_3' AS test_name,
|
||||
vector_dims(rag_bge_small_en_v15.embedding_for_passage('')) > 0 AS result;
|
||||
|
||||
SELECT 'embedding_for_query_test_1' AS test_name,
|
||||
vector_dims(rag_bge_small_en_v15.embedding_for_query('the cat sat on the mat')) > 0 AS result;
|
||||
|
||||
SELECT 'embedding_for_query_test_2' AS test_name,
|
||||
vector_dims(rag_bge_small_en_v15.embedding_for_query('Lorem ipsum dolor sit amet')) > 0 AS result;
|
||||
|
||||
SELECT 'embedding_for_query_test_3' AS test_name,
|
||||
vector_dims(rag_bge_small_en_v15.embedding_for_query('')) > 0 AS result;
|
||||
|
||||
-- Test that passage and query embeddings have the same dimensions
|
||||
SELECT 'embedding_dimensions_match' AS test_name,
|
||||
vector_dims(rag_bge_small_en_v15.embedding_for_passage('test')) =
|
||||
vector_dims(rag_bge_small_en_v15.embedding_for_query('test')) AS result;
|
||||
@@ -1,10 +0,0 @@
|
||||
EXTENSION = rag_jina_reranker_v1_tiny_en
|
||||
MODULE_big = rag_jina_reranker_v1_tiny_en
|
||||
OBJS = $(patsubst %.rs,%.o,$(wildcard src/*.rs))
|
||||
|
||||
REGRESS = reranking_functions reranking_functions_enhanced
|
||||
REGRESS_OPTS = --load-extension=vector --load-extension=rag_jina_reranker_v1_tiny_en
|
||||
|
||||
PG_CONFIG = pg_config
|
||||
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
||||
include $(PGXS)
|
||||
@@ -1,25 +0,0 @@
|
||||
-- Reranking function tests
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_distance('the cat sat on the mat', 'the baboon played with the balloon');
|
||||
rerank_distance
|
||||
-----------------
|
||||
0.8989152
|
||||
(1 row)
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_distance('the cat sat on the mat', ARRAY['the baboon played with the balloon', 'the tanks fired at the buildings']);
|
||||
rerank_distance
|
||||
-----------------------
|
||||
{0.8989152,1.3018152}
|
||||
(1 row)
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_score('the cat sat on the mat', 'the baboon played with the balloon');
|
||||
rerank_score
|
||||
--------------
|
||||
-0.8989152
|
||||
(1 row)
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_score('the cat sat on the mat', ARRAY['the baboon played with the balloon', 'the tanks fired at the buildings']);
|
||||
rerank_score
|
||||
-------------------------
|
||||
{-0.8989152,-1.3018152}
|
||||
(1 row)
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
-- Reranking function tests - single passage
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_distance('the cat sat on the mat', 'the baboon played with the balloon');
|
||||
rerank_distance
|
||||
-----------------
|
||||
0.8989152
|
||||
(1 row)
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_distance('the cat sat on the mat', 'the tanks fired at the buildings');
|
||||
rerank_distance
|
||||
-----------------
|
||||
1.3018152
|
||||
(1 row)
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_distance('query about cats', 'information about felines');
|
||||
rerank_distance
|
||||
-----------------
|
||||
1.3133051
|
||||
(1 row)
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_distance('', 'empty query test');
|
||||
rerank_distance
|
||||
-----------------
|
||||
0.7075559
|
||||
(1 row)
|
||||
|
||||
-- Reranking function tests - array of passages
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_distance('the cat sat on the mat',
|
||||
ARRAY['the baboon played with the balloon', 'the tanks fired at the buildings']);
|
||||
rerank_distance
|
||||
-----------------------
|
||||
{0.8989152,1.3018152}
|
||||
(1 row)
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_distance('query about programming',
|
||||
ARRAY['Python is a programming language', 'Java is also a programming language', 'SQL is used for databases']);
|
||||
rerank_distance
|
||||
------------------------------------
|
||||
{0.16591403,0.33475375,0.10132827}
|
||||
(1 row)
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_distance('empty array test', ARRAY[]::text[]);
|
||||
rerank_distance
|
||||
-----------------
|
||||
{}
|
||||
(1 row)
|
||||
|
||||
-- Reranking score function tests - single passage
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_score('the cat sat on the mat', 'the baboon played with the balloon');
|
||||
rerank_score
|
||||
--------------
|
||||
-0.8989152
|
||||
(1 row)
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_score('the cat sat on the mat', 'the tanks fired at the buildings');
|
||||
rerank_score
|
||||
--------------
|
||||
-1.3018152
|
||||
(1 row)
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_score('query about cats', 'information about felines');
|
||||
rerank_score
|
||||
--------------
|
||||
-1.3133051
|
||||
(1 row)
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_score('', 'empty query test');
|
||||
rerank_score
|
||||
--------------
|
||||
-0.7075559
|
||||
(1 row)
|
||||
|
||||
-- Reranking score function tests - array of passages
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_score('the cat sat on the mat',
|
||||
ARRAY['the baboon played with the balloon', 'the tanks fired at the buildings']);
|
||||
rerank_score
|
||||
-------------------------
|
||||
{-0.8989152,-1.3018152}
|
||||
(1 row)
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_score('query about programming',
|
||||
ARRAY['Python is a programming language', 'Java is also a programming language', 'SQL is used for databases']);
|
||||
rerank_score
|
||||
---------------------------------------
|
||||
{-0.16591403,-0.33475375,-0.10132827}
|
||||
(1 row)
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_score('empty array test', ARRAY[]::text[]);
|
||||
rerank_score
|
||||
--------------
|
||||
{}
|
||||
(1 row)
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
-- Reranking function tests
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_distance('the cat sat on the mat', 'the baboon played with the balloon');
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_distance('the cat sat on the mat', ARRAY['the baboon played with the balloon', 'the tanks fired at the buildings']);
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_score('the cat sat on the mat', 'the baboon played with the balloon');
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_score('the cat sat on the mat', ARRAY['the baboon played with the balloon', 'the tanks fired at the buildings']);
|
||||
@@ -1,35 +0,0 @@
|
||||
-- Reranking function tests - single passage
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_distance('the cat sat on the mat', 'the baboon played with the balloon');
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_distance('the cat sat on the mat', 'the tanks fired at the buildings');
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_distance('query about cats', 'information about felines');
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_distance('', 'empty query test');
|
||||
|
||||
-- Reranking function tests - array of passages
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_distance('the cat sat on the mat',
|
||||
ARRAY['the baboon played with the balloon', 'the tanks fired at the buildings']);
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_distance('query about programming',
|
||||
ARRAY['Python is a programming language', 'Java is also a programming language', 'SQL is used for databases']);
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_distance('empty array test', ARRAY[]::text[]);
|
||||
|
||||
-- Reranking score function tests - single passage
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_score('the cat sat on the mat', 'the baboon played with the balloon');
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_score('the cat sat on the mat', 'the tanks fired at the buildings');
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_score('query about cats', 'information about felines');
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_score('', 'empty query test');
|
||||
|
||||
-- Reranking score function tests - array of passages
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_score('the cat sat on the mat',
|
||||
ARRAY['the baboon played with the balloon', 'the tanks fired at the buildings']);
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_score('query about programming',
|
||||
ARRAY['Python is a programming language', 'Java is also a programming language', 'SQL is used for databases']);
|
||||
|
||||
SELECT rag_jina_reranker_v1_tiny_en.rerank_score('empty array test', ARRAY[]::text[]);
|
||||
@@ -51,54 +51,9 @@ pub struct NodeMetadata {
|
||||
/// If there cannot be a static default value because we need to make runtime
|
||||
/// checks to determine the default, make it an `Option` (which defaults to None).
|
||||
/// The runtime check should be done in the consuming crate, i.e., `pageserver`.
|
||||
///
|
||||
/// Unknown fields are silently ignored during deserialization.
|
||||
/// The alternative, which we used in the past, was to set `deny_unknown_fields`,
|
||||
/// which fails deserialization, and hence pageserver startup, if there is an unknown field.
|
||||
/// The reason we don't do that anymore is that it complicates
|
||||
/// usage of config fields for feature flagging, which we commonly do for
|
||||
/// region-by-region rollouts.
|
||||
/// The complications mainly arise because the `pageserver.toml` contents on a
|
||||
/// prod server have a separate lifecycle from the pageserver binary.
|
||||
/// For instance, `pageserver.toml` contents today are defined in the internal
|
||||
/// infra repo, and thus introducing a new config field to pageserver and
|
||||
/// rolling it out to prod servers are separate commits in separate repos
|
||||
/// that can't be made or rolled back atomically.
|
||||
/// Rollbacks in particular pose a risk with deny_unknown_fields because
|
||||
/// the old pageserver binary may reject a new config field, resulting in
|
||||
/// an outage unless the person doing the pageserver rollback remembers
|
||||
/// to also revert the commit that added the config field in to the
|
||||
/// `pageserver.toml` templates in the internal infra repo.
|
||||
/// (A pre-deploy config check would eliminate this risk during rollbacks,
|
||||
/// cf [here](https://github.com/neondatabase/cloud/issues/24349).)
|
||||
/// In addition to this compatibility problem during emergency rollbacks,
|
||||
/// deny_unknown_fields adds further complications when decomissioning a feature
|
||||
/// flag: with deny_unknown_fields, we can't remove a flag from the [`ConfigToml`]
|
||||
/// until all prod servers' `pageserver.toml` files have been updated to a version
|
||||
/// that doesn't specify the flag. Otherwise new software would fail to start up.
|
||||
/// This adds the requirement for an intermediate step where the new config field
|
||||
/// is accepted but ignored, prolonging the decomissioning process by an entire
|
||||
/// release cycle.
|
||||
/// By contrast with unknown fields silently ignored, decomissioning a feature
|
||||
/// flag is a one-step process: we can skip the intermediate step and straight
|
||||
/// remove the field from the [`ConfigToml`]. We leave the field in the
|
||||
/// `pageserver.toml` files on prod servers until we reach certainty that we
|
||||
/// will not roll back to old software whose behavior was dependent on config.
|
||||
/// Then we can remove the field from the templates in the internal infra repo.
|
||||
/// This process is [documented internally](
|
||||
/// https://docs.neon.build/storage/pageserver_configuration.html).
|
||||
///
|
||||
/// Note that above relaxed compatbility for the config format does NOT APPLY
|
||||
/// TO THE STORAGE FORMAT. As general guidance, when introducing storage format
|
||||
/// changes, ensure that the potential rollback target version will be compatible
|
||||
/// with the new format. This must hold regardless of what flags are set in in the `pageserver.toml`:
|
||||
/// any format version that exists in an environment must be compatible with the software that runs there.
|
||||
/// Use a pageserver.toml flag only to gate whether software _writes_ the new format.
|
||||
/// For more compatibility considerations, refer to [internal docs](
|
||||
/// https://docs.neon.build/storage/compat.html?highlight=compat#format-versions--compatibility)
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(default)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct ConfigToml {
|
||||
// types mapped 1:1 into the runtime PageServerConfig type
|
||||
pub listen_pg_addr: String,
|
||||
@@ -179,6 +134,7 @@ pub struct ConfigToml {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct DiskUsageEvictionTaskConfig {
|
||||
pub max_usage_pct: utils::serde_percent::Percent,
|
||||
pub min_avail_bytes: u64,
|
||||
@@ -193,11 +149,13 @@ pub struct DiskUsageEvictionTaskConfig {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(tag = "mode", rename_all = "kebab-case")]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub enum PageServicePipeliningConfig {
|
||||
Serial,
|
||||
Pipelined(PageServicePipeliningConfigPipelined),
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct PageServicePipeliningConfigPipelined {
|
||||
/// Causes runtime errors if larger than max get_vectored batch size.
|
||||
pub max_batch_size: NonZeroUsize,
|
||||
@@ -213,6 +171,7 @@ pub enum PageServiceProtocolPipelinedExecutionStrategy {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(tag = "mode", rename_all = "kebab-case")]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub enum GetVectoredConcurrentIo {
|
||||
/// The read path is fully sequential: layers are visited
|
||||
/// one after the other and IOs are issued and waited upon
|
||||
@@ -281,9 +240,13 @@ impl Default for EvictionOrder {
|
||||
#[serde(transparent)]
|
||||
pub struct MaxVectoredReadBytes(pub NonZeroUsize);
|
||||
|
||||
/// Tenant-level configuration values, used for various purposes.
|
||||
/// A tenant's calcuated configuration, which is the result of merging a
|
||||
/// tenant's TenantConfOpt with the global TenantConf from PageServerConf.
|
||||
///
|
||||
/// For storing and transmitting individual tenant's configuration, see
|
||||
/// TenantConfOpt.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(default)]
|
||||
#[serde(deny_unknown_fields, default)]
|
||||
pub struct TenantConfigToml {
|
||||
// Flush out an inmemory layer, if it's holding WAL older than this
|
||||
// This puts a backstop on how much WAL needs to be re-digested if the
|
||||
|
||||
@@ -572,126 +572,65 @@ pub struct TenantConfigPatch {
|
||||
pub gc_compaction_ratio_percent: FieldPatch<u64>,
|
||||
}
|
||||
|
||||
/// Like [`crate::config::TenantConfigToml`], but preserves the information
|
||||
/// about which parameters are set and which are not.
|
||||
///
|
||||
/// Used in many places, including durably stored ones.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[serde(default)] // this maps omitted fields in deserialization to None
|
||||
/// An alternative representation of `pageserver::tenant::TenantConf` with
|
||||
/// simpler types.
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq)]
|
||||
pub struct TenantConfig {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub checkpoint_distance: Option<u64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub checkpoint_timeout: Option<Duration>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub compaction_target_size: Option<u64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub compaction_period: Option<Duration>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub compaction_threshold: Option<usize>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub compaction_upper_limit: Option<usize>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
// defer parsing compaction_algorithm, like eviction_policy
|
||||
pub compaction_algorithm: Option<CompactionAlgorithmSettings>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub compaction_l0_first: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub compaction_l0_semaphore: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub l0_flush_delay_threshold: Option<usize>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub l0_flush_stall_threshold: Option<usize>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub l0_flush_wait_upload: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub gc_horizon: Option<u64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub gc_period: Option<Duration>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_creation_threshold: Option<usize>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub pitr_interval: Option<Duration>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub walreceiver_connect_timeout: Option<Duration>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub lagging_wal_timeout: Option<Duration>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub max_lsn_wal_lag: Option<NonZeroU64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub eviction_policy: Option<EvictionPolicy>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub min_resident_size_override: Option<u64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub evictions_low_residence_duration_metric_threshold: Option<Duration>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub heatmap_period: Option<Duration>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub lazy_slru_download: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub timeline_get_throttle: Option<ThrottleConfig>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_layer_creation_check_threshold: Option<u8>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_creation_preempt_threshold: Option<usize>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub lsn_lease_length: Option<Duration>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
#[serde(with = "humantime_serde")]
|
||||
pub lsn_lease_length_for_ts: Option<Duration>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub timeline_offloading: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub wal_receiver_protocol_override: Option<PostgresClientProtocol>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub rel_size_v2_enabled: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub gc_compaction_enabled: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub gc_compaction_initial_threshold_kb: Option<u64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub gc_compaction_ratio_percent: Option<u64>,
|
||||
}
|
||||
|
||||
@@ -870,110 +809,6 @@ impl TenantConfig {
|
||||
gc_compaction_ratio_percent,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn merge(
|
||||
&self,
|
||||
global_conf: crate::config::TenantConfigToml,
|
||||
) -> crate::config::TenantConfigToml {
|
||||
crate::config::TenantConfigToml {
|
||||
checkpoint_distance: self
|
||||
.checkpoint_distance
|
||||
.unwrap_or(global_conf.checkpoint_distance),
|
||||
checkpoint_timeout: self
|
||||
.checkpoint_timeout
|
||||
.unwrap_or(global_conf.checkpoint_timeout),
|
||||
compaction_target_size: self
|
||||
.compaction_target_size
|
||||
.unwrap_or(global_conf.compaction_target_size),
|
||||
compaction_period: self
|
||||
.compaction_period
|
||||
.unwrap_or(global_conf.compaction_period),
|
||||
compaction_threshold: self
|
||||
.compaction_threshold
|
||||
.unwrap_or(global_conf.compaction_threshold),
|
||||
compaction_upper_limit: self
|
||||
.compaction_upper_limit
|
||||
.unwrap_or(global_conf.compaction_upper_limit),
|
||||
compaction_algorithm: self
|
||||
.compaction_algorithm
|
||||
.as_ref()
|
||||
.unwrap_or(&global_conf.compaction_algorithm)
|
||||
.clone(),
|
||||
compaction_l0_first: self
|
||||
.compaction_l0_first
|
||||
.unwrap_or(global_conf.compaction_l0_first),
|
||||
compaction_l0_semaphore: self
|
||||
.compaction_l0_semaphore
|
||||
.unwrap_or(global_conf.compaction_l0_semaphore),
|
||||
l0_flush_delay_threshold: self
|
||||
.l0_flush_delay_threshold
|
||||
.or(global_conf.l0_flush_delay_threshold),
|
||||
l0_flush_stall_threshold: self
|
||||
.l0_flush_stall_threshold
|
||||
.or(global_conf.l0_flush_stall_threshold),
|
||||
l0_flush_wait_upload: self
|
||||
.l0_flush_wait_upload
|
||||
.unwrap_or(global_conf.l0_flush_wait_upload),
|
||||
gc_horizon: self.gc_horizon.unwrap_or(global_conf.gc_horizon),
|
||||
gc_period: self.gc_period.unwrap_or(global_conf.gc_period),
|
||||
image_creation_threshold: self
|
||||
.image_creation_threshold
|
||||
.unwrap_or(global_conf.image_creation_threshold),
|
||||
pitr_interval: self.pitr_interval.unwrap_or(global_conf.pitr_interval),
|
||||
walreceiver_connect_timeout: self
|
||||
.walreceiver_connect_timeout
|
||||
.unwrap_or(global_conf.walreceiver_connect_timeout),
|
||||
lagging_wal_timeout: self
|
||||
.lagging_wal_timeout
|
||||
.unwrap_or(global_conf.lagging_wal_timeout),
|
||||
max_lsn_wal_lag: self.max_lsn_wal_lag.unwrap_or(global_conf.max_lsn_wal_lag),
|
||||
eviction_policy: self.eviction_policy.unwrap_or(global_conf.eviction_policy),
|
||||
min_resident_size_override: self
|
||||
.min_resident_size_override
|
||||
.or(global_conf.min_resident_size_override),
|
||||
evictions_low_residence_duration_metric_threshold: self
|
||||
.evictions_low_residence_duration_metric_threshold
|
||||
.unwrap_or(global_conf.evictions_low_residence_duration_metric_threshold),
|
||||
heatmap_period: self.heatmap_period.unwrap_or(global_conf.heatmap_period),
|
||||
lazy_slru_download: self
|
||||
.lazy_slru_download
|
||||
.unwrap_or(global_conf.lazy_slru_download),
|
||||
timeline_get_throttle: self
|
||||
.timeline_get_throttle
|
||||
.clone()
|
||||
.unwrap_or(global_conf.timeline_get_throttle),
|
||||
image_layer_creation_check_threshold: self
|
||||
.image_layer_creation_check_threshold
|
||||
.unwrap_or(global_conf.image_layer_creation_check_threshold),
|
||||
image_creation_preempt_threshold: self
|
||||
.image_creation_preempt_threshold
|
||||
.unwrap_or(global_conf.image_creation_preempt_threshold),
|
||||
lsn_lease_length: self
|
||||
.lsn_lease_length
|
||||
.unwrap_or(global_conf.lsn_lease_length),
|
||||
lsn_lease_length_for_ts: self
|
||||
.lsn_lease_length_for_ts
|
||||
.unwrap_or(global_conf.lsn_lease_length_for_ts),
|
||||
timeline_offloading: self
|
||||
.timeline_offloading
|
||||
.unwrap_or(global_conf.timeline_offloading),
|
||||
wal_receiver_protocol_override: self
|
||||
.wal_receiver_protocol_override
|
||||
.or(global_conf.wal_receiver_protocol_override),
|
||||
rel_size_v2_enabled: self
|
||||
.rel_size_v2_enabled
|
||||
.unwrap_or(global_conf.rel_size_v2_enabled),
|
||||
gc_compaction_enabled: self
|
||||
.gc_compaction_enabled
|
||||
.unwrap_or(global_conf.gc_compaction_enabled),
|
||||
gc_compaction_initial_threshold_kb: self
|
||||
.gc_compaction_initial_threshold_kb
|
||||
.unwrap_or(global_conf.gc_compaction_initial_threshold_kb),
|
||||
gc_compaction_ratio_percent: self
|
||||
.gc_compaction_ratio_percent
|
||||
.unwrap_or(global_conf.gc_compaction_ratio_percent),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The policy for the aux file storage.
|
||||
@@ -1105,7 +940,7 @@ pub struct CompactionAlgorithmSettings {
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
|
||||
#[serde(tag = "mode", rename_all = "kebab-case")]
|
||||
#[serde(tag = "mode", rename_all = "kebab-case", deny_unknown_fields)]
|
||||
pub enum L0FlushConfig {
|
||||
#[serde(rename_all = "snake_case")]
|
||||
Direct { max_concurrency: NonZeroUsize },
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Types in this file are for pageserver's upward-facing API calls to the storage controller,
|
||||
//! Types in this file are for pageserver's upward-facing API calls to the control plane,
|
||||
//! required for acquiring and validating tenant generation numbers.
|
||||
//!
|
||||
//! See docs/rfcs/025-generation-numbers.md
|
||||
|
||||
@@ -52,7 +52,6 @@ rustls.workspace = true
|
||||
scopeguard.workspace = true
|
||||
send-future.workspace = true
|
||||
serde.workspace = true
|
||||
serde_ignored.workspace = true
|
||||
serde_json = { workspace = true, features = ["raw_value"] }
|
||||
serde_path_to_error.workspace = true
|
||||
serde_with.workspace = true
|
||||
|
||||
@@ -16,7 +16,7 @@ use metrics::launch_timestamp::{LaunchTimestamp, set_launch_timestamp_metric};
|
||||
use metrics::set_build_info_metric;
|
||||
use nix::sys::socket::{setsockopt, sockopt};
|
||||
use pageserver::config::{PageServerConf, PageserverIdentity};
|
||||
use pageserver::controller_upcall_client::StorageControllerUpcallClient;
|
||||
use pageserver::controller_upcall_client::ControllerUpcallClient;
|
||||
use pageserver::deletion_queue::DeletionQueue;
|
||||
use pageserver::disk_usage_eviction_task::{self, launch_disk_usage_global_eviction_task};
|
||||
use pageserver::metrics::{STARTUP_DURATION, STARTUP_IS_LOADING};
|
||||
@@ -96,7 +96,7 @@ fn main() -> anyhow::Result<()> {
|
||||
env::set_current_dir(&workdir)
|
||||
.with_context(|| format!("Failed to set application's current dir to '{workdir}'"))?;
|
||||
|
||||
let (conf, ignored) = initialize_config(&identity_file_path, &cfg_file_path, &workdir)?;
|
||||
let conf = initialize_config(&identity_file_path, &cfg_file_path, &workdir)?;
|
||||
|
||||
// Initialize logging.
|
||||
//
|
||||
@@ -127,17 +127,7 @@ fn main() -> anyhow::Result<()> {
|
||||
&[("node_id", &conf.id.to_string())],
|
||||
);
|
||||
|
||||
// Warn about ignored config items; see pageserver_api::config::ConfigToml
|
||||
// doc comment for rationale why we prefer this over serde(deny_unknown_fields).
|
||||
{
|
||||
let IgnoredConfigItems { paths } = ignored;
|
||||
for path in paths {
|
||||
warn!(?path, "ignoring unknown configuration item");
|
||||
}
|
||||
}
|
||||
|
||||
// Log configuration items for feature-flag-like config
|
||||
// (maybe we should automate this with a visitor?).
|
||||
// after setting up logging, log the effective IO engine choice and read path implementations
|
||||
info!(?conf.virtual_file_io_engine, "starting with virtual_file IO engine");
|
||||
info!(?conf.virtual_file_io_mode, "starting with virtual_file IO mode");
|
||||
info!(?conf.wal_receiver_protocol, "starting with WAL receiver protocol");
|
||||
@@ -206,15 +196,11 @@ fn main() -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct IgnoredConfigItems {
|
||||
paths: Vec<String>,
|
||||
}
|
||||
|
||||
fn initialize_config(
|
||||
identity_file_path: &Utf8Path,
|
||||
cfg_file_path: &Utf8Path,
|
||||
workdir: &Utf8Path,
|
||||
) -> anyhow::Result<(&'static PageServerConf, IgnoredConfigItems)> {
|
||||
) -> anyhow::Result<&'static PageServerConf> {
|
||||
// The deployment orchestrator writes out an indentity file containing the node id
|
||||
// for all pageservers. This file is the source of truth for the node id. In order
|
||||
// to allow for rolling back pageserver releases, the node id is also included in
|
||||
@@ -243,23 +229,15 @@ fn initialize_config(
|
||||
|
||||
let config_file_contents =
|
||||
std::fs::read_to_string(cfg_file_path).context("read config file from filesystem")?;
|
||||
let deserializer = toml_edit::de::Deserializer::from_str(&config_file_contents)
|
||||
.context("build toml deserializer")?;
|
||||
let mut path_to_error_track = serde_path_to_error::Track::new();
|
||||
let deserializer =
|
||||
serde_path_to_error::Deserializer::new(deserializer, &mut path_to_error_track);
|
||||
let mut ignored = Vec::new();
|
||||
let mut push_to_ignored = |path: serde_ignored::Path<'_>| {
|
||||
ignored.push(path.to_string());
|
||||
};
|
||||
let deserializer = serde_ignored::Deserializer::new(deserializer, &mut push_to_ignored);
|
||||
let config_toml: pageserver_api::config::ConfigToml =
|
||||
serde::Deserialize::deserialize(deserializer).context("deserialize config toml")?;
|
||||
let config_toml = serde_path_to_error::deserialize(
|
||||
toml_edit::de::Deserializer::from_str(&config_file_contents)
|
||||
.context("build toml deserializer")?,
|
||||
)
|
||||
.context("deserialize config toml")?;
|
||||
let conf = PageServerConf::parse_and_validate(identity.id, config_toml, workdir)
|
||||
.context("runtime-validation of config toml")?;
|
||||
let conf = Box::leak(Box::new(conf));
|
||||
let ignored = IgnoredConfigItems { paths: ignored };
|
||||
Ok((conf, ignored))
|
||||
|
||||
Ok(Box::leak(Box::new(conf)))
|
||||
}
|
||||
|
||||
struct WaitForPhaseResult<F: std::future::Future + Unpin> {
|
||||
@@ -449,7 +427,7 @@ fn start_pageserver(
|
||||
// Set up deletion queue
|
||||
let (deletion_queue, deletion_workers) = DeletionQueue::new(
|
||||
remote_storage.clone(),
|
||||
StorageControllerUpcallClient::new(conf, &shutdown_pageserver),
|
||||
ControllerUpcallClient::new(conf, &shutdown_pageserver),
|
||||
conf,
|
||||
);
|
||||
deletion_workers.spawn_with(BACKGROUND_RUNTIME.handle());
|
||||
|
||||
@@ -94,7 +94,7 @@ pub struct PageServerConf {
|
||||
|
||||
pub remote_storage_config: Option<RemoteStorageConfig>,
|
||||
|
||||
pub default_tenant_conf: pageserver_api::config::TenantConfigToml,
|
||||
pub default_tenant_conf: crate::tenant::config::TenantConf,
|
||||
|
||||
/// Storage broker endpoints to connect to.
|
||||
pub broker_endpoint: Uri,
|
||||
@@ -526,6 +526,7 @@ impl PageServerConf {
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct PageserverIdentity {
|
||||
pub id: NodeId,
|
||||
}
|
||||
@@ -597,4 +598,82 @@ mod tests {
|
||||
PageServerConf::parse_and_validate(NodeId(0), config_toml, &workdir)
|
||||
.expect("parse_and_validate");
|
||||
}
|
||||
|
||||
/// If there's a typo in the pageserver config, we'd rather catch that typo
|
||||
/// and fail pageserver startup than silently ignoring the typo, leaving whoever
|
||||
/// made it in the believe that their config change is effective.
|
||||
///
|
||||
/// The default in serde is to allow unknown fields, so, we rely
|
||||
/// on developer+review discipline to add `deny_unknown_fields` when adding
|
||||
/// new structs to the config, and these tests here as a regression test.
|
||||
///
|
||||
/// The alternative to all of this would be to allow unknown fields in the config.
|
||||
/// To catch them, we could have a config check tool or mgmt API endpoint that
|
||||
/// compares the effective config with the TOML on disk and makes sure that
|
||||
/// the on-disk TOML is a strict subset of the effective config.
|
||||
mod unknown_fields_handling {
|
||||
macro_rules! test {
|
||||
($short_name:ident, $input:expr) => {
|
||||
#[test]
|
||||
fn $short_name() {
|
||||
let input = $input;
|
||||
let err = toml_edit::de::from_str::<pageserver_api::config::ConfigToml>(&input)
|
||||
.expect_err("some_invalid_field is an invalid field");
|
||||
dbg!(&err);
|
||||
assert!(err.to_string().contains("some_invalid_field"));
|
||||
}
|
||||
};
|
||||
}
|
||||
use indoc::indoc;
|
||||
|
||||
test!(
|
||||
toplevel,
|
||||
indoc! {r#"
|
||||
some_invalid_field = 23
|
||||
"#}
|
||||
);
|
||||
|
||||
test!(
|
||||
toplevel_nested,
|
||||
indoc! {r#"
|
||||
[some_invalid_field]
|
||||
foo = 23
|
||||
"#}
|
||||
);
|
||||
|
||||
test!(
|
||||
disk_usage_based_eviction,
|
||||
indoc! {r#"
|
||||
[disk_usage_based_eviction]
|
||||
some_invalid_field = 23
|
||||
"#}
|
||||
);
|
||||
|
||||
test!(
|
||||
tenant_config,
|
||||
indoc! {r#"
|
||||
[tenant_config]
|
||||
some_invalid_field = 23
|
||||
"#}
|
||||
);
|
||||
|
||||
test!(
|
||||
l0_flush,
|
||||
indoc! {r#"
|
||||
[l0_flush]
|
||||
mode = "direct"
|
||||
some_invalid_field = 23
|
||||
"#}
|
||||
);
|
||||
|
||||
// TODO: fix this => https://github.com/neondatabase/neon/issues/8915
|
||||
// test!(
|
||||
// remote_storage_config,
|
||||
// indoc! {r#"
|
||||
// [remote_storage_config]
|
||||
// local_path = "/nonexistent"
|
||||
// some_invalid_field = 23
|
||||
// "#}
|
||||
// );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,10 @@ use crate::virtual_file::on_fatal_io_error;
|
||||
|
||||
/// The Pageserver's client for using the storage controller upcall API: this is a small API
|
||||
/// for dealing with generations (see docs/rfcs/025-generation-numbers.md).
|
||||
pub struct StorageControllerUpcallClient {
|
||||
///
|
||||
/// The server presenting this API may either be the storage controller or some other
|
||||
/// service (such as the Neon control plane) providing a store of generation numbers.
|
||||
pub struct ControllerUpcallClient {
|
||||
http_client: reqwest::Client,
|
||||
base_url: Url,
|
||||
node_id: NodeId,
|
||||
@@ -34,7 +37,7 @@ pub enum RetryForeverError {
|
||||
ShuttingDown,
|
||||
}
|
||||
|
||||
pub trait StorageControllerUpcallApi {
|
||||
pub trait ControlPlaneGenerationsApi {
|
||||
fn re_attach(
|
||||
&self,
|
||||
conf: &PageServerConf,
|
||||
@@ -47,7 +50,7 @@ pub trait StorageControllerUpcallApi {
|
||||
) -> impl Future<Output = Result<HashMap<TenantShardId, bool>, RetryForeverError>> + Send;
|
||||
}
|
||||
|
||||
impl StorageControllerUpcallClient {
|
||||
impl ControllerUpcallClient {
|
||||
/// A None return value indicates that the input `conf` object does not have control
|
||||
/// plane API enabled.
|
||||
pub fn new(conf: &'static PageServerConf, cancel: &CancellationToken) -> Option<Self> {
|
||||
@@ -121,7 +124,7 @@ impl StorageControllerUpcallClient {
|
||||
}
|
||||
}
|
||||
|
||||
impl StorageControllerUpcallApi for StorageControllerUpcallClient {
|
||||
impl ControlPlaneGenerationsApi for ControllerUpcallClient {
|
||||
/// Block until we get a successful response, or error out if we are shut down
|
||||
#[tracing::instrument(skip_all)] // so that warning logs from retry_http_forever have context
|
||||
async fn re_attach(
|
||||
|
||||
@@ -26,7 +26,7 @@ use self::deleter::Deleter;
|
||||
use self::list_writer::{DeletionOp, ListWriter, RecoverOp};
|
||||
use self::validator::Validator;
|
||||
use crate::config::PageServerConf;
|
||||
use crate::controller_upcall_client::StorageControllerUpcallApi;
|
||||
use crate::controller_upcall_client::ControlPlaneGenerationsApi;
|
||||
use crate::metrics;
|
||||
use crate::tenant::remote_timeline_client::{LayerFileMetadata, remote_timeline_path};
|
||||
use crate::tenant::storage_layer::LayerName;
|
||||
@@ -76,7 +76,7 @@ pub struct DeletionQueue {
|
||||
/// worker objects themselves public
|
||||
pub struct DeletionQueueWorkers<C>
|
||||
where
|
||||
C: StorageControllerUpcallApi + Send + Sync,
|
||||
C: ControlPlaneGenerationsApi + Send + Sync,
|
||||
{
|
||||
frontend: ListWriter,
|
||||
backend: Validator<C>,
|
||||
@@ -85,7 +85,7 @@ where
|
||||
|
||||
impl<C> DeletionQueueWorkers<C>
|
||||
where
|
||||
C: StorageControllerUpcallApi + Send + Sync + 'static,
|
||||
C: ControlPlaneGenerationsApi + Send + Sync + 'static,
|
||||
{
|
||||
pub fn spawn_with(mut self, runtime: &tokio::runtime::Handle) -> tokio::task::JoinHandle<()> {
|
||||
let jh_frontend = runtime.spawn(async move {
|
||||
@@ -589,7 +589,7 @@ impl DeletionQueue {
|
||||
conf: &'static PageServerConf,
|
||||
) -> (Self, DeletionQueueWorkers<C>)
|
||||
where
|
||||
C: StorageControllerUpcallApi + Send + Sync,
|
||||
C: ControlPlaneGenerationsApi + Send + Sync,
|
||||
{
|
||||
// Unbounded channel: enables non-async functions to submit deletions. The actual length is
|
||||
// constrained by how promptly the ListWriter wakes up and drains it, which should be frequent
|
||||
@@ -691,7 +691,7 @@ mod test {
|
||||
harness: TenantHarness,
|
||||
remote_fs_dir: Utf8PathBuf,
|
||||
storage: GenericRemoteStorage,
|
||||
mock_control_plane: MockStorageController,
|
||||
mock_control_plane: MockControlPlane,
|
||||
deletion_queue: DeletionQueue,
|
||||
worker_join: JoinHandle<()>,
|
||||
}
|
||||
@@ -751,11 +751,11 @@ mod test {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct MockStorageController {
|
||||
struct MockControlPlane {
|
||||
pub latest_generation: std::sync::Arc<std::sync::Mutex<HashMap<TenantShardId, Generation>>>,
|
||||
}
|
||||
|
||||
impl MockStorageController {
|
||||
impl MockControlPlane {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
latest_generation: Arc::default(),
|
||||
@@ -763,7 +763,7 @@ mod test {
|
||||
}
|
||||
}
|
||||
|
||||
impl StorageControllerUpcallApi for MockStorageController {
|
||||
impl ControlPlaneGenerationsApi for MockControlPlane {
|
||||
async fn re_attach(
|
||||
&self,
|
||||
_conf: &PageServerConf,
|
||||
@@ -810,7 +810,7 @@ mod test {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mock_control_plane = MockStorageController::new();
|
||||
let mock_control_plane = MockControlPlane::new();
|
||||
|
||||
let (deletion_queue, worker) = DeletionQueue::new(
|
||||
storage.clone(),
|
||||
|
||||
@@ -25,7 +25,7 @@ use tracing::{debug, info, warn};
|
||||
use super::deleter::DeleterMessage;
|
||||
use super::{DeletionHeader, DeletionList, DeletionQueueError, FlushOp, VisibleLsnUpdates};
|
||||
use crate::config::PageServerConf;
|
||||
use crate::controller_upcall_client::{RetryForeverError, StorageControllerUpcallApi};
|
||||
use crate::controller_upcall_client::{ControlPlaneGenerationsApi, RetryForeverError};
|
||||
use crate::metrics;
|
||||
use crate::virtual_file::MaybeFatalIo;
|
||||
|
||||
@@ -46,7 +46,7 @@ pub(super) enum ValidatorQueueMessage {
|
||||
}
|
||||
pub(super) struct Validator<C>
|
||||
where
|
||||
C: StorageControllerUpcallApi,
|
||||
C: ControlPlaneGenerationsApi,
|
||||
{
|
||||
conf: &'static PageServerConf,
|
||||
rx: tokio::sync::mpsc::Receiver<ValidatorQueueMessage>,
|
||||
@@ -80,7 +80,7 @@ where
|
||||
|
||||
impl<C> Validator<C>
|
||||
where
|
||||
C: StorageControllerUpcallApi,
|
||||
C: ControlPlaneGenerationsApi,
|
||||
{
|
||||
pub(super) fn new(
|
||||
conf: &'static PageServerConf,
|
||||
|
||||
@@ -60,7 +60,7 @@ use crate::context::{DownloadBehavior, RequestContext, RequestContextBuilder};
|
||||
use crate::deletion_queue::DeletionQueueClient;
|
||||
use crate::pgdatadir_mapping::LsnForTimestamp;
|
||||
use crate::task_mgr::TaskKind;
|
||||
use crate::tenant::config::LocationConf;
|
||||
use crate::tenant::config::{LocationConf, TenantConfOpt};
|
||||
use crate::tenant::mgr::{
|
||||
GetActiveTenantError, GetTenantError, TenantManager, TenantMapError, TenantMapInsertError,
|
||||
TenantSlot, TenantSlotError, TenantSlotUpsertError, TenantStateError, UpsertLocationError,
|
||||
@@ -1849,7 +1849,8 @@ async fn update_tenant_config_handler(
|
||||
let tenant_id = request_data.tenant_id;
|
||||
check_permission(&request, Some(tenant_id))?;
|
||||
|
||||
let new_tenant_conf = request_data.config;
|
||||
let new_tenant_conf =
|
||||
TenantConfOpt::try_from(&request_data.config).map_err(ApiError::BadRequest)?;
|
||||
|
||||
let state = get_state(&request);
|
||||
|
||||
@@ -1898,10 +1899,7 @@ async fn patch_tenant_config_handler(
|
||||
tenant.wait_to_become_active(ACTIVE_TENANT_TIMEOUT).await?;
|
||||
|
||||
let updated = tenant
|
||||
.update_tenant_config(|crnt| {
|
||||
crnt.apply_patch(request_data.config.clone())
|
||||
.map_err(anyhow::Error::new)
|
||||
})
|
||||
.update_tenant_config(|crnt| crnt.apply_patch(request_data.config.clone()))
|
||||
.map_err(ApiError::BadRequest)?;
|
||||
|
||||
// This is a legacy API that only operates on attached tenants: the preferred
|
||||
|
||||
@@ -67,7 +67,7 @@ use utils::try_rcu::ArcSwapExt;
|
||||
use utils::zstd::{create_zst_tarball, extract_zst_tarball};
|
||||
use utils::{backoff, completion, failpoint_support, fs_ext, pausable_failpoint};
|
||||
|
||||
use self::config::{AttachedLocationConfig, AttachmentMode, LocationConf};
|
||||
use self::config::{AttachedLocationConfig, AttachmentMode, LocationConf, TenantConf};
|
||||
use self::metadata::TimelineMetadata;
|
||||
use self::mgr::{GetActiveTenantError, GetTenantError};
|
||||
use self::remote_timeline_client::upload::{upload_index_part, upload_tenant_manifest};
|
||||
@@ -88,7 +88,7 @@ use crate::metrics::{
|
||||
TENANT_SYNTHETIC_SIZE_METRIC, remove_tenant_metrics,
|
||||
};
|
||||
use crate::task_mgr::TaskKind;
|
||||
use crate::tenant::config::LocationMode;
|
||||
use crate::tenant::config::{LocationMode, TenantConfOpt};
|
||||
use crate::tenant::gc_result::GcResult;
|
||||
pub use crate::tenant::remote_timeline_client::index::IndexPart;
|
||||
use crate::tenant::remote_timeline_client::{
|
||||
@@ -162,7 +162,7 @@ pub struct TenantSharedResources {
|
||||
/// in this struct.
|
||||
#[derive(Clone)]
|
||||
pub(super) struct AttachedTenantConf {
|
||||
tenant_conf: pageserver_api::models::TenantConfig,
|
||||
tenant_conf: TenantConfOpt,
|
||||
location: AttachedLocationConfig,
|
||||
/// The deadline before which we are blocked from GC so that
|
||||
/// leases have a chance to be renewed.
|
||||
@@ -170,10 +170,7 @@ pub(super) struct AttachedTenantConf {
|
||||
}
|
||||
|
||||
impl AttachedTenantConf {
|
||||
fn new(
|
||||
tenant_conf: pageserver_api::models::TenantConfig,
|
||||
location: AttachedLocationConfig,
|
||||
) -> Self {
|
||||
fn new(tenant_conf: TenantConfOpt, location: AttachedLocationConfig) -> Self {
|
||||
// Sets a deadline before which we cannot proceed to GC due to lsn lease.
|
||||
//
|
||||
// We do this as the leases mapping are not persisted to disk. By delaying GC by lease
|
||||
@@ -254,7 +251,7 @@ pub struct Tenant {
|
||||
state: watch::Sender<TenantState>,
|
||||
|
||||
// Overridden tenant-specific config parameters.
|
||||
// We keep pageserver_api::models::TenantConfig sturct here to preserve the information
|
||||
// We keep TenantConfOpt sturct here to preserve the information
|
||||
// about parameters that are not set.
|
||||
// This is necessary to allow global config updates.
|
||||
tenant_conf: Arc<ArcSwap<AttachedTenantConf>>,
|
||||
@@ -3705,14 +3702,17 @@ impl Tenant {
|
||||
/// create a Tenant in the same state. Do not use this in hot paths: it's for relatively
|
||||
/// rare external API calls, like a reconciliation at startup.
|
||||
pub(crate) fn get_location_conf(&self) -> models::LocationConfig {
|
||||
let attached_tenant_conf = self.tenant_conf.load();
|
||||
let conf = self.tenant_conf.load();
|
||||
|
||||
let location_config_mode = match attached_tenant_conf.location.attach_mode {
|
||||
let location_config_mode = match conf.location.attach_mode {
|
||||
AttachmentMode::Single => models::LocationConfigMode::AttachedSingle,
|
||||
AttachmentMode::Multi => models::LocationConfigMode::AttachedMulti,
|
||||
AttachmentMode::Stale => models::LocationConfigMode::AttachedStale,
|
||||
};
|
||||
|
||||
// We have a pageserver TenantConf, we need the API-facing TenantConfig.
|
||||
let tenant_config: models::TenantConfig = conf.tenant_conf.clone().into();
|
||||
|
||||
models::LocationConfig {
|
||||
mode: location_config_mode,
|
||||
generation: self.generation.into(),
|
||||
@@ -3720,7 +3720,7 @@ impl Tenant {
|
||||
shard_number: self.shard_identity.number.0,
|
||||
shard_count: self.shard_identity.count.literal(),
|
||||
shard_stripe_size: self.shard_identity.stripe_size.0,
|
||||
tenant_conf: attached_tenant_conf.tenant_conf.clone(),
|
||||
tenant_conf: tenant_config,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3926,11 +3926,11 @@ enum ActivateTimelineArgs {
|
||||
}
|
||||
|
||||
impl Tenant {
|
||||
pub fn tenant_specific_overrides(&self) -> pageserver_api::models::TenantConfig {
|
||||
pub fn tenant_specific_overrides(&self) -> TenantConfOpt {
|
||||
self.tenant_conf.load().tenant_conf.clone()
|
||||
}
|
||||
|
||||
pub fn effective_config(&self) -> pageserver_api::config::TenantConfigToml {
|
||||
pub fn effective_config(&self) -> TenantConf {
|
||||
self.tenant_specific_overrides()
|
||||
.merge(self.conf.default_tenant_conf.clone())
|
||||
}
|
||||
@@ -4072,14 +4072,10 @@ impl Tenant {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_tenant_config<
|
||||
F: Fn(
|
||||
pageserver_api::models::TenantConfig,
|
||||
) -> anyhow::Result<pageserver_api::models::TenantConfig>,
|
||||
>(
|
||||
pub fn update_tenant_config<F: Fn(TenantConfOpt) -> anyhow::Result<TenantConfOpt>>(
|
||||
&self,
|
||||
update: F,
|
||||
) -> anyhow::Result<pageserver_api::models::TenantConfig> {
|
||||
) -> anyhow::Result<TenantConfOpt> {
|
||||
// Use read-copy-update in order to avoid overwriting the location config
|
||||
// state if this races with [`Tenant::set_new_location_config`]. Note that
|
||||
// this race is not possible if both request types come from the storage
|
||||
@@ -4126,7 +4122,7 @@ impl Tenant {
|
||||
|
||||
fn get_pagestream_throttle_config(
|
||||
psconf: &'static PageServerConf,
|
||||
overrides: &pageserver_api::models::TenantConfig,
|
||||
overrides: &TenantConfOpt,
|
||||
) -> throttle::Config {
|
||||
overrides
|
||||
.timeline_get_throttle
|
||||
@@ -4134,7 +4130,7 @@ impl Tenant {
|
||||
.unwrap_or(psconf.default_tenant_conf.timeline_get_throttle.clone())
|
||||
}
|
||||
|
||||
pub(crate) fn tenant_conf_updated(&self, new_conf: &pageserver_api::models::TenantConfig) {
|
||||
pub(crate) fn tenant_conf_updated(&self, new_conf: &TenantConfOpt) {
|
||||
let conf = Self::get_pagestream_throttle_config(self.conf, new_conf);
|
||||
self.pagestream_throttle.reconfigure(conf)
|
||||
}
|
||||
@@ -5095,17 +5091,14 @@ impl Tenant {
|
||||
fs::remove_dir_all(&pgdata_path).with_context(|| {
|
||||
format!("Failed to remove already existing initdb directory: {pgdata_path}")
|
||||
})?;
|
||||
tracing::info!("removed previous attempt's temporary initdb directory '{pgdata_path}'");
|
||||
}
|
||||
|
||||
// this new directory is very temporary, set to remove it immediately after bootstrap, we don't need it
|
||||
let pgdata_path_deferred = pgdata_path.clone();
|
||||
scopeguard::defer! {
|
||||
if let Err(e) = fs::remove_dir_all(&pgdata_path_deferred).or_else(fs_ext::ignore_not_found) {
|
||||
if let Err(e) = fs::remove_dir_all(&pgdata_path_deferred) {
|
||||
// this is unlikely, but we will remove the directory on pageserver restart or another bootstrap call
|
||||
error!("Failed to remove temporary initdb directory '{pgdata_path_deferred}': {e}");
|
||||
} else {
|
||||
tracing::info!("removed temporary initdb directory '{pgdata_path_deferred}'");
|
||||
}
|
||||
}
|
||||
if let Some(existing_initdb_timeline_id) = load_existing_initdb {
|
||||
@@ -5499,7 +5492,7 @@ impl Tenant {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn get_tenant_conf(&self) -> pageserver_api::models::TenantConfig {
|
||||
pub(crate) fn get_tenant_conf(&self) -> TenantConfOpt {
|
||||
self.tenant_conf.load().tenant_conf.clone()
|
||||
}
|
||||
|
||||
@@ -5689,9 +5682,59 @@ pub(crate) mod harness {
|
||||
buf.freeze()
|
||||
}
|
||||
|
||||
impl From<TenantConf> for TenantConfOpt {
|
||||
fn from(tenant_conf: TenantConf) -> Self {
|
||||
Self {
|
||||
checkpoint_distance: Some(tenant_conf.checkpoint_distance),
|
||||
checkpoint_timeout: Some(tenant_conf.checkpoint_timeout),
|
||||
compaction_target_size: Some(tenant_conf.compaction_target_size),
|
||||
compaction_period: Some(tenant_conf.compaction_period),
|
||||
compaction_threshold: Some(tenant_conf.compaction_threshold),
|
||||
compaction_upper_limit: Some(tenant_conf.compaction_upper_limit),
|
||||
compaction_algorithm: Some(tenant_conf.compaction_algorithm),
|
||||
compaction_l0_first: Some(tenant_conf.compaction_l0_first),
|
||||
compaction_l0_semaphore: Some(tenant_conf.compaction_l0_semaphore),
|
||||
l0_flush_delay_threshold: tenant_conf.l0_flush_delay_threshold,
|
||||
l0_flush_stall_threshold: tenant_conf.l0_flush_stall_threshold,
|
||||
l0_flush_wait_upload: Some(tenant_conf.l0_flush_wait_upload),
|
||||
gc_horizon: Some(tenant_conf.gc_horizon),
|
||||
gc_period: Some(tenant_conf.gc_period),
|
||||
image_creation_threshold: Some(tenant_conf.image_creation_threshold),
|
||||
pitr_interval: Some(tenant_conf.pitr_interval),
|
||||
walreceiver_connect_timeout: Some(tenant_conf.walreceiver_connect_timeout),
|
||||
lagging_wal_timeout: Some(tenant_conf.lagging_wal_timeout),
|
||||
max_lsn_wal_lag: Some(tenant_conf.max_lsn_wal_lag),
|
||||
eviction_policy: Some(tenant_conf.eviction_policy),
|
||||
min_resident_size_override: tenant_conf.min_resident_size_override,
|
||||
evictions_low_residence_duration_metric_threshold: Some(
|
||||
tenant_conf.evictions_low_residence_duration_metric_threshold,
|
||||
),
|
||||
heatmap_period: Some(tenant_conf.heatmap_period),
|
||||
lazy_slru_download: Some(tenant_conf.lazy_slru_download),
|
||||
timeline_get_throttle: Some(tenant_conf.timeline_get_throttle),
|
||||
image_layer_creation_check_threshold: Some(
|
||||
tenant_conf.image_layer_creation_check_threshold,
|
||||
),
|
||||
image_creation_preempt_threshold: Some(
|
||||
tenant_conf.image_creation_preempt_threshold,
|
||||
),
|
||||
lsn_lease_length: Some(tenant_conf.lsn_lease_length),
|
||||
lsn_lease_length_for_ts: Some(tenant_conf.lsn_lease_length_for_ts),
|
||||
timeline_offloading: Some(tenant_conf.timeline_offloading),
|
||||
wal_receiver_protocol_override: tenant_conf.wal_receiver_protocol_override,
|
||||
rel_size_v2_enabled: Some(tenant_conf.rel_size_v2_enabled),
|
||||
gc_compaction_enabled: Some(tenant_conf.gc_compaction_enabled),
|
||||
gc_compaction_initial_threshold_kb: Some(
|
||||
tenant_conf.gc_compaction_initial_threshold_kb,
|
||||
),
|
||||
gc_compaction_ratio_percent: Some(tenant_conf.gc_compaction_ratio_percent),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TenantHarness {
|
||||
pub conf: &'static PageServerConf,
|
||||
pub tenant_conf: pageserver_api::models::TenantConfig,
|
||||
pub tenant_conf: TenantConf,
|
||||
pub tenant_shard_id: TenantShardId,
|
||||
pub generation: Generation,
|
||||
pub shard: ShardIndex,
|
||||
@@ -5718,7 +5761,7 @@ pub(crate) mod harness {
|
||||
impl TenantHarness {
|
||||
pub async fn create_custom(
|
||||
test_name: &'static str,
|
||||
tenant_conf: pageserver_api::models::TenantConfig,
|
||||
tenant_conf: TenantConf,
|
||||
tenant_id: TenantId,
|
||||
shard_identity: ShardIdentity,
|
||||
generation: Generation,
|
||||
@@ -5771,10 +5814,10 @@ pub(crate) mod harness {
|
||||
pub async fn create(test_name: &'static str) -> anyhow::Result<Self> {
|
||||
// Disable automatic GC and compaction to make the unit tests more deterministic.
|
||||
// The tests perform them manually if needed.
|
||||
let tenant_conf = pageserver_api::models::TenantConfig {
|
||||
gc_period: Some(Duration::ZERO),
|
||||
compaction_period: Some(Duration::ZERO),
|
||||
..Default::default()
|
||||
let tenant_conf = TenantConf {
|
||||
gc_period: Duration::ZERO,
|
||||
compaction_period: Duration::ZERO,
|
||||
..TenantConf::default()
|
||||
};
|
||||
let tenant_id = TenantId::generate();
|
||||
let shard = ShardIdentity::unsharded();
|
||||
@@ -5814,7 +5857,7 @@ pub(crate) mod harness {
|
||||
TenantState::Attaching,
|
||||
self.conf,
|
||||
AttachedTenantConf::try_from(LocationConf::attached_single(
|
||||
self.tenant_conf.clone(),
|
||||
TenantConfOpt::from(self.tenant_conf.clone()),
|
||||
self.generation,
|
||||
&ShardParameters::default(),
|
||||
))
|
||||
@@ -6898,14 +6941,14 @@ mod tests {
|
||||
// ```
|
||||
#[tokio::test]
|
||||
async fn test_get_vectored_key_gap() -> anyhow::Result<()> {
|
||||
let tenant_conf = pageserver_api::models::TenantConfig {
|
||||
let tenant_conf = TenantConf {
|
||||
// Make compaction deterministic
|
||||
gc_period: Some(Duration::ZERO),
|
||||
compaction_period: Some(Duration::ZERO),
|
||||
gc_period: Duration::ZERO,
|
||||
compaction_period: Duration::ZERO,
|
||||
// Encourage creation of L1 layers
|
||||
checkpoint_distance: Some(16 * 1024),
|
||||
compaction_target_size: Some(8 * 1024),
|
||||
..Default::default()
|
||||
checkpoint_distance: 16 * 1024,
|
||||
compaction_target_size: 8 * 1024,
|
||||
..TenantConf::default()
|
||||
};
|
||||
|
||||
let harness = TenantHarness::create_custom(
|
||||
@@ -7211,9 +7254,9 @@ mod tests {
|
||||
compaction_algorithm: CompactionAlgorithm,
|
||||
) -> anyhow::Result<()> {
|
||||
let mut harness = TenantHarness::create(name).await?;
|
||||
harness.tenant_conf.compaction_algorithm = Some(CompactionAlgorithmSettings {
|
||||
harness.tenant_conf.compaction_algorithm = CompactionAlgorithmSettings {
|
||||
kind: compaction_algorithm,
|
||||
});
|
||||
};
|
||||
let (tenant, ctx) = harness.load().await;
|
||||
let tline = tenant
|
||||
.create_test_timeline(TIMELINE_ID, Lsn(0x10), DEFAULT_PG_VERSION, &ctx)
|
||||
@@ -7580,9 +7623,9 @@ mod tests {
|
||||
compaction_algorithm: CompactionAlgorithm,
|
||||
) -> anyhow::Result<()> {
|
||||
let mut harness = TenantHarness::create(name).await?;
|
||||
harness.tenant_conf.compaction_algorithm = Some(CompactionAlgorithmSettings {
|
||||
harness.tenant_conf.compaction_algorithm = CompactionAlgorithmSettings {
|
||||
kind: compaction_algorithm,
|
||||
});
|
||||
};
|
||||
let (tenant, ctx) = harness.load().await;
|
||||
let tline = tenant
|
||||
.create_test_timeline(TIMELINE_ID, Lsn(0x08), DEFAULT_PG_VERSION, &ctx)
|
||||
|
||||
@@ -8,11 +8,19 @@
|
||||
//! We cannot use global or default config instead, because wrong settings
|
||||
//! may lead to a data loss.
|
||||
//!
|
||||
use std::num::NonZeroU64;
|
||||
use std::time::Duration;
|
||||
|
||||
use pageserver_api::models;
|
||||
pub(crate) use pageserver_api::config::TenantConfigToml as TenantConf;
|
||||
use pageserver_api::models::{
|
||||
self, CompactionAlgorithmSettings, EvictionPolicy, TenantConfigPatch,
|
||||
};
|
||||
use pageserver_api::shard::{ShardCount, ShardIdentity, ShardNumber, ShardStripeSize};
|
||||
use serde::de::IntoDeserializer;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use utils::generation::Generation;
|
||||
use utils::postgres_client::PostgresClientProtocol;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub(crate) enum AttachmentMode {
|
||||
@@ -66,7 +74,7 @@ pub(crate) struct LocationConf {
|
||||
pub(crate) shard: ShardIdentity,
|
||||
|
||||
/// The pan-cluster tenant configuration, the same on all locations
|
||||
pub(crate) tenant_conf: pageserver_api::models::TenantConfig,
|
||||
pub(crate) tenant_conf: TenantConfOpt,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for LocationConf {
|
||||
@@ -132,7 +140,7 @@ impl LocationConf {
|
||||
/// implies it is in AttachmentMode::Single, which used to be the only
|
||||
/// possible state. This function should eventually be removed.
|
||||
pub(crate) fn attached_single(
|
||||
tenant_conf: pageserver_api::models::TenantConfig,
|
||||
tenant_conf: TenantConfOpt,
|
||||
generation: Generation,
|
||||
shard_params: &models::ShardParameters,
|
||||
) -> Self {
|
||||
@@ -166,7 +174,7 @@ impl LocationConf {
|
||||
}
|
||||
|
||||
pub(crate) fn try_from(conf: &'_ models::LocationConfig) -> anyhow::Result<Self> {
|
||||
let tenant_conf = conf.tenant_conf.clone();
|
||||
let tenant_conf = TenantConfOpt::try_from(&conf.tenant_conf)?;
|
||||
|
||||
fn get_generation(conf: &'_ models::LocationConfig) -> Result<Generation, anyhow::Error> {
|
||||
conf.generation
|
||||
@@ -242,19 +250,509 @@ impl Default for LocationConf {
|
||||
generation: Generation::none(),
|
||||
attach_mode: AttachmentMode::Single,
|
||||
}),
|
||||
tenant_conf: pageserver_api::models::TenantConfig::default(),
|
||||
tenant_conf: TenantConfOpt::default(),
|
||||
shard: ShardIdentity::unsharded(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as TenantConf, but this struct preserves the information about
|
||||
/// which parameters are set and which are not.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
pub struct TenantConfOpt {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub checkpoint_distance: Option<u64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(with = "humantime_serde")]
|
||||
#[serde(default)]
|
||||
pub checkpoint_timeout: Option<Duration>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub compaction_target_size: Option<u64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(with = "humantime_serde")]
|
||||
#[serde(default)]
|
||||
pub compaction_period: Option<Duration>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub compaction_threshold: Option<usize>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub compaction_upper_limit: Option<usize>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub compaction_algorithm: Option<CompactionAlgorithmSettings>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub compaction_l0_first: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub compaction_l0_semaphore: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub l0_flush_delay_threshold: Option<usize>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub l0_flush_stall_threshold: Option<usize>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub l0_flush_wait_upload: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub gc_horizon: Option<u64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(with = "humantime_serde")]
|
||||
#[serde(default)]
|
||||
pub gc_period: Option<Duration>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub image_creation_threshold: Option<usize>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(with = "humantime_serde")]
|
||||
#[serde(default)]
|
||||
pub pitr_interval: Option<Duration>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(with = "humantime_serde")]
|
||||
#[serde(default)]
|
||||
pub walreceiver_connect_timeout: Option<Duration>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(with = "humantime_serde")]
|
||||
#[serde(default)]
|
||||
pub lagging_wal_timeout: Option<Duration>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub max_lsn_wal_lag: Option<NonZeroU64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub eviction_policy: Option<EvictionPolicy>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub min_resident_size_override: Option<u64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(with = "humantime_serde")]
|
||||
#[serde(default)]
|
||||
pub evictions_low_residence_duration_metric_threshold: Option<Duration>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(with = "humantime_serde")]
|
||||
#[serde(default)]
|
||||
pub heatmap_period: Option<Duration>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub lazy_slru_download: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub timeline_get_throttle: Option<pageserver_api::models::ThrottleConfig>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_layer_creation_check_threshold: Option<u8>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image_creation_preempt_threshold: Option<usize>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(with = "humantime_serde")]
|
||||
#[serde(default)]
|
||||
pub lsn_lease_length: Option<Duration>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(with = "humantime_serde")]
|
||||
#[serde(default)]
|
||||
pub lsn_lease_length_for_ts: Option<Duration>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(default)]
|
||||
pub timeline_offloading: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub wal_receiver_protocol_override: Option<PostgresClientProtocol>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub rel_size_v2_enabled: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub gc_compaction_enabled: Option<bool>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub gc_compaction_initial_threshold_kb: Option<u64>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub gc_compaction_ratio_percent: Option<u64>,
|
||||
}
|
||||
|
||||
impl TenantConfOpt {
|
||||
pub fn merge(&self, global_conf: TenantConf) -> TenantConf {
|
||||
TenantConf {
|
||||
checkpoint_distance: self
|
||||
.checkpoint_distance
|
||||
.unwrap_or(global_conf.checkpoint_distance),
|
||||
checkpoint_timeout: self
|
||||
.checkpoint_timeout
|
||||
.unwrap_or(global_conf.checkpoint_timeout),
|
||||
compaction_target_size: self
|
||||
.compaction_target_size
|
||||
.unwrap_or(global_conf.compaction_target_size),
|
||||
compaction_period: self
|
||||
.compaction_period
|
||||
.unwrap_or(global_conf.compaction_period),
|
||||
compaction_threshold: self
|
||||
.compaction_threshold
|
||||
.unwrap_or(global_conf.compaction_threshold),
|
||||
compaction_upper_limit: self
|
||||
.compaction_upper_limit
|
||||
.unwrap_or(global_conf.compaction_upper_limit),
|
||||
compaction_algorithm: self
|
||||
.compaction_algorithm
|
||||
.as_ref()
|
||||
.unwrap_or(&global_conf.compaction_algorithm)
|
||||
.clone(),
|
||||
compaction_l0_first: self
|
||||
.compaction_l0_first
|
||||
.unwrap_or(global_conf.compaction_l0_first),
|
||||
compaction_l0_semaphore: self
|
||||
.compaction_l0_semaphore
|
||||
.unwrap_or(global_conf.compaction_l0_semaphore),
|
||||
l0_flush_delay_threshold: self
|
||||
.l0_flush_delay_threshold
|
||||
.or(global_conf.l0_flush_delay_threshold),
|
||||
l0_flush_stall_threshold: self
|
||||
.l0_flush_stall_threshold
|
||||
.or(global_conf.l0_flush_stall_threshold),
|
||||
l0_flush_wait_upload: self
|
||||
.l0_flush_wait_upload
|
||||
.unwrap_or(global_conf.l0_flush_wait_upload),
|
||||
gc_horizon: self.gc_horizon.unwrap_or(global_conf.gc_horizon),
|
||||
gc_period: self.gc_period.unwrap_or(global_conf.gc_period),
|
||||
image_creation_threshold: self
|
||||
.image_creation_threshold
|
||||
.unwrap_or(global_conf.image_creation_threshold),
|
||||
pitr_interval: self.pitr_interval.unwrap_or(global_conf.pitr_interval),
|
||||
walreceiver_connect_timeout: self
|
||||
.walreceiver_connect_timeout
|
||||
.unwrap_or(global_conf.walreceiver_connect_timeout),
|
||||
lagging_wal_timeout: self
|
||||
.lagging_wal_timeout
|
||||
.unwrap_or(global_conf.lagging_wal_timeout),
|
||||
max_lsn_wal_lag: self.max_lsn_wal_lag.unwrap_or(global_conf.max_lsn_wal_lag),
|
||||
eviction_policy: self.eviction_policy.unwrap_or(global_conf.eviction_policy),
|
||||
min_resident_size_override: self
|
||||
.min_resident_size_override
|
||||
.or(global_conf.min_resident_size_override),
|
||||
evictions_low_residence_duration_metric_threshold: self
|
||||
.evictions_low_residence_duration_metric_threshold
|
||||
.unwrap_or(global_conf.evictions_low_residence_duration_metric_threshold),
|
||||
heatmap_period: self.heatmap_period.unwrap_or(global_conf.heatmap_period),
|
||||
lazy_slru_download: self
|
||||
.lazy_slru_download
|
||||
.unwrap_or(global_conf.lazy_slru_download),
|
||||
timeline_get_throttle: self
|
||||
.timeline_get_throttle
|
||||
.clone()
|
||||
.unwrap_or(global_conf.timeline_get_throttle),
|
||||
image_layer_creation_check_threshold: self
|
||||
.image_layer_creation_check_threshold
|
||||
.unwrap_or(global_conf.image_layer_creation_check_threshold),
|
||||
image_creation_preempt_threshold: self
|
||||
.image_creation_preempt_threshold
|
||||
.unwrap_or(global_conf.image_creation_preempt_threshold),
|
||||
lsn_lease_length: self
|
||||
.lsn_lease_length
|
||||
.unwrap_or(global_conf.lsn_lease_length),
|
||||
lsn_lease_length_for_ts: self
|
||||
.lsn_lease_length_for_ts
|
||||
.unwrap_or(global_conf.lsn_lease_length_for_ts),
|
||||
timeline_offloading: self
|
||||
.timeline_offloading
|
||||
.unwrap_or(global_conf.timeline_offloading),
|
||||
wal_receiver_protocol_override: self
|
||||
.wal_receiver_protocol_override
|
||||
.or(global_conf.wal_receiver_protocol_override),
|
||||
rel_size_v2_enabled: self
|
||||
.rel_size_v2_enabled
|
||||
.unwrap_or(global_conf.rel_size_v2_enabled),
|
||||
gc_compaction_enabled: self
|
||||
.gc_compaction_enabled
|
||||
.unwrap_or(global_conf.gc_compaction_enabled),
|
||||
gc_compaction_initial_threshold_kb: self
|
||||
.gc_compaction_initial_threshold_kb
|
||||
.unwrap_or(global_conf.gc_compaction_initial_threshold_kb),
|
||||
gc_compaction_ratio_percent: self
|
||||
.gc_compaction_ratio_percent
|
||||
.unwrap_or(global_conf.gc_compaction_ratio_percent),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_patch(self, patch: TenantConfigPatch) -> anyhow::Result<TenantConfOpt> {
|
||||
let Self {
|
||||
mut checkpoint_distance,
|
||||
mut checkpoint_timeout,
|
||||
mut compaction_target_size,
|
||||
mut compaction_period,
|
||||
mut compaction_threshold,
|
||||
mut compaction_upper_limit,
|
||||
mut compaction_algorithm,
|
||||
mut compaction_l0_first,
|
||||
mut compaction_l0_semaphore,
|
||||
mut l0_flush_delay_threshold,
|
||||
mut l0_flush_stall_threshold,
|
||||
mut l0_flush_wait_upload,
|
||||
mut gc_horizon,
|
||||
mut gc_period,
|
||||
mut image_creation_threshold,
|
||||
mut pitr_interval,
|
||||
mut walreceiver_connect_timeout,
|
||||
mut lagging_wal_timeout,
|
||||
mut max_lsn_wal_lag,
|
||||
mut eviction_policy,
|
||||
mut min_resident_size_override,
|
||||
mut evictions_low_residence_duration_metric_threshold,
|
||||
mut heatmap_period,
|
||||
mut lazy_slru_download,
|
||||
mut timeline_get_throttle,
|
||||
mut image_layer_creation_check_threshold,
|
||||
mut image_creation_preempt_threshold,
|
||||
mut lsn_lease_length,
|
||||
mut lsn_lease_length_for_ts,
|
||||
mut timeline_offloading,
|
||||
mut wal_receiver_protocol_override,
|
||||
mut rel_size_v2_enabled,
|
||||
mut gc_compaction_enabled,
|
||||
mut gc_compaction_initial_threshold_kb,
|
||||
mut gc_compaction_ratio_percent,
|
||||
} = self;
|
||||
|
||||
patch.checkpoint_distance.apply(&mut checkpoint_distance);
|
||||
patch
|
||||
.checkpoint_timeout
|
||||
.map(|v| humantime::parse_duration(&v))?
|
||||
.apply(&mut checkpoint_timeout);
|
||||
patch
|
||||
.compaction_target_size
|
||||
.apply(&mut compaction_target_size);
|
||||
patch
|
||||
.compaction_period
|
||||
.map(|v| humantime::parse_duration(&v))?
|
||||
.apply(&mut compaction_period);
|
||||
patch.compaction_threshold.apply(&mut compaction_threshold);
|
||||
patch
|
||||
.compaction_upper_limit
|
||||
.apply(&mut compaction_upper_limit);
|
||||
patch.compaction_algorithm.apply(&mut compaction_algorithm);
|
||||
patch.compaction_l0_first.apply(&mut compaction_l0_first);
|
||||
patch
|
||||
.compaction_l0_semaphore
|
||||
.apply(&mut compaction_l0_semaphore);
|
||||
patch
|
||||
.l0_flush_delay_threshold
|
||||
.apply(&mut l0_flush_delay_threshold);
|
||||
patch
|
||||
.l0_flush_stall_threshold
|
||||
.apply(&mut l0_flush_stall_threshold);
|
||||
patch.l0_flush_wait_upload.apply(&mut l0_flush_wait_upload);
|
||||
patch.gc_horizon.apply(&mut gc_horizon);
|
||||
patch
|
||||
.gc_period
|
||||
.map(|v| humantime::parse_duration(&v))?
|
||||
.apply(&mut gc_period);
|
||||
patch
|
||||
.image_creation_threshold
|
||||
.apply(&mut image_creation_threshold);
|
||||
patch
|
||||
.pitr_interval
|
||||
.map(|v| humantime::parse_duration(&v))?
|
||||
.apply(&mut pitr_interval);
|
||||
patch
|
||||
.walreceiver_connect_timeout
|
||||
.map(|v| humantime::parse_duration(&v))?
|
||||
.apply(&mut walreceiver_connect_timeout);
|
||||
patch
|
||||
.lagging_wal_timeout
|
||||
.map(|v| humantime::parse_duration(&v))?
|
||||
.apply(&mut lagging_wal_timeout);
|
||||
patch.max_lsn_wal_lag.apply(&mut max_lsn_wal_lag);
|
||||
patch.eviction_policy.apply(&mut eviction_policy);
|
||||
patch
|
||||
.min_resident_size_override
|
||||
.apply(&mut min_resident_size_override);
|
||||
patch
|
||||
.evictions_low_residence_duration_metric_threshold
|
||||
.map(|v| humantime::parse_duration(&v))?
|
||||
.apply(&mut evictions_low_residence_duration_metric_threshold);
|
||||
patch
|
||||
.heatmap_period
|
||||
.map(|v| humantime::parse_duration(&v))?
|
||||
.apply(&mut heatmap_period);
|
||||
patch.lazy_slru_download.apply(&mut lazy_slru_download);
|
||||
patch
|
||||
.timeline_get_throttle
|
||||
.apply(&mut timeline_get_throttle);
|
||||
patch
|
||||
.image_layer_creation_check_threshold
|
||||
.apply(&mut image_layer_creation_check_threshold);
|
||||
patch
|
||||
.image_creation_preempt_threshold
|
||||
.apply(&mut image_creation_preempt_threshold);
|
||||
patch
|
||||
.lsn_lease_length
|
||||
.map(|v| humantime::parse_duration(&v))?
|
||||
.apply(&mut lsn_lease_length);
|
||||
patch
|
||||
.lsn_lease_length_for_ts
|
||||
.map(|v| humantime::parse_duration(&v))?
|
||||
.apply(&mut lsn_lease_length_for_ts);
|
||||
patch.timeline_offloading.apply(&mut timeline_offloading);
|
||||
patch
|
||||
.wal_receiver_protocol_override
|
||||
.apply(&mut wal_receiver_protocol_override);
|
||||
patch.rel_size_v2_enabled.apply(&mut rel_size_v2_enabled);
|
||||
patch
|
||||
.gc_compaction_enabled
|
||||
.apply(&mut gc_compaction_enabled);
|
||||
patch
|
||||
.gc_compaction_initial_threshold_kb
|
||||
.apply(&mut gc_compaction_initial_threshold_kb);
|
||||
patch
|
||||
.gc_compaction_ratio_percent
|
||||
.apply(&mut gc_compaction_ratio_percent);
|
||||
|
||||
Ok(Self {
|
||||
checkpoint_distance,
|
||||
checkpoint_timeout,
|
||||
compaction_target_size,
|
||||
compaction_period,
|
||||
compaction_threshold,
|
||||
compaction_upper_limit,
|
||||
compaction_algorithm,
|
||||
compaction_l0_first,
|
||||
compaction_l0_semaphore,
|
||||
l0_flush_delay_threshold,
|
||||
l0_flush_stall_threshold,
|
||||
l0_flush_wait_upload,
|
||||
gc_horizon,
|
||||
gc_period,
|
||||
image_creation_threshold,
|
||||
pitr_interval,
|
||||
walreceiver_connect_timeout,
|
||||
lagging_wal_timeout,
|
||||
max_lsn_wal_lag,
|
||||
eviction_policy,
|
||||
min_resident_size_override,
|
||||
evictions_low_residence_duration_metric_threshold,
|
||||
heatmap_period,
|
||||
lazy_slru_download,
|
||||
timeline_get_throttle,
|
||||
image_layer_creation_check_threshold,
|
||||
image_creation_preempt_threshold,
|
||||
lsn_lease_length,
|
||||
lsn_lease_length_for_ts,
|
||||
timeline_offloading,
|
||||
wal_receiver_protocol_override,
|
||||
rel_size_v2_enabled,
|
||||
gc_compaction_enabled,
|
||||
gc_compaction_initial_threshold_kb,
|
||||
gc_compaction_ratio_percent,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&'_ models::TenantConfig> for TenantConfOpt {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(request_data: &'_ models::TenantConfig) -> Result<Self, Self::Error> {
|
||||
// Convert the request_data to a JSON Value
|
||||
let json_value: Value = serde_json::to_value(request_data)?;
|
||||
|
||||
// Create a Deserializer from the JSON Value
|
||||
let deserializer = json_value.into_deserializer();
|
||||
|
||||
// Use serde_path_to_error to deserialize the JSON Value into TenantConfOpt
|
||||
let tenant_conf: TenantConfOpt = serde_path_to_error::deserialize(deserializer)?;
|
||||
|
||||
Ok(tenant_conf)
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a conversion from our internal tenant config object to the one used
|
||||
/// in external APIs.
|
||||
impl From<TenantConfOpt> for models::TenantConfig {
|
||||
// TODO(vlad): These are now the same, but they have different serialization logic.
|
||||
// Can we merge them?
|
||||
fn from(value: TenantConfOpt) -> Self {
|
||||
Self {
|
||||
checkpoint_distance: value.checkpoint_distance,
|
||||
checkpoint_timeout: value.checkpoint_timeout,
|
||||
compaction_algorithm: value.compaction_algorithm,
|
||||
compaction_target_size: value.compaction_target_size,
|
||||
compaction_period: value.compaction_period,
|
||||
compaction_threshold: value.compaction_threshold,
|
||||
compaction_upper_limit: value.compaction_upper_limit,
|
||||
compaction_l0_first: value.compaction_l0_first,
|
||||
compaction_l0_semaphore: value.compaction_l0_semaphore,
|
||||
l0_flush_delay_threshold: value.l0_flush_delay_threshold,
|
||||
l0_flush_stall_threshold: value.l0_flush_stall_threshold,
|
||||
l0_flush_wait_upload: value.l0_flush_wait_upload,
|
||||
gc_horizon: value.gc_horizon,
|
||||
gc_period: value.gc_period,
|
||||
image_creation_threshold: value.image_creation_threshold,
|
||||
pitr_interval: value.pitr_interval,
|
||||
walreceiver_connect_timeout: value.walreceiver_connect_timeout,
|
||||
lagging_wal_timeout: value.lagging_wal_timeout,
|
||||
max_lsn_wal_lag: value.max_lsn_wal_lag,
|
||||
eviction_policy: value.eviction_policy,
|
||||
min_resident_size_override: value.min_resident_size_override,
|
||||
evictions_low_residence_duration_metric_threshold: value
|
||||
.evictions_low_residence_duration_metric_threshold,
|
||||
heatmap_period: value.heatmap_period,
|
||||
lazy_slru_download: value.lazy_slru_download,
|
||||
timeline_get_throttle: value.timeline_get_throttle,
|
||||
image_layer_creation_check_threshold: value.image_layer_creation_check_threshold,
|
||||
image_creation_preempt_threshold: value.image_creation_preempt_threshold,
|
||||
lsn_lease_length: value.lsn_lease_length,
|
||||
lsn_lease_length_for_ts: value.lsn_lease_length_for_ts,
|
||||
timeline_offloading: value.timeline_offloading,
|
||||
wal_receiver_protocol_override: value.wal_receiver_protocol_override,
|
||||
rel_size_v2_enabled: value.rel_size_v2_enabled,
|
||||
gc_compaction_enabled: value.gc_compaction_enabled,
|
||||
gc_compaction_initial_threshold_kb: value.gc_compaction_initial_threshold_kb,
|
||||
gc_compaction_ratio_percent: value.gc_compaction_ratio_percent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use models::TenantConfig;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn serde_roundtrip_tenant_conf_opt() {
|
||||
let small_conf = pageserver_api::models::TenantConfig {
|
||||
fn de_serializing_pageserver_config_omits_empty_values() {
|
||||
let small_conf = TenantConfOpt {
|
||||
gc_horizon: Some(42),
|
||||
..Default::default()
|
||||
..TenantConfOpt::default()
|
||||
};
|
||||
|
||||
let toml_form = toml_edit::ser::to_string(&small_conf).unwrap();
|
||||
@@ -265,4 +763,19 @@ mod tests {
|
||||
assert_eq!(json_form, "{\"gc_horizon\":42}");
|
||||
assert_eq!(small_conf, serde_json::from_str(&json_form).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try_from_models_tenant_config_success() {
|
||||
let tenant_config = models::TenantConfig {
|
||||
lagging_wal_timeout: Some(Duration::from_secs(5)),
|
||||
..TenantConfig::default()
|
||||
};
|
||||
|
||||
let tenant_conf_opt = TenantConfOpt::try_from(&tenant_config).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
tenant_conf_opt.lagging_wal_timeout,
|
||||
Some(Duration::from_secs(5))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ use super::{GlobalShutDown, TenantSharedResources};
|
||||
use crate::config::PageServerConf;
|
||||
use crate::context::{DownloadBehavior, RequestContext};
|
||||
use crate::controller_upcall_client::{
|
||||
RetryForeverError, StorageControllerUpcallApi, StorageControllerUpcallClient,
|
||||
ControlPlaneGenerationsApi, ControllerUpcallClient, RetryForeverError,
|
||||
};
|
||||
use crate::deletion_queue::DeletionQueueClient;
|
||||
use crate::http::routes::ACTIVE_TENANT_TIMEOUT;
|
||||
@@ -344,7 +344,7 @@ async fn init_load_generations(
|
||||
"Emergency mode! Tenants will be attached unsafely using their last known generation"
|
||||
);
|
||||
emergency_generations(tenant_confs)
|
||||
} else if let Some(client) = StorageControllerUpcallClient::new(conf, cancel) {
|
||||
} else if let Some(client) = ControllerUpcallClient::new(conf, cancel) {
|
||||
info!("Calling {} API to re-attach tenants", client.base_url());
|
||||
// If we are configured to use the control plane API, then it is the source of truth for what tenants to load.
|
||||
match client.re_attach(conf).await {
|
||||
|
||||
@@ -20,7 +20,7 @@ use utils::sync::gate::Gate;
|
||||
use self::downloader::{SecondaryDetail, downloader_task};
|
||||
use self::heatmap_uploader::heatmap_uploader_task;
|
||||
use super::GetTenantError;
|
||||
use super::config::SecondaryLocationConfig;
|
||||
use super::config::{SecondaryLocationConfig, TenantConfOpt};
|
||||
use super::mgr::TenantManager;
|
||||
use super::span::debug_assert_current_span_has_tenant_id;
|
||||
use super::storage_layer::LayerName;
|
||||
@@ -98,11 +98,11 @@ pub(crate) struct SecondaryTenant {
|
||||
|
||||
pub(crate) gate: Gate,
|
||||
|
||||
// Secondary mode does not need the full shard identity or the pageserver_api::models::TenantConfig. However,
|
||||
// Secondary mode does not need the full shard identity or the TenantConfOpt. However,
|
||||
// storing these enables us to report our full LocationConf, enabling convenient reconciliation
|
||||
// by the control plane (see [`Self::get_location_conf`])
|
||||
shard_identity: ShardIdentity,
|
||||
tenant_conf: std::sync::Mutex<pageserver_api::models::TenantConfig>,
|
||||
tenant_conf: std::sync::Mutex<TenantConfOpt>,
|
||||
|
||||
// Internal state used by the Downloader.
|
||||
detail: std::sync::Mutex<SecondaryDetail>,
|
||||
@@ -121,7 +121,7 @@ impl SecondaryTenant {
|
||||
pub(crate) fn new(
|
||||
tenant_shard_id: TenantShardId,
|
||||
shard_identity: ShardIdentity,
|
||||
tenant_conf: pageserver_api::models::TenantConfig,
|
||||
tenant_conf: TenantConfOpt,
|
||||
config: &SecondaryLocationConfig,
|
||||
) -> Arc<Self> {
|
||||
let tenant_id = tenant_shard_id.tenant_id.to_string();
|
||||
@@ -177,7 +177,7 @@ impl SecondaryTenant {
|
||||
self.detail.lock().unwrap().config = config.clone();
|
||||
}
|
||||
|
||||
pub(crate) fn set_tenant_conf(&self, config: &pageserver_api::models::TenantConfig) {
|
||||
pub(crate) fn set_tenant_conf(&self, config: &TenantConfOpt) {
|
||||
*(self.tenant_conf.lock().unwrap()) = config.clone();
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ impl SecondaryTenant {
|
||||
shard_number: self.tenant_shard_id.shard_number.0,
|
||||
shard_count: self.tenant_shard_id.shard_count.literal(),
|
||||
shard_stripe_size: self.shard_identity.stripe_size.0,
|
||||
tenant_conf,
|
||||
tenant_conf: tenant_conf.into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1148,6 +1148,7 @@ mod test {
|
||||
use super::{ImageLayerIterator, ImageLayerWriter};
|
||||
use crate::DEFAULT_PG_VERSION;
|
||||
use crate::context::RequestContext;
|
||||
use crate::tenant::config::TenantConf;
|
||||
use crate::tenant::harness::{TIMELINE_ID, TenantHarness};
|
||||
use crate::tenant::storage_layer::{Layer, ResidentLayer};
|
||||
use crate::tenant::vectored_blob_io::StreamingVectoredReadPlanner;
|
||||
@@ -1155,10 +1156,10 @@ mod test {
|
||||
|
||||
#[tokio::test]
|
||||
async fn image_layer_rewrite() {
|
||||
let tenant_conf = pageserver_api::models::TenantConfig {
|
||||
gc_period: Some(Duration::ZERO),
|
||||
compaction_period: Some(Duration::ZERO),
|
||||
..Default::default()
|
||||
let tenant_conf = TenantConf {
|
||||
gc_period: Duration::ZERO,
|
||||
compaction_period: Duration::ZERO,
|
||||
..TenantConf::default()
|
||||
};
|
||||
let tenant_id = TenantId::generate();
|
||||
let mut gen_ = Generation::new(0xdead0001);
|
||||
|
||||
@@ -84,6 +84,7 @@ use self::eviction_task::EvictionTaskTimelineState;
|
||||
use self::layer_manager::LayerManager;
|
||||
use self::logical_size::LogicalSize;
|
||||
use self::walreceiver::{WalReceiver, WalReceiverConf};
|
||||
use super::config::TenantConf;
|
||||
use super::remote_timeline_client::index::{GcCompactionState, IndexPart};
|
||||
use super::remote_timeline_client::{RemoteTimelineClient, WaitCompletionError};
|
||||
use super::secondary::heatmap::HeatMapLayer;
|
||||
@@ -110,7 +111,7 @@ use crate::pgdatadir_mapping::{
|
||||
MAX_AUX_FILE_V2_DELTAS, MetricsUpdate,
|
||||
};
|
||||
use crate::task_mgr::TaskKind;
|
||||
use crate::tenant::config::AttachmentMode;
|
||||
use crate::tenant::config::{AttachmentMode, TenantConfOpt};
|
||||
use crate::tenant::gc_result::GcResult;
|
||||
use crate::tenant::layer_map::{LayerMap, SearchResult};
|
||||
use crate::tenant::metadata::TimelineMetadata;
|
||||
@@ -535,11 +536,11 @@ impl GcInfo {
|
||||
/// between time-based and space-based retention for observability and consumption metrics purposes.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct GcCutoffs {
|
||||
/// Calculated from the [`pageserver_api::models::TenantConfig::gc_horizon`], this LSN indicates how much
|
||||
/// Calculated from the [`TenantConf::gc_horizon`], this LSN indicates how much
|
||||
/// history we must keep to retain a specified number of bytes of WAL.
|
||||
pub(crate) space: Lsn,
|
||||
|
||||
/// Calculated from [`pageserver_api::models::TenantConfig::pitr_interval`], this LSN indicates how much
|
||||
/// Calculated from [`TenantConf::pitr_interval`], this LSN indicates how much
|
||||
/// history we must keep to enable reading back at least the PITR interval duration.
|
||||
pub(crate) time: Lsn,
|
||||
}
|
||||
@@ -2597,8 +2598,8 @@ impl Timeline {
|
||||
}
|
||||
|
||||
fn get_evictions_low_residence_duration_metric_threshold(
|
||||
tenant_conf: &pageserver_api::models::TenantConfig,
|
||||
default_tenant_conf: &pageserver_api::config::TenantConfigToml,
|
||||
tenant_conf: &TenantConfOpt,
|
||||
default_tenant_conf: &TenantConf,
|
||||
) -> Duration {
|
||||
tenant_conf
|
||||
.evictions_low_residence_duration_metric_threshold
|
||||
|
||||
@@ -246,6 +246,859 @@ class NeonAPI:
|
||||
has_running = True
|
||||
time.sleep(0.5)
|
||||
|
||||
def get_operation(self, project_id: str, operation_id: str) -> dict[str, Any]:
|
||||
"""
|
||||
Retrieves a specific operation.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
operation_id: The operation ID
|
||||
|
||||
Returns:
|
||||
The API response containing the operation details
|
||||
"""
|
||||
resp = self.__request(
|
||||
"GET",
|
||||
f"/projects/{project_id}/operations/{operation_id}",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def list_projects(self) -> dict[str, Any]:
|
||||
"""
|
||||
Lists all projects.
|
||||
|
||||
Returns:
|
||||
The API response containing the list of projects
|
||||
"""
|
||||
resp = self.__request(
|
||||
"GET",
|
||||
"/projects",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def update_project(
|
||||
self,
|
||||
project_id: str,
|
||||
name: str | None = None,
|
||||
settings: dict[str, Any] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Updates a project.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
name: New name for the project (optional)
|
||||
settings: Project settings to update (optional)
|
||||
|
||||
Returns:
|
||||
The API response containing the updated project details
|
||||
"""
|
||||
data: dict[str, Any] = {
|
||||
"project": {},
|
||||
}
|
||||
|
||||
if name is not None:
|
||||
data["project"]["name"] = name
|
||||
|
||||
if settings is not None:
|
||||
data["project"]["settings"] = settings
|
||||
|
||||
resp = self.__request(
|
||||
"PATCH",
|
||||
f"/projects/{project_id}",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
json=data,
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def get_project_consumption(
|
||||
self,
|
||||
project_id: str,
|
||||
from_time: str | None = None,
|
||||
to_time: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Retrieves project consumption data.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
from_time: Start time for consumption data (optional)
|
||||
to_time: End time for consumption data (optional)
|
||||
|
||||
Returns:
|
||||
The API response containing the project consumption data
|
||||
"""
|
||||
params = {}
|
||||
if from_time is not None:
|
||||
params["from"] = from_time
|
||||
if to_time is not None:
|
||||
params["to"] = to_time
|
||||
|
||||
resp = self.__request(
|
||||
"GET",
|
||||
f"/projects/{project_id}/consumption",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
params=params,
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def get_project_vpc_endpoints(self, project_id: str) -> dict[str, Any]:
|
||||
"""
|
||||
Retrieves project VPC endpoints.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
|
||||
Returns:
|
||||
The API response containing the project VPC endpoints
|
||||
"""
|
||||
resp = self.__request(
|
||||
"GET",
|
||||
f"/projects/{project_id}/vpc_endpoints",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def create_branch(
|
||||
self,
|
||||
project_id: str,
|
||||
parent_id: str | None = None,
|
||||
name: str | None = None,
|
||||
endpoints: list[dict[str, Any]] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Creates a new branch.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
parent_id: The parent branch ID (optional)
|
||||
name: Name for the branch (optional)
|
||||
endpoints: List of endpoints to create with the branch (optional)
|
||||
|
||||
Returns:
|
||||
The API response containing the created branch details and operations
|
||||
"""
|
||||
data: dict[str, Any] = {
|
||||
"branch": {},
|
||||
}
|
||||
|
||||
if parent_id is not None:
|
||||
data["branch"]["parent_id"] = parent_id
|
||||
|
||||
if name is not None:
|
||||
data["branch"]["name"] = name
|
||||
|
||||
if endpoints is not None:
|
||||
data["endpoints"] = endpoints
|
||||
|
||||
resp = self.__request(
|
||||
"POST",
|
||||
f"/projects/{project_id}/branches",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
json=data,
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def get_branch_details(self, project_id: str, branch_id: str) -> dict[str, Any]:
|
||||
"""
|
||||
Retrieves details of a specific branch.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
branch_id: The branch ID
|
||||
|
||||
Returns:
|
||||
The API response containing the branch details
|
||||
"""
|
||||
resp = self.__request(
|
||||
"GET",
|
||||
f"/projects/{project_id}/branches/{branch_id}",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def update_branch(
|
||||
self,
|
||||
project_id: str,
|
||||
branch_id: str,
|
||||
name: str | None = None,
|
||||
default: bool | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Updates the specified branch.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
branch_id: The branch ID
|
||||
name: New name for the branch (optional)
|
||||
default: Whether to set this branch as the default branch (optional)
|
||||
|
||||
Returns:
|
||||
The API response containing the updated branch details and operations
|
||||
"""
|
||||
data: dict[str, Any] = {
|
||||
"branch": {},
|
||||
}
|
||||
|
||||
if name is not None:
|
||||
data["branch"]["name"] = name
|
||||
|
||||
if default is not None:
|
||||
data["branch"]["default"] = default
|
||||
|
||||
resp = self.__request(
|
||||
"PATCH",
|
||||
f"/projects/{project_id}/branches/{branch_id}",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
json=data,
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def delete_branch(self, project_id: str, branch_id: str) -> dict[str, Any]:
|
||||
"""
|
||||
Deletes a branch.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
branch_id: The branch ID
|
||||
|
||||
Returns:
|
||||
The API response containing the operation details
|
||||
"""
|
||||
resp = self.__request(
|
||||
"DELETE",
|
||||
f"/projects/{project_id}/branches/{branch_id}",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def reset_branch(
|
||||
self,
|
||||
project_id: str,
|
||||
branch_id: str,
|
||||
lsn: str | None = None,
|
||||
timestamp: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Resets a branch to a specified LSN or timestamp.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
branch_id: The branch ID
|
||||
lsn: The Log Sequence Number (LSN) to reset to (optional)
|
||||
timestamp: The timestamp to reset to (optional)
|
||||
|
||||
Returns:
|
||||
The API response containing the operation details
|
||||
"""
|
||||
params = {}
|
||||
if lsn is not None:
|
||||
params["lsn"] = lsn
|
||||
if timestamp is not None:
|
||||
params["timestamp"] = timestamp
|
||||
|
||||
resp = self.__request(
|
||||
"POST",
|
||||
f"/projects/{project_id}/branches/{branch_id}/reset",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
params=params,
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def reset_branch_to_parent(self, project_id: str, branch_id: str) -> dict[str, Any]:
|
||||
"""
|
||||
Resets a branch to the current state of the parent branch.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
branch_id: The branch ID
|
||||
|
||||
Returns:
|
||||
The API response containing the operation details
|
||||
"""
|
||||
resp = self.__request(
|
||||
"POST",
|
||||
f"/projects/{project_id}/branches/{branch_id}/reset_to_parent",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def restore_branch(self, project_id: str, branch_id: str) -> dict[str, Any]:
|
||||
"""
|
||||
Restores a branch that was previously deleted.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
branch_id: The branch ID
|
||||
|
||||
Returns:
|
||||
The API response containing the operation details
|
||||
"""
|
||||
resp = self.__request(
|
||||
"POST",
|
||||
f"/projects/{project_id}/branches/{branch_id}/restore",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def get_branch_schema(
|
||||
self,
|
||||
project_id: str,
|
||||
branch_id: str,
|
||||
db_name: str,
|
||||
lsn: str | None = None,
|
||||
timestamp: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Retrieves the schema from the specified database.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
branch_id: The branch ID
|
||||
db_name: Name of the database for which the schema is retrieved
|
||||
lsn: The Log Sequence Number (LSN) for which the schema is retrieved (optional)
|
||||
timestamp: The point in time for which the schema is retrieved (optional)
|
||||
|
||||
Returns:
|
||||
The API response containing the database schema
|
||||
"""
|
||||
params = {
|
||||
"db_name": db_name,
|
||||
}
|
||||
|
||||
if lsn is not None:
|
||||
params["lsn"] = lsn
|
||||
|
||||
if timestamp is not None:
|
||||
params["timestamp"] = timestamp
|
||||
|
||||
resp = self.__request(
|
||||
"GET",
|
||||
f"/projects/{project_id}/branches/{branch_id}/schema",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
params=params,
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def compare_branch_schema(
|
||||
self,
|
||||
project_id: str,
|
||||
branch_id: str,
|
||||
target_branch_id: str,
|
||||
db_name: str,
|
||||
target_db_name: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Compares schemas between two branches.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
branch_id: The source branch ID
|
||||
target_branch_id: The target branch ID to compare with
|
||||
db_name: Name of the database in the source branch
|
||||
target_db_name: Name of the database in the target branch (optional)
|
||||
|
||||
Returns:
|
||||
The API response containing the schema comparison
|
||||
"""
|
||||
params = {
|
||||
"target_branch_id": target_branch_id,
|
||||
"db_name": db_name,
|
||||
}
|
||||
|
||||
if target_db_name is not None:
|
||||
params["target_db_name"] = target_db_name
|
||||
|
||||
resp = self.__request(
|
||||
"GET",
|
||||
f"/projects/{project_id}/branches/{branch_id}/compare_schema",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
params=params,
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def set_branch_as_default(self, project_id: str, branch_id: str) -> dict[str, Any]:
|
||||
"""
|
||||
Sets a branch as the default branch for the project.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
branch_id: The branch ID
|
||||
|
||||
Returns:
|
||||
The API response containing the operation details
|
||||
"""
|
||||
resp = self.__request(
|
||||
"POST",
|
||||
f"/projects/{project_id}/branches/{branch_id}/set_as_default",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def get_branch_endpoints(self, project_id: str, branch_id: str) -> dict[str, Any]:
|
||||
"""
|
||||
Retrieves endpoints associated with a branch.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
branch_id: The branch ID
|
||||
|
||||
Returns:
|
||||
The API response containing the branch endpoints
|
||||
"""
|
||||
resp = self.__request(
|
||||
"GET",
|
||||
f"/projects/{project_id}/branches/{branch_id}/endpoints",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def get_branch_databases(self, project_id: str, branch_id: str) -> dict[str, Any]:
|
||||
"""
|
||||
Retrieves databases associated with a branch.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
branch_id: The branch ID
|
||||
|
||||
Returns:
|
||||
The API response containing the branch databases
|
||||
"""
|
||||
resp = self.__request(
|
||||
"GET",
|
||||
f"/projects/{project_id}/branches/{branch_id}/databases",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def create_branch_database(
|
||||
self, project_id: str, branch_id: str, database_name: str, owner_name: str | None = None
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Creates a new database in a branch.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
branch_id: The branch ID
|
||||
database_name: Name of the database to create
|
||||
owner_name: Name of the role that will own the database (optional)
|
||||
|
||||
Returns:
|
||||
The API response containing the created database details
|
||||
"""
|
||||
data: dict[str, Any] = {
|
||||
"database": {
|
||||
"name": database_name,
|
||||
},
|
||||
}
|
||||
|
||||
if owner_name is not None:
|
||||
data["database"]["owner_name"] = owner_name
|
||||
|
||||
resp = self.__request(
|
||||
"POST",
|
||||
f"/projects/{project_id}/branches/{branch_id}/databases",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
json=data,
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def get_branch_database(
|
||||
self, project_id: str, branch_id: str, database_name: str
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Retrieves details of a specific database in a branch.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
branch_id: The branch ID
|
||||
database_name: Name of the database to retrieve
|
||||
|
||||
Returns:
|
||||
The API response containing the database details
|
||||
"""
|
||||
resp = self.__request(
|
||||
"GET",
|
||||
f"/projects/{project_id}/branches/{branch_id}/databases/{database_name}",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def delete_branch_database(
|
||||
self, project_id: str, branch_id: str, database_name: str
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Deletes a database from a branch.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
branch_id: The branch ID
|
||||
database_name: Name of the database to delete
|
||||
|
||||
Returns:
|
||||
The API response containing the operation details
|
||||
"""
|
||||
resp = self.__request(
|
||||
"DELETE",
|
||||
f"/projects/{project_id}/branches/{branch_id}/databases/{database_name}",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def get_branch_roles(self, project_id: str, branch_id: str) -> dict[str, Any]:
|
||||
"""
|
||||
Retrieves roles associated with a branch.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
branch_id: The branch ID
|
||||
|
||||
Returns:
|
||||
The API response containing the branch roles
|
||||
"""
|
||||
resp = self.__request(
|
||||
"GET",
|
||||
f"/projects/{project_id}/branches/{branch_id}/roles",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def create_branch_role(self, project_id: str, branch_id: str, role_name: str) -> dict[str, Any]:
|
||||
"""
|
||||
Creates a new role in a branch.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
branch_id: The branch ID
|
||||
role_name: Name of the role to create
|
||||
|
||||
Returns:
|
||||
The API response containing the created role details
|
||||
"""
|
||||
data: dict[str, Any] = {
|
||||
"role": {
|
||||
"name": role_name,
|
||||
},
|
||||
}
|
||||
|
||||
resp = self.__request(
|
||||
"POST",
|
||||
f"/projects/{project_id}/branches/{branch_id}/roles",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
json=data,
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def get_branch_role(self, project_id: str, branch_id: str, role_name: str) -> dict[str, Any]:
|
||||
"""
|
||||
Retrieves details of a specific role in a branch.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
branch_id: The branch ID
|
||||
role_name: Name of the role to retrieve
|
||||
|
||||
Returns:
|
||||
The API response containing the role details
|
||||
"""
|
||||
resp = self.__request(
|
||||
"GET",
|
||||
f"/projects/{project_id}/branches/{branch_id}/roles/{role_name}",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def delete_branch_role(self, project_id: str, branch_id: str, role_name: str) -> dict[str, Any]:
|
||||
"""
|
||||
Deletes a role from a branch.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
branch_id: The branch ID
|
||||
role_name: Name of the role to delete
|
||||
|
||||
Returns:
|
||||
The API response containing the operation details
|
||||
"""
|
||||
resp = self.__request(
|
||||
"DELETE",
|
||||
f"/projects/{project_id}/branches/{branch_id}/roles/{role_name}",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def get_branch_role_password(
|
||||
self, project_id: str, branch_id: str, role_name: str
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Retrieves the password for a specific role in a branch.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
branch_id: The branch ID
|
||||
role_name: Name of the role
|
||||
|
||||
Returns:
|
||||
The API response containing the role password
|
||||
"""
|
||||
resp = self.__request(
|
||||
"GET",
|
||||
f"/projects/{project_id}/branches/{branch_id}/roles/{role_name}/reveal_password",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def reset_branch_role_password(
|
||||
self, project_id: str, branch_id: str, role_name: str
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Resets the password for a specific role in a branch.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
branch_id: The branch ID
|
||||
role_name: Name of the role
|
||||
|
||||
Returns:
|
||||
The API response containing the new role password
|
||||
"""
|
||||
resp = self.__request(
|
||||
"POST",
|
||||
f"/projects/{project_id}/branches/{branch_id}/roles/{role_name}/reset_password",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def get_endpoint(self, project_id: str, endpoint_id: str) -> dict[str, Any]:
|
||||
"""
|
||||
Retrieves details of a specific endpoint.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
endpoint_id: The endpoint ID
|
||||
|
||||
Returns:
|
||||
The API response containing the endpoint details
|
||||
"""
|
||||
resp = self.__request(
|
||||
"GET",
|
||||
f"/projects/{project_id}/endpoints/{endpoint_id}",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def update_endpoint(
|
||||
self,
|
||||
project_id: str,
|
||||
endpoint_id: str,
|
||||
branch_id: str | None = None,
|
||||
settings: dict[str, Any] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Updates an endpoint.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
endpoint_id: The endpoint ID
|
||||
branch_id: The branch ID to connect the endpoint to (optional)
|
||||
settings: Endpoint settings to update (optional)
|
||||
|
||||
Returns:
|
||||
The API response containing the updated endpoint details
|
||||
"""
|
||||
data: dict[str, Any] = {
|
||||
"endpoint": {},
|
||||
}
|
||||
|
||||
if branch_id is not None:
|
||||
data["endpoint"]["branch_id"] = branch_id
|
||||
|
||||
if settings is not None:
|
||||
data["endpoint"]["settings"] = settings
|
||||
|
||||
resp = self.__request(
|
||||
"PATCH",
|
||||
f"/projects/{project_id}/endpoints/{endpoint_id}",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
json=data,
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def delete_endpoint(self, project_id: str, endpoint_id: str) -> dict[str, Any]:
|
||||
"""
|
||||
Deletes an endpoint.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
endpoint_id: The endpoint ID
|
||||
|
||||
Returns:
|
||||
The API response containing the operation details
|
||||
"""
|
||||
resp = self.__request(
|
||||
"DELETE",
|
||||
f"/projects/{project_id}/endpoints/{endpoint_id}",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def get_endpoint_stats(
|
||||
self,
|
||||
project_id: str,
|
||||
endpoint_id: str,
|
||||
from_time: str | None = None,
|
||||
to_time: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Retrieves statistics for a specific endpoint.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
endpoint_id: The endpoint ID
|
||||
from_time: Start time for statistics data (optional)
|
||||
to_time: End time for statistics data (optional)
|
||||
|
||||
Returns:
|
||||
The API response containing the endpoint statistics
|
||||
"""
|
||||
data: dict[str, Any] = {}
|
||||
|
||||
if from_time is not None:
|
||||
data["from"] = from_time
|
||||
|
||||
if to_time is not None:
|
||||
data["to"] = to_time
|
||||
|
||||
resp = self.__request(
|
||||
"POST",
|
||||
f"/projects/{project_id}/endpoints/{endpoint_id}/stats",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
json=data,
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
def authenticate_passwordless_session(
|
||||
self, project_id: str, endpoint_id: str
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Authenticates a passwordless session for an endpoint.
|
||||
|
||||
Args:
|
||||
project_id: The Neon project ID
|
||||
endpoint_id: The endpoint ID
|
||||
|
||||
Returns:
|
||||
The API response containing the authentication details
|
||||
"""
|
||||
resp = self.__request(
|
||||
"POST",
|
||||
f"/projects/{project_id}/endpoints/{endpoint_id}/passwordless_auth",
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
|
||||
return cast("dict[str, Any]", resp.json())
|
||||
|
||||
|
||||
@final
|
||||
class NeonApiEndpoint:
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
from fixtures.benchmark_fixture import MetricReport, NeonBenchmarker
|
||||
from fixtures.neon_fixtures import NeonEnvBuilder, PgBin
|
||||
|
||||
|
||||
# Just start and measure duration.
|
||||
#
|
||||
# This test runs pretty quickly and can be informative when used in combination
|
||||
# with emulated network delay. Some useful delay commands:
|
||||
#
|
||||
# 1. Add 2msec delay to all localhost traffic
|
||||
# `sudo tc qdisc add dev lo root handle 1:0 netem delay 2msec`
|
||||
#
|
||||
# 2. Test that it works (you should see 4ms ping)
|
||||
# `ping localhost`
|
||||
#
|
||||
# 3. Revert back to normal
|
||||
# `sudo tc qdisc del dev lo root netem`
|
||||
#
|
||||
# NOTE this test might not represent the real startup time because the basebackup
|
||||
# for a large database might be larger if there's a lof of transaction metadata,
|
||||
# or safekeepers might need more syncing, or there might be more operations to
|
||||
# apply during config step, like more users, databases, or extensions. By default
|
||||
# we load extensions 'neon,pg_stat_statements,timescaledb,pg_cron', but in this
|
||||
# test we only load neon.
|
||||
def test_compute_startup_simple(
|
||||
neon_env_builder: NeonEnvBuilder,
|
||||
zenbenchmark: NeonBenchmarker,
|
||||
):
|
||||
neon_env_builder.num_safekeepers = 3
|
||||
env = neon_env_builder.init_start()
|
||||
|
||||
env.create_branch("test_startup")
|
||||
|
||||
endpoint = None
|
||||
|
||||
# We do two iterations so we can see if the second startup is faster. It should
|
||||
# be because the compute node should already be configured with roles, databases,
|
||||
# extensions, etc from the first run.
|
||||
for i in range(2):
|
||||
# Start
|
||||
with zenbenchmark.record_duration(f"{i}_start_and_select"):
|
||||
if endpoint:
|
||||
endpoint.start()
|
||||
else:
|
||||
endpoint = env.endpoints.create(
|
||||
"test_startup",
|
||||
# Shared buffers need to be allocated during startup, so they
|
||||
# impact startup time. This is the default value we use for
|
||||
# 1CPU pods (maybe different for VMs).
|
||||
#
|
||||
# TODO extensions also contribute to shared memory allocation,
|
||||
# and this test doesn't include all default extensions we
|
||||
# load.
|
||||
config_lines=["shared_buffers=262144"],
|
||||
)
|
||||
# Do not skip pg_catalog updates at first start, i.e.
|
||||
# imitate 'the first start after project creation'.
|
||||
endpoint.respec(skip_pg_catalog_updates=False)
|
||||
endpoint.start()
|
||||
endpoint.safe_psql("select 1;")
|
||||
|
||||
# Get metrics
|
||||
metrics = requests.get(
|
||||
f"http://localhost:{endpoint.external_http_port}/metrics.json"
|
||||
).json()
|
||||
durations = {
|
||||
"wait_for_spec_ms": f"{i}_wait_for_spec",
|
||||
"sync_safekeepers_ms": f"{i}_sync_safekeepers",
|
||||
"sync_sk_check_ms": f"{i}_sync_sk_check",
|
||||
"basebackup_ms": f"{i}_basebackup",
|
||||
"start_postgres_ms": f"{i}_start_postgres",
|
||||
"config_ms": f"{i}_config",
|
||||
"total_startup_ms": f"{i}_total_startup",
|
||||
}
|
||||
for key, name in durations.items():
|
||||
value = metrics[key]
|
||||
zenbenchmark.record(name, value, "ms", report=MetricReport.LOWER_IS_BETTER)
|
||||
|
||||
# Check basebackup size makes sense
|
||||
basebackup_bytes = metrics["basebackup_bytes"]
|
||||
if i > 0:
|
||||
assert basebackup_bytes < 100 * 1024
|
||||
|
||||
# Stop so we can restart
|
||||
endpoint.stop()
|
||||
|
||||
# Imitate optimizations that console would do for the second start
|
||||
endpoint.respec(skip_pg_catalog_updates=True)
|
||||
|
||||
|
||||
# Start and measure duration with huge SLRU segments.
|
||||
# This test is similar to test_compute_startup_simple, but it creates huge number of transactions
|
||||
# and records containing this XIDs. Autovacuum is disable for the table to prevent CLOG truncation.
|
||||
# TODO: this is very suspicious test, I doubt that it does what it's supposed to do,
|
||||
# e.g. these two starts do not make much sense. Looks like it's just copy-paste.
|
||||
# To be fixed within https://github.com/neondatabase/cloud/issues/8673
|
||||
@pytest.mark.timeout(1800)
|
||||
@pytest.mark.parametrize("slru", ["lazy", "eager"])
|
||||
def test_compute_ondemand_slru_startup(
|
||||
slru: str, neon_env_builder: NeonEnvBuilder, zenbenchmark: NeonBenchmarker
|
||||
):
|
||||
neon_env_builder.num_safekeepers = 3
|
||||
env = neon_env_builder.init_start()
|
||||
|
||||
lazy_slru_download = "true" if slru == "lazy" else "false"
|
||||
tenant, _ = env.create_tenant(
|
||||
conf={
|
||||
"lazy_slru_download": lazy_slru_download,
|
||||
}
|
||||
)
|
||||
|
||||
endpoint = env.endpoints.create_start("main", tenant_id=tenant)
|
||||
with endpoint.cursor() as cur:
|
||||
cur.execute("CREATE TABLE t (pk integer PRIMARY KEY, x integer)")
|
||||
cur.execute("ALTER TABLE t SET (autovacuum_enabled = false)")
|
||||
cur.execute("INSERT INTO t VALUES (1, 0)")
|
||||
cur.execute(
|
||||
"""
|
||||
CREATE PROCEDURE updating() as
|
||||
$$
|
||||
DECLARE
|
||||
i integer;
|
||||
BEGIN
|
||||
FOR i IN 1..1000000 LOOP
|
||||
UPDATE t SET x = x + 1 WHERE pk=1;
|
||||
COMMIT;
|
||||
END LOOP;
|
||||
END
|
||||
$$ LANGUAGE plpgsql
|
||||
"""
|
||||
)
|
||||
cur.execute("SET statement_timeout=0")
|
||||
cur.execute("call updating()")
|
||||
|
||||
endpoint.stop()
|
||||
|
||||
# We do two iterations so we can see if the second startup is faster. It should
|
||||
# be because the compute node should already be configured with roles, databases,
|
||||
# extensions, etc from the first run.
|
||||
for i in range(2):
|
||||
# Start
|
||||
with zenbenchmark.record_duration(f"{slru}_{i}_start"):
|
||||
endpoint.start()
|
||||
|
||||
with zenbenchmark.record_duration(f"{slru}_{i}_select"):
|
||||
sum = endpoint.safe_psql("select sum(x) from t")[0][0]
|
||||
assert sum == 1000000
|
||||
|
||||
# Get metrics
|
||||
metrics = requests.get(
|
||||
f"http://localhost:{endpoint.external_http_port}/metrics.json"
|
||||
).json()
|
||||
durations = {
|
||||
"wait_for_spec_ms": f"{slru}_{i}_wait_for_spec",
|
||||
"sync_safekeepers_ms": f"{slru}_{i}_sync_safekeepers",
|
||||
"sync_sk_check_ms": f"{slru}_{i}_sync_sk_check",
|
||||
"basebackup_ms": f"{slru}_{i}_basebackup",
|
||||
"start_postgres_ms": f"{slru}_{i}_start_postgres",
|
||||
"config_ms": f"{slru}_{i}_config",
|
||||
"total_startup_ms": f"{slru}_{i}_total_startup",
|
||||
}
|
||||
for key, name in durations.items():
|
||||
value = metrics[key]
|
||||
zenbenchmark.record(name, value, "ms", report=MetricReport.LOWER_IS_BETTER)
|
||||
|
||||
basebackup_bytes = metrics["basebackup_bytes"]
|
||||
zenbenchmark.record(
|
||||
f"{slru}_{i}_basebackup_bytes",
|
||||
basebackup_bytes,
|
||||
"bytes",
|
||||
report=MetricReport.LOWER_IS_BETTER,
|
||||
)
|
||||
|
||||
# Stop so we can restart
|
||||
endpoint.stop()
|
||||
|
||||
# Imitate optimizations that console would do for the second start
|
||||
endpoint.respec(skip_pg_catalog_updates=True)
|
||||
|
||||
|
||||
@pytest.mark.timeout(240)
|
||||
def test_compute_startup_latency(
|
||||
neon_env_builder: NeonEnvBuilder,
|
||||
pg_bin: PgBin,
|
||||
zenbenchmark: NeonBenchmarker,
|
||||
):
|
||||
"""
|
||||
Do NUM_STARTS 'optimized' starts, i.e. with pg_catalog updates skipped,
|
||||
and measure the duration of each step. Report p50, p90, p99 latencies.
|
||||
"""
|
||||
neon_env_builder.num_safekeepers = 3
|
||||
env = neon_env_builder.init_start()
|
||||
|
||||
endpoint = env.endpoints.create_start("main")
|
||||
pg_bin.run_capture(["pgbench", "-i", "-I", "dtGvp", "-s4", endpoint.connstr()])
|
||||
endpoint.stop()
|
||||
|
||||
NUM_STARTS = 100
|
||||
|
||||
durations: dict[str, list[int]] = {
|
||||
"sync_sk_check_ms": [],
|
||||
"sync_safekeepers_ms": [],
|
||||
"basebackup_ms": [],
|
||||
"start_postgres_ms": [],
|
||||
"total_startup_ms": [],
|
||||
}
|
||||
|
||||
for _i in range(NUM_STARTS):
|
||||
endpoint.start()
|
||||
client = endpoint.http_client()
|
||||
metrics = client.metrics_json()
|
||||
for key in durations.keys():
|
||||
value = metrics[key]
|
||||
durations[key].append(value)
|
||||
endpoint.stop()
|
||||
|
||||
for key in durations.keys():
|
||||
durations[key] = sorted(durations[key])
|
||||
zenbenchmark.record(
|
||||
f"{key}_p50",
|
||||
durations[key][len(durations[key]) // 2],
|
||||
"ms",
|
||||
report=MetricReport.LOWER_IS_BETTER,
|
||||
)
|
||||
zenbenchmark.record(
|
||||
f"{key}_p90",
|
||||
durations[key][len(durations[key]) * 9 // 10],
|
||||
"ms",
|
||||
report=MetricReport.LOWER_IS_BETTER,
|
||||
)
|
||||
zenbenchmark.record(
|
||||
f"{key}_p99",
|
||||
durations[key][len(durations[key]) * 99 // 100],
|
||||
"ms",
|
||||
report=MetricReport.LOWER_IS_BETTER,
|
||||
)
|
||||
110
test_runner/performance/test_lazy_startup.py
Normal file
110
test_runner/performance/test_lazy_startup.py
Normal file
@@ -0,0 +1,110 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
from fixtures.benchmark_fixture import MetricReport, NeonBenchmarker
|
||||
from fixtures.neon_fixtures import NeonEnvBuilder
|
||||
|
||||
|
||||
# Start and measure duration with huge SLRU segments.
|
||||
# This test is similar to test_startup_simple, but it creates huge number of transactions
|
||||
# and records containing this XIDs. Autovacuum is disable for the table to prevent CLOG truncation.
|
||||
#
|
||||
# This test runs pretty quickly and can be informative when used in combination
|
||||
# with emulated network delay. Some useful delay commands:
|
||||
#
|
||||
# 1. Add 2msec delay to all localhost traffic
|
||||
# `sudo tc qdisc add dev lo root handle 1:0 netem delay 2msec`
|
||||
#
|
||||
# 2. Test that it works (you should see 4ms ping)
|
||||
# `ping localhost`
|
||||
#
|
||||
# 3. Revert back to normal
|
||||
# `sudo tc qdisc del dev lo root netem`
|
||||
#
|
||||
# NOTE this test might not represent the real startup time because the basebackup
|
||||
# for a large database might be larger if there's a lof of transaction metadata,
|
||||
# or safekeepers might need more syncing, or there might be more operations to
|
||||
# apply during config step, like more users, databases, or extensions. By default
|
||||
# we load extensions 'neon,pg_stat_statements,timescaledb,pg_cron', but in this
|
||||
# test we only load neon.
|
||||
@pytest.mark.timeout(1800)
|
||||
@pytest.mark.parametrize("slru", ["lazy", "eager"])
|
||||
def test_lazy_startup(slru: str, neon_env_builder: NeonEnvBuilder, zenbenchmark: NeonBenchmarker):
|
||||
neon_env_builder.num_safekeepers = 3
|
||||
env = neon_env_builder.init_start()
|
||||
|
||||
lazy_slru_download = "true" if slru == "lazy" else "false"
|
||||
tenant, _ = env.create_tenant(
|
||||
conf={
|
||||
"lazy_slru_download": lazy_slru_download,
|
||||
}
|
||||
)
|
||||
|
||||
endpoint = env.endpoints.create_start("main", tenant_id=tenant)
|
||||
with endpoint.cursor() as cur:
|
||||
cur.execute("CREATE TABLE t (pk integer PRIMARY KEY, x integer)")
|
||||
cur.execute("ALTER TABLE t SET (autovacuum_enabled = false)")
|
||||
cur.execute("INSERT INTO t VALUES (1, 0)")
|
||||
cur.execute(
|
||||
"""
|
||||
CREATE PROCEDURE updating() as
|
||||
$$
|
||||
DECLARE
|
||||
i integer;
|
||||
BEGIN
|
||||
FOR i IN 1..1000000 LOOP
|
||||
UPDATE t SET x = x + 1 WHERE pk=1;
|
||||
COMMIT;
|
||||
END LOOP;
|
||||
END
|
||||
$$ LANGUAGE plpgsql
|
||||
"""
|
||||
)
|
||||
cur.execute("SET statement_timeout=0")
|
||||
cur.execute("call updating()")
|
||||
|
||||
endpoint.stop()
|
||||
|
||||
# We do two iterations so we can see if the second startup is faster. It should
|
||||
# be because the compute node should already be configured with roles, databases,
|
||||
# extensions, etc from the first run.
|
||||
for i in range(2):
|
||||
# Start
|
||||
with zenbenchmark.record_duration(f"{slru}_{i}_start"):
|
||||
endpoint.start()
|
||||
|
||||
with zenbenchmark.record_duration(f"{slru}_{i}_select"):
|
||||
sum = endpoint.safe_psql("select sum(x) from t")[0][0]
|
||||
assert sum == 1000000
|
||||
|
||||
# Get metrics
|
||||
metrics = requests.get(
|
||||
f"http://localhost:{endpoint.external_http_port}/metrics.json"
|
||||
).json()
|
||||
durations = {
|
||||
"wait_for_spec_ms": f"{slru}_{i}_wait_for_spec",
|
||||
"sync_safekeepers_ms": f"{slru}_{i}_sync_safekeepers",
|
||||
"sync_sk_check_ms": f"{slru}_{i}_sync_sk_check",
|
||||
"basebackup_ms": f"{slru}_{i}_basebackup",
|
||||
"start_postgres_ms": f"{slru}_{i}_start_postgres",
|
||||
"config_ms": f"{slru}_{i}_config",
|
||||
"total_startup_ms": f"{slru}_{i}_total_startup",
|
||||
}
|
||||
for key, name in durations.items():
|
||||
value = metrics[key]
|
||||
zenbenchmark.record(name, value, "ms", report=MetricReport.LOWER_IS_BETTER)
|
||||
|
||||
basebackup_bytes = metrics["basebackup_bytes"]
|
||||
zenbenchmark.record(
|
||||
f"{slru}_{i}_basebackup_bytes",
|
||||
basebackup_bytes,
|
||||
"bytes",
|
||||
report=MetricReport.LOWER_IS_BETTER,
|
||||
)
|
||||
|
||||
# Stop so we can restart
|
||||
endpoint.stop()
|
||||
|
||||
# Imitate optimizations that console would do for the second start
|
||||
endpoint.respec(skip_pg_catalog_updates=True)
|
||||
84
test_runner/performance/test_startup.py
Normal file
84
test_runner/performance/test_startup.py
Normal file
@@ -0,0 +1,84 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import requests
|
||||
from fixtures.benchmark_fixture import MetricReport, NeonBenchmarker
|
||||
from fixtures.neon_fixtures import NeonEnvBuilder
|
||||
|
||||
|
||||
# Just start and measure duration.
|
||||
#
|
||||
# This test runs pretty quickly and can be informative when used in combination
|
||||
# with emulated network delay. Some useful delay commands:
|
||||
#
|
||||
# 1. Add 2msec delay to all localhost traffic
|
||||
# `sudo tc qdisc add dev lo root handle 1:0 netem delay 2msec`
|
||||
#
|
||||
# 2. Test that it works (you should see 4ms ping)
|
||||
# `ping localhost`
|
||||
#
|
||||
# 3. Revert back to normal
|
||||
# `sudo tc qdisc del dev lo root netem`
|
||||
#
|
||||
# NOTE this test might not represent the real startup time because the basebackup
|
||||
# for a large database might be larger if there's a lof of transaction metadata,
|
||||
# or safekeepers might need more syncing, or there might be more operations to
|
||||
# apply during config step, like more users, databases, or extensions. By default
|
||||
# we load extensions 'neon,pg_stat_statements,timescaledb,pg_cron', but in this
|
||||
# test we only load neon.
|
||||
def test_startup_simple(neon_env_builder: NeonEnvBuilder, zenbenchmark: NeonBenchmarker):
|
||||
neon_env_builder.num_safekeepers = 3
|
||||
env = neon_env_builder.init_start()
|
||||
|
||||
env.create_branch("test_startup")
|
||||
|
||||
endpoint = None
|
||||
|
||||
# We do two iterations so we can see if the second startup is faster. It should
|
||||
# be because the compute node should already be configured with roles, databases,
|
||||
# extensions, etc from the first run.
|
||||
for i in range(2):
|
||||
# Start
|
||||
with zenbenchmark.record_duration(f"{i}_start_and_select"):
|
||||
if endpoint:
|
||||
endpoint.start()
|
||||
else:
|
||||
endpoint = env.endpoints.create_start(
|
||||
"test_startup",
|
||||
# Shared buffers need to be allocated during startup, so they
|
||||
# impact startup time. This is the default value we use for
|
||||
# 1CPU pods (maybe different for VMs).
|
||||
#
|
||||
# TODO extensions also contribute to shared memory allocation,
|
||||
# and this test doesn't include all default extensions we
|
||||
# load.
|
||||
config_lines=["shared_buffers=262144"],
|
||||
)
|
||||
endpoint.safe_psql("select 1;")
|
||||
|
||||
# Get metrics
|
||||
metrics = requests.get(
|
||||
f"http://localhost:{endpoint.external_http_port}/metrics.json"
|
||||
).json()
|
||||
durations = {
|
||||
"wait_for_spec_ms": f"{i}_wait_for_spec",
|
||||
"sync_safekeepers_ms": f"{i}_sync_safekeepers",
|
||||
"sync_sk_check_ms": f"{i}_sync_sk_check",
|
||||
"basebackup_ms": f"{i}_basebackup",
|
||||
"start_postgres_ms": f"{i}_start_postgres",
|
||||
"config_ms": f"{i}_config",
|
||||
"total_startup_ms": f"{i}_total_startup",
|
||||
}
|
||||
for key, name in durations.items():
|
||||
value = metrics[key]
|
||||
zenbenchmark.record(name, value, "ms", report=MetricReport.LOWER_IS_BETTER)
|
||||
|
||||
# Check basebackup size makes sense
|
||||
basebackup_bytes = metrics["basebackup_bytes"]
|
||||
if i > 0:
|
||||
assert basebackup_bytes < 100 * 1024
|
||||
|
||||
# Stop so we can restart
|
||||
endpoint.stop()
|
||||
|
||||
# Imitate optimizations that console would do for the second start
|
||||
endpoint.respec(skip_pg_catalog_updates=True)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user