diff --git a/.github/actions/build-ami/action.yml b/.github/actions/build-ami/action.yml index c10bc40682..5b4ca4347a 100644 --- a/.github/actions/build-ami/action.yml +++ b/.github/actions/build-ami/action.yml @@ -69,10 +69,11 @@ runs: AWS_REGION: ${{ inputs.region }} run: | nix run .#build-ami -- stage1 \ + -var 'ami-regions=${{ inputs.ami_regions }}' \ -var "git-head-version=${{ inputs.git_sha }}" \ -var "packer-execution-id=${{ env.EXECUTION_ID }}" \ - -var "ansible_arguments=-e postgresql_major=${{ inputs.postgres_version }}" \ - -var 'ami_regions=${{ inputs.ami_regions }}' \ + -var "postgres-version=${{ inputs.postgres_version }}" \ + -var "postgres-major-version=${{ inputs.postgres_version }}" \ ${{ inputs.packer_template }} - name: Build AMI stage 2 @@ -87,10 +88,10 @@ runs: AWS_REGION: ${{ inputs.region }} run: | nix run .#build-ami -- stage2 \ + -var "ami-name=${{ inputs.ami_name_prefix }}" \ -var "git-head-version=${{ inputs.git_sha }}" \ + -var "git-sha=${{ inputs.git_sha }}" \ + -var "instance-type=${{ inputs.instance_type }}" \ -var "packer-execution-id=${{ env.EXECUTION_ID }}" \ - -var "postgres_major_version=${{ inputs.postgres_version }}" \ - -var "ami_name=${{ inputs.ami_name_prefix }}" \ - -var "git_sha=${{ inputs.git_sha }}" \ - -var "instance_type=${{ inputs.instance_type }}" \ + -var "postgres-major-version=${{ inputs.postgres_version }}" \ stage2-nix-psql.pkr.hcl diff --git a/.github/workflows/ami-release-nix.yml b/.github/workflows/ami-release-nix.yml index cf4e830189..b9f1455a45 100644 --- a/.github/workflows/ami-release-nix.yml +++ b/.github/workflows/ami-release-nix.yml @@ -95,7 +95,16 @@ jobs: GIT_SHA=${{github.sha}} nix run github:supabase/postgres/${GIT_SHA}#packer -- init ${{ matrix.arch.packer_template }} - nix run github:supabase/postgres/${GIT_SHA}#packer -- build -var "git-head-version=${GIT_SHA}" -var "packer-execution-id=${EXECUTION_ID}" -var-file="${{ matrix.arch.vars_file }}" -var-file="common-nix.vars.pkr.hcl" -var "ansible_arguments=-e postgresql_major=${POSTGRES_MAJOR_VERSION}" -var "region=us-east-1" -var 'ami_regions=["us-east-1"]' -var "ami_name=supabase-postgres-${{ matrix.arch.ami_arch_filter }}" ${{ matrix.arch.packer_template }} + nix run github:supabase/postgres/${GIT_SHA}#packer -- build \ + -var "ami-name=supabase-postgres-${{ matrix.arch.ami_arch_filter }}" \ + -var "ansible-arguments=-e postgresql_major=${POSTGRES_MAJOR_VERSION}" \ + -var "git-head-version=${GIT_SHA}" \ + -var "packer-execution-id=${EXECUTION_ID}" \ + -var "region=us-east-1" \ + -var 'ami-regions=["us-east-1"]' \ + -var-file="${{ matrix.arch.vars_file }}" \ + -var-file="common-nix.vars.pkr.hcl" \ + ${{ matrix.arch.packer_template }} - name: Find stage 1 AMI run: | @@ -131,7 +140,18 @@ jobs: run: | GIT_SHA=${{github.sha}} nix run github:supabase/postgres/${GIT_SHA}#packer -- init stage2-nix-psql.pkr.hcl - nix run github:supabase/postgres/${GIT_SHA}#packer -- build -var "git_sha=${GIT_SHA}" -var "git-head-version=${GIT_SHA}" -var "packer-execution-id=${EXECUTION_ID}" -var "postgres_major_version=${POSTGRES_MAJOR_VERSION}" -var "source_ami=${STAGE1_AMI_ID}" -var-file="${{ matrix.arch.vars_file }}" -var-file="common-nix.vars.pkr.hcl" -var "region=us-east-1" -var "instance_type=${{ matrix.arch.instance_type }}" -var "ami_name=supabase-postgres-${{ matrix.arch.ami_arch_filter }}" stage2-nix-psql.pkr.hcl + nix run github:supabase/postgres/${GIT_SHA}#packer -- build \ + -var "ami-name=supabase-postgres-${{ matrix.arch.ami_arch_filter }}" \ + -var "git-head-version=${GIT_SHA}" \ + -var "git-sha=${GIT_SHA}" \ + -var "instance-type=${{ matrix.arch.instance_type }}" \ + -var "packer-execution-id=${EXECUTION_ID}" \ + -var "postgres-major-version=${POSTGRES_MAJOR_VERSION}" \ + -var "region=us-east-1" \ + -var "source-ami=${STAGE1_AMI_ID}" \ + -var-file="${{ matrix.arch.vars_file }}" \ + -var-file="common-nix.vars.pkr.hcl" \ + stage2-nix-psql.pkr.hcl - name: Grab release version id: process_release_version diff --git a/Dockerfile-multigres b/Dockerfile-multigres index bddb8407ba..19823441e7 100644 --- a/Dockerfile-multigres +++ b/Dockerfile-multigres @@ -202,7 +202,7 @@ COPY docker/pgctld/postgresql.conf.tmpl /etc/pgctld-custom/postgresql.conf.tmpl # Wrapper: injects --postgres-config-template on every pgctld call AND bridges # postgres's JSON log file to container stdout via a /proc/1/fd/1 symlink so # kubelet + Vector can ship it without a sidecar. See docker/pgctld/pgctld-wrapper. -COPY --chmod=755 docker/pgctld/pgctld-wrapper /usr/local/bin/pgctld +COPY --chmod=755 docker/pgctld/pgctld-wrapper.sh /usr/local/bin/pgctld ENV POSTGRES_CONFIG_TEMPLATE_PATH=/etc/pgctld-custom/postgresql.conf.tmpl # Strip extensions absent from pg17 vanilla build diff --git a/README.md b/README.md index b509bdddd7..40106aaddf 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,6 @@ Here's a comprehensive overview of the project's directory structure: | **tests/** | Integration and system tests | | testinfra/ | Infrastructure tests using pytest framework | | tests/ | General integration test suites | -| **scripts/** | Utility scripts for development and deployment | | **docs/** | Additional documentation, images, and resources | | **ebssurrogate/** | AWS EBS surrogate building for AMI creation | | **http/** | HTTP-related configurations and files | diff --git a/amazon-amd64-nix.pkr.hcl b/amazon-amd64-nix.pkr.hcl index 443387d6d0..06da94fb97 100644 --- a/amazon-amd64-nix.pkr.hcl +++ b/amazon-amd64-nix.pkr.hcl @@ -3,28 +3,18 @@ variable "ami" { default = "ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.04-amd64-server-*" } -variable "profile" { - type = string - default = "${env("AWS_PROFILE")}" -} - -variable "ami_name" { +variable "ami-name" { type = string default = "supabase-postgres" } -variable "ami_regions" { +variable "ami-regions" { type = list(string) default = ["ap-southeast-1"] } -variable "ansible_arguments" { - type = string - default = "--skip-tags install-postgrest,install-pgbouncer,install-supabase-internal" -} - -variable "region" { - type = string +variable "ansible-arguments" { + type = string } variable "build-vol" { @@ -32,55 +22,43 @@ variable "build-vol" { default = "xvdc" } -# ccache docker image details -variable "docker_user" { - type = string - default = "" -} - -variable "docker_passwd" { - type = string - default = "" +variable "force-deregister" { + type = bool + default = false } -variable "docker_image" { - type = string - default = "" +variable "git-head-version" { + type = string } -variable "docker_image_tag" { - type = string - default = "latest" +variable "input-hash" { + type = string + description = "Content hash of all input sources" } -locals { - creator = "packer" +variable "packer-execution-id" { + type = string } variable "postgres-version" { type = string - default = "" } -variable "git-head-version" { +variable "postgres-major-version" { type = string - default = "unknown" } -variable "packer-execution-id" { - type = string - default = "unknown" +variable "profile" { + type = string + default = "${env("AWS_PROFILE")}" } -variable "force-deregister" { - type = bool - default = false +variable "region" { + type = string } -variable "input-hash" { - type = string - default = "" - description = "Content hash of all input sources" +locals { + creator = "packer" } packer { @@ -94,29 +72,29 @@ packer { # source block source "amazon-ebssurrogate" "source" { - profile = "${var.profile}" - ami_name = "${var.ami_name}-${var.postgres-version}-${var.input-hash}-stage-1" + profile = "${var.profile}" + ami_name = "${var.ami-name}-${var.postgres-version}-${var.input-hash}-stage-1" ami_virtualization_type = "hvm" - ami_architecture = "x86_64" - ami_regions = "${var.ami_regions}" - instance_type = "c6i.4xlarge" - region = "${var.region}" - force_deregister = var.force-deregister + ami_architecture = "x86_64" + ami_regions = "${var.ami-regions}" + instance_type = "c6i.4xlarge" + region = "${var.region}" + force_deregister = var.force-deregister # Increase timeout for instance stop operations to handle large instances aws_polling { delay_seconds = 15 - max_attempts = 120 # 120 * 15s = 30 minutes max wait + max_attempts = 120 # 120 * 15s = 30 minutes max wait } # Use latest official ubuntu noble ami owned by Canonical. source_ami_filter { filters = { virtualization-type = "hvm" - name = "${var.ami}" - root-device-type = "ebs" + name = "${var.ami}" + root-device-type = "ebs" } - owners = [ "099720109477" ] + owners = ["099720109477"] most_recent = true } @@ -126,7 +104,7 @@ source "amazon-ebssurrogate" "source" { delete_on_termination = true volume_size = 10 volume_type = "gp3" - } + } # NOTE: /dev/xvdh is mounted as /data (PostgreSQL data/WAL). The 1 GiB size # is a minimal default for this AMI; consumers should override this volume @@ -136,7 +114,7 @@ source "amazon-ebssurrogate" "source" { delete_on_termination = true volume_size = 1 volume_type = "gp3" - } + } launch_block_device_mappings { device_name = "/dev/${var.build-vol}" @@ -160,17 +138,17 @@ source "amazon-ebssurrogate" "source" { appType = "postgres" } tags = { - creator = "packer" - appType = "postgres" + creator = "packer" + appType = "postgres" postgresVersion = "${var.postgres-version}-stage1" - sourceSha = "${var.git-head-version}" - inputHash = "${var.input-hash}" + sourceSha = "${var.git-head-version}" + inputHash = "${var.input-hash}" } communicator = "ssh" - ssh_pty = false + ssh_pty = false ssh_username = "ubuntu" - ssh_timeout = "5m" + ssh_timeout = "5m" ami_root_device { source_device_name = "/dev/xvdf" @@ -188,84 +166,71 @@ build { sources = ["source.amazon-ebssurrogate.source"] provisioner "file" { - source = "ebssurrogate/files/sources.cfg" + source = "ebssurrogate/files/sources.cfg" destination = "/tmp/sources.list" } provisioner "file" { - source = "ebssurrogate/files/ebsnvme-id" - destination = "/tmp/ebsnvme-id" + source = "ebssurrogate/files/ebsnvme-id" + destination = "/tmp/" } provisioner "file" { - source = "ebssurrogate/files/70-ec2-nvme-devices.rules" - destination = "/tmp/70-ec2-nvme-devices.rules" + source = "ebssurrogate/files/70-ec2-nvme-devices.rules" + destination = "/tmp/" } provisioner "file" { - source = "ebssurrogate/scripts/chroot-bootstrap-nix.sh" - destination = "/tmp/chroot-bootstrap-nix.sh" + source = "ebssurrogate/scripts/chroot-bootstrap-nix.sh" + destination = "/tmp/" } provisioner "file" { - source = "ebssurrogate/files/cloud.cfg" - destination = "/tmp/cloud.cfg" + source = "ebssurrogate/files/cloud.cfg" + destination = "/tmp/" } provisioner "file" { - source = "ebssurrogate/files/vector.timer" - destination = "/tmp/vector.timer" + source = "ebssurrogate/files/vector.timer" + destination = "/tmp/" } provisioner "file" { - source = "ebssurrogate/files/apparmor_profiles" - destination = "/tmp" - } - - provisioner "file" { - source = "migrations" - destination = "/tmp" - } - - # Copy ansible playbook - provisioner "shell" { - inline = ["mkdir /tmp/ansible-playbook"] + source = "ebssurrogate/files/apparmor_profiles" + destination = "/tmp/" } provisioner "file" { - source = "ansible" - destination = "/tmp/ansible-playbook" + source = "migrations" + destination = "/tmp/" } provisioner "file" { - source = "scripts" - destination = "/tmp/ansible-playbook" + source = "ansible" + destination = "/tmp/" } provisioner "file" { - source = "ansible/vars.yml" - destination = "/tmp/ansible-playbook/vars.yml" + source = "ebssurrogate/scripts/90-cleanup.sh" + destination = "/tmp/" } provisioner "shell" { environment_vars = [ - "ARGS=${var.ansible_arguments}", - "DOCKER_USER=${var.docker_user}", - "DOCKER_PASSWD=${var.docker_passwd}", - "DOCKER_IMAGE=${var.docker_image}", - "DOCKER_IMAGE_TAG=${var.docker_image_tag}", + "ARGS=${var.ansible-arguments}", + "POSTGERS_MAJOR_VERSION=${var.postgres-major-version}" "POSTGRES_SUPABASE_VERSION=${var.postgres-version}" ] - use_env_var_file = true - script = "ebssurrogate/scripts/surrogate-bootstrap-nix.sh" - execute_command = "sudo -S sh -c '. {{.EnvVarFile}} && cd /tmp/ansible-playbook && {{.Path}}'" + use_env_var_file = true + script = "ebssurrogate/scripts/surrogate-bootstrap-nix.sh" + execute_command = "sudo -S sh -c '. {{.EnvVarFile}} && {{.Path}}'" start_retry_timeout = "5m" - skip_clean = true + skip_clean = true } provisioner "file" { - source = "/tmp/ansible.log" + source = "/tmp/ansible.log" destination = "/tmp/ansible.log" - direction = "download" + direction = "download" } } diff --git a/amazon-arm64-nix.pkr.hcl b/amazon-arm64-nix.pkr.hcl index 4faa8aac40..e145cd9b26 100644 --- a/amazon-arm64-nix.pkr.hcl +++ b/amazon-arm64-nix.pkr.hcl @@ -3,28 +3,18 @@ variable "ami" { default = "ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.04-arm64-server-*" } -variable "profile" { - type = string - default = "${env("AWS_PROFILE")}" -} - -variable "ami_name" { +variable "ami-name" { type = string default = "supabase-postgres" } -variable "ami_regions" { +variable "ami-regions" { type = list(string) default = ["ap-southeast-1"] } -variable "ansible_arguments" { - type = string - default = "--skip-tags install-postgrest,install-pgbouncer,install-supabase-internal" -} - -variable "region" { - type = string +variable "ansible-arguments" { + type = string } variable "build-vol" { @@ -32,55 +22,43 @@ variable "build-vol" { default = "xvdc" } -# ccache docker image details -variable "docker_user" { - type = string - default = "" -} - -variable "docker_passwd" { - type = string - default = "" +variable "force-deregister" { + type = bool + default = false } -variable "docker_image" { - type = string - default = "" +variable "git-head-version" { + type = string } -variable "docker_image_tag" { - type = string - default = "latest" +variable "input-hash" { + type = string + description = "Content hash of all input sources" } -locals { - creator = "packer" +variable "packer-execution-id" { + type = string } variable "postgres-version" { type = string - default = "" } -variable "git-head-version" { +variable "postgres-major-version" { type = string - default = "unknown" } -variable "packer-execution-id" { - type = string - default = "unknown" +variable "profile" { + type = string + default = "${env("AWS_PROFILE")}" } -variable "force-deregister" { - type = bool - default = false +variable "region" { + type = string } -variable "input-hash" { - type = string - default = "" - description = "Content hash of all input sources" +locals { + creator = "packer" } packer { @@ -94,29 +72,29 @@ packer { # source block source "amazon-ebssurrogate" "source" { - profile = "${var.profile}" - ami_name = "${var.ami_name}-${var.postgres-version}-${var.input-hash}-stage-1" + profile = "${var.profile}" + ami_name = "${var.ami-name}-${var.postgres-version}-${var.input-hash}-stage-1" ami_virtualization_type = "hvm" - ami_architecture = "arm64" - ami_regions = "${var.ami_regions}" - instance_type = "c6g.4xlarge" - region = "${var.region}" - force_deregister = var.force-deregister + ami_architecture = "arm64" + ami_regions = "${var.ami-regions}" + instance_type = "c6g.4xlarge" + region = "${var.region}" + force_deregister = var.force-deregister # Increase timeout for instance stop operations to handle large instances aws_polling { delay_seconds = 15 - max_attempts = 120 # 120 * 15s = 30 minutes max wait + max_attempts = 120 # 120 * 15s = 30 minutes max wait } # Use latest official ubuntu noble ami owned by Canonical. source_ami_filter { filters = { virtualization-type = "hvm" - name = "${var.ami}" - root-device-type = "ebs" + name = "${var.ami}" + root-device-type = "ebs" } - owners = [ "099720109477" ] + owners = ["099720109477"] most_recent = true } @@ -126,7 +104,7 @@ source "amazon-ebssurrogate" "source" { delete_on_termination = true volume_size = 10 volume_type = "gp3" - } + } # NOTE: /dev/xvdh is mounted as /data (PostgreSQL data/WAL). The 1 GiB size # is a minimal default for this AMI; consumers should override this volume @@ -136,7 +114,7 @@ source "amazon-ebssurrogate" "source" { delete_on_termination = true volume_size = 1 volume_type = "gp3" - } + } launch_block_device_mappings { device_name = "/dev/${var.build-vol}" @@ -160,17 +138,17 @@ source "amazon-ebssurrogate" "source" { appType = "postgres" } tags = { - creator = "packer" - appType = "postgres" + creator = "packer" + appType = "postgres" postgresVersion = "${var.postgres-version}-stage1" - sourceSha = "${var.git-head-version}" - inputHash = "${var.input-hash}" + sourceSha = "${var.git-head-version}" + inputHash = "${var.input-hash}" } communicator = "ssh" - ssh_pty = true + ssh_pty = true ssh_username = "ubuntu" - ssh_timeout = "5m" + ssh_timeout = "5m" ami_root_device { source_device_name = "/dev/xvdf" @@ -188,84 +166,71 @@ build { sources = ["source.amazon-ebssurrogate.source"] provisioner "file" { - source = "ebssurrogate/files/sources-arm64.cfg" + source = "ebssurrogate/files/sources-arm64.cfg" destination = "/tmp/sources.list" } provisioner "file" { - source = "ebssurrogate/files/ebsnvme-id" - destination = "/tmp/ebsnvme-id" + source = "ebssurrogate/files/ebsnvme-id" + destination = "/tmp/" } provisioner "file" { - source = "ebssurrogate/files/70-ec2-nvme-devices.rules" - destination = "/tmp/70-ec2-nvme-devices.rules" + source = "ebssurrogate/files/70-ec2-nvme-devices.rules" + destination = "/tmp/" } provisioner "file" { - source = "ebssurrogate/scripts/chroot-bootstrap-nix.sh" - destination = "/tmp/chroot-bootstrap-nix.sh" + source = "ebssurrogate/scripts/chroot-bootstrap-nix.sh" + destination = "/tmp/" } provisioner "file" { - source = "ebssurrogate/files/cloud.cfg" - destination = "/tmp/cloud.cfg" + source = "ebssurrogate/files/cloud.cfg" + destination = "/tmp/" } provisioner "file" { - source = "ebssurrogate/files/vector.timer" - destination = "/tmp/vector.timer" + source = "ebssurrogate/files/vector.timer" + destination = "/tmp/" } provisioner "file" { - source = "ebssurrogate/files/apparmor_profiles" - destination = "/tmp" - } - - provisioner "file" { - source = "migrations" - destination = "/tmp" - } - - # Copy ansible playbook - provisioner "shell" { - inline = ["mkdir /tmp/ansible-playbook"] + source = "ebssurrogate/files/apparmor_profiles" + destination = "/tmp/" } provisioner "file" { - source = "ansible" - destination = "/tmp/ansible-playbook" + source = "migrations" + destination = "/tmp/" } provisioner "file" { - source = "scripts" - destination = "/tmp/ansible-playbook" + source = "ansible" + destination = "/tmp/" } provisioner "file" { - source = "ansible/vars.yml" - destination = "/tmp/ansible-playbook/vars.yml" + source = "ebssurrogate/scripts/90-cleanup.sh" + destination = "/tmp/" } provisioner "shell" { environment_vars = [ - "ARGS=${var.ansible_arguments}", - "DOCKER_USER=${var.docker_user}", - "DOCKER_PASSWD=${var.docker_passwd}", - "DOCKER_IMAGE=${var.docker_image}", - "DOCKER_IMAGE_TAG=${var.docker_image_tag}", + "ARGS=${var.ansible-arguments}", + "POSTGERS_MAJOR_VERSION=${var.postgres-major-version}" "POSTGRES_SUPABASE_VERSION=${var.postgres-version}" ] - use_env_var_file = true - script = "ebssurrogate/scripts/surrogate-bootstrap-nix.sh" - execute_command = "sudo -S sh -c '. {{.EnvVarFile}} && cd /tmp/ansible-playbook && {{.Path}}'" + use_env_var_file = true + script = "ebssurrogate/scripts/surrogate-bootstrap-nix.sh" + execute_command = "sudo -S sh -c '. {{.EnvVarFile}} && {{.Path}}'" start_retry_timeout = "5m" - skip_clean = true + skip_clean = true } provisioner "file" { - source = "/tmp/ansible.log" + source = "/tmp/ansible.log" destination = "/tmp/ansible.log" - direction = "download" + direction = "download" } } diff --git a/ansible/files/admin_api_scripts/grow_fs.sh b/ansible/files/admin_api_scripts/grow_fs.sh index 1a524d1968..d0707442b6 100644 --- a/ansible/files/admin_api_scripts/grow_fs.sh +++ b/ansible/files/admin_api_scripts/grow_fs.sh @@ -8,14 +8,14 @@ VOLUME_TYPE=${1:-data} UBUNTU_VERSION=$(lsb_release -rs) if pgrep resizefs; then - echo "resize2fs is already running" - exit 1 + echo "resize2fs is already running" + exit 1 fi # install amazon disk utilities if not present on 24.04 if [ "${UBUNTU_VERSION}" = "24.04" ] && ! /usr/bin/dpkg-query -W amazon-ec2-utils >/dev/null 2>&1; then - apt-get update - apt-get install -y amazon-ec2-utils || true + apt-get update + apt-get install -y amazon-ec2-utils || true fi # We currently mount 3 possible disks @@ -27,15 +27,15 @@ XVDA_DEVICE="/dev/nvme0n1" XVDH_DEVICE="/dev/nvme1n1" # Map AWS devices to NVMe for ubuntu 24.04 and later if [ "${UBUNTU_VERSION}" = "24.04" ] && /usr/bin/dpkg-query -W amazon-ec2-utils >/dev/null 2>&1; then - for nvme_dev in $(lsblk -dprno name,type | grep disk | awk '{print $1}'); do - if [ -b "$nvme_dev" ]; then - mapping=$(ebsnvme-id -b "$nvme_dev" 2>/dev/null) - case "$mapping" in - "xvda"|"/dev/xvda") XVDA_DEVICE="$nvme_dev" ;; - "xvdh"|"/dev/xvdh") XVDH_DEVICE="$nvme_dev" ;; - esac - fi - done + for nvme_dev in $(lsblk -dprno name,type | grep disk | awk '{print $1}'); do + if [ -b "$nvme_dev" ]; then + mapping=$(ebsnvme-id -b "$nvme_dev" 2>/dev/null) + case "$mapping" in + "xvda" | "/dev/xvda") XVDA_DEVICE="$nvme_dev" ;; + "xvdh" | "/dev/xvdh") XVDH_DEVICE="$nvme_dev" ;; + esac + fi + done fi echo "Using devices - Root: $XVDA_DEVICE, Data: $XVDH_DEVICE" @@ -45,35 +45,35 @@ ROOT_DEVICE_FULL=$(findmnt -no SOURCE /) ROOT_DEVICE=$(lsblk -no PKNAME "$ROOT_DEVICE_FULL") ROOT_PARTITION_NUMBER=$(echo "$ROOT_DEVICE_FULL" | sed "s|.*${ROOT_DEVICE}p||") -if ! [[ "$ROOT_PARTITION_NUMBER" =~ ^[0-9]+$ ]]; then - echo "Error: ROOT_PARTITION_NUMBER is not a valid number: $ROOT_PARTITION_NUMBER" - exit 1 +if ! [[ $ROOT_PARTITION_NUMBER =~ ^[0-9]+$ ]]; then + echo "Error: ROOT_PARTITION_NUMBER is not a valid number: $ROOT_PARTITION_NUMBER" + exit 1 fi -if [ -b "${XVDH_DEVICE}" ] ; then - if [[ "${VOLUME_TYPE}" == "data" ]]; then - resize2fs "${XVDH_DEVICE}" +if [ -b "${XVDH_DEVICE}" ]; then + if [[ ${VOLUME_TYPE} == "data" ]]; then + resize2fs "${XVDH_DEVICE}" - # Explicitly reserving 100MiB worth of blocks for the data volume - # - # This is owned in $GIT_DIR/ebssurrogate/scripts/surrogate-bootstrap-nix.sh - RESERVED_DATA_VOLUME_BLOCK_COUNT=$((100 * 1024 * 1024 / 4096)) - tune2fs -r $RESERVED_DATA_VOLUME_BLOCK_COUNT "${XVDH_DEVICE}" + # Explicitly reserving 100MiB worth of blocks for the data volume + # + # This is owned in $GIT_DIR/ebssurrogate/scripts/surrogate-bootstrap-nix.sh + RESERVED_DATA_VOLUME_BLOCK_COUNT=$((100 * 1024 * 1024 / 4096)) + tune2fs -r $RESERVED_DATA_VOLUME_BLOCK_COUNT "${XVDH_DEVICE}" - elif [[ "${VOLUME_TYPE}" == "root" ]] ; then - PLACEHOLDER_FL=/home/ubuntu/50M_PLACEHOLDER - rm -f "${PLACEHOLDER_FL}" || true - growpart "${XVDA_DEVICE}" "${ROOT_PARTITION_NUMBER}" - resize2fs "${XVDA_DEVICE}p${ROOT_PARTITION_NUMBER}" - if [[ ! -f "${PLACEHOLDER_FL}" ]] ; then - fallocate -l50M "${PLACEHOLDER_FL}" - fi - else - echo "Invalid disk specified: ${VOLUME_TYPE}" - exit 1 - fi + elif [[ ${VOLUME_TYPE} == "root" ]]; then + PLACEHOLDER_FL=/home/ubuntu/50M_PLACEHOLDER + rm -f "${PLACEHOLDER_FL}" || true + growpart "${XVDA_DEVICE}" "${ROOT_PARTITION_NUMBER}" + resize2fs "${XVDA_DEVICE}p${ROOT_PARTITION_NUMBER}" + if [[ ! -f ${PLACEHOLDER_FL} ]]; then + fallocate -l50M "${PLACEHOLDER_FL}" + fi + else + echo "Invalid disk specified: ${VOLUME_TYPE}" + exit 1 + fi else - growpart "${XVDA_DEVICE}" "${ROOT_PARTITION_NUMBER}" - resize2fs "${XVDA_DEVICE}p${ROOT_PARTITION_NUMBER}" + growpart "${XVDA_DEVICE}" "${ROOT_PARTITION_NUMBER}" + resize2fs "${XVDA_DEVICE}p${ROOT_PARTITION_NUMBER}" fi echo "Done resizing disk" diff --git a/ansible/files/admin_api_scripts/manage_readonly_mode.sh b/ansible/files/admin_api_scripts/manage_readonly_mode.sh index 41c9f5a1e3..6c9fef5880 100644 --- a/ansible/files/admin_api_scripts/manage_readonly_mode.sh +++ b/ansible/files/admin_api_scripts/manage_readonly_mode.sh @@ -5,13 +5,14 @@ set -euo pipefail SUBCOMMAND=$1 function set_mode { - MODE=$1 - psql -h localhost -U supabase_admin -d postgres -c "ALTER SYSTEM SET default_transaction_read_only to ${MODE};" - psql -h localhost -U supabase_admin -d postgres -c "SELECT pg_reload_conf();" + MODE=$1 + psql -h localhost -U supabase_admin -d postgres -c "ALTER SYSTEM SET default_transaction_read_only to ${MODE};" + psql -h localhost -U supabase_admin -d postgres -c "SELECT pg_reload_conf();" } function check_override { - COMMAND=$(cat < " - echo "Example: sudo ./mount-volume.sh /dev/nvme1n1 /data/150008" - logger "Usage: $0 " - logger "Example: sudo ./mount-volume.sh /dev/nvme1n1 /data/150008" - exit 1 +if [[ -z $DEVICE || -z $MOUNT_POINT ]]; then + echo "Usage: $0 " + echo "Example: sudo ./mount-volume.sh /dev/nvme1n1 /data/150008" + logger "Usage: $0 " + logger "Example: sudo ./mount-volume.sh /dev/nvme1n1 /data/150008" + exit 1 fi OWNER="postgres:postgres" @@ -24,8 +24,8 @@ LOGGER_TAG="mount-volume" # --- Helper function for echo + logger --- log() { - echo "$1" - logger -t "$LOGGER_TAG" "$1" + echo "$1" + logger -t "$LOGGER_TAG" "$1" } log "Starting mount procedure for device $DEVICE → $MOUNT_POINT" @@ -33,57 +33,57 @@ log "Starting mount procedure for device $DEVICE → $MOUNT_POINT" # --- Wait for block device --- log "Waiting for block device $DEVICE to become available..." while true; do - if [ -b "$DEVICE" ]; then - if blkid "$DEVICE" >/dev/null 2>&1 || true; then - log "$DEVICE is ready" - break - fi - fi - - ELAPSED=$((ELAPSED + INTERVAL)) - if [ $ELAPSED -ge $TIMEOUT ]; then - log "Error: $DEVICE did not become ready after $TIMEOUT seconds" - exit 3 - fi - - sleep $INTERVAL + if [ -b "$DEVICE" ]; then + if blkid "$DEVICE" >/dev/null 2>&1 || true; then + log "$DEVICE is ready" + break + fi + fi + + ELAPSED=$((ELAPSED + INTERVAL)) + if [ $ELAPSED -ge $TIMEOUT ]; then + log "Error: $DEVICE did not become ready after $TIMEOUT seconds" + exit 3 + fi + + sleep $INTERVAL done # --- Validate device --- if [ ! -b "$DEVICE" ]; then - log "Error: Block device '$DEVICE' does not exist." - exit 2 + log "Error: Block device '$DEVICE' does not exist." + exit 2 fi # --- Safety: refuse to mount over non-empty directory --- mkdir -p "$MOUNT_POINT" if [ "$(ls -A "$MOUNT_POINT" 2>/dev/null)" ]; then - if ! mountpoint -q "$MOUNT_POINT"; then - log "Error: Mount point $MOUNT_POINT is not empty. Aborting to protect existing data." - exit 4 - fi + if ! mountpoint -q "$MOUNT_POINT"; then + log "Error: Mount point $MOUNT_POINT is not empty. Aborting to protect existing data." + exit 4 + fi fi # --- Format if needed --- if ! blkid "$DEVICE" >/dev/null 2>&1; then - log "Device $DEVICE appears unformatted. Formatting as $FSTYPE..." - mkfs."$FSTYPE" -F "$DEVICE" + log "Device $DEVICE appears unformatted. Formatting as $FSTYPE..." + mkfs."$FSTYPE" -F "$DEVICE" else - log "$DEVICE already has a filesystem — skipping format." + log "$DEVICE already has a filesystem — skipping format." fi # --- Filesystem check --- if ! mountpoint -q "$MOUNT_POINT"; then - log "Running e2fsck check on $DEVICE" - e2fsck -pf "$DEVICE" || log "Warning: e2fsck returned non-zero exit code" + log "Running e2fsck check on $DEVICE" + e2fsck -pf "$DEVICE" || log "Warning: e2fsck returned non-zero exit code" fi # --- Mount --- if ! mountpoint -q "$MOUNT_POINT"; then - log "Mounting $DEVICE to $MOUNT_POINT" - mount -t "$FSTYPE" -o "$MOUNT_OPTS" "$DEVICE" "$MOUNT_POINT" + log "Mounting $DEVICE to $MOUNT_POINT" + mount -t "$FSTYPE" -o "$MOUNT_OPTS" "$DEVICE" "$MOUNT_POINT" else - log "$MOUNT_POINT is already mounted" + log "$MOUNT_POINT is already mounted" fi # --- Ownership and permissions --- @@ -96,10 +96,10 @@ UUID=$(blkid -s UUID -o value "$DEVICE") FSTAB_LINE="UUID=$UUID $MOUNT_POINT $FSTYPE $MOUNT_OPTS 0 2" if ! grep -q "$UUID" "$FSTAB_FILE"; then - log "Adding $FSTAB_LINE to $FSTAB_FILE" - echo "$FSTAB_LINE" >> "$FSTAB_FILE" + log "Adding $FSTAB_LINE to $FSTAB_FILE" + echo "$FSTAB_LINE" >>"$FSTAB_FILE" else - log "UUID $UUID already in $FSTAB_FILE — skipping" + log "UUID $UUID already in $FSTAB_FILE — skipping" fi -log "Mounted $DEVICE at $MOUNT_POINT with owner=$OWNER and mode=$PERMISSIONS" \ No newline at end of file +log "Mounted $DEVICE at $MOUNT_POINT with owner=$OWNER and mode=$PERMISSIONS" diff --git a/ansible/files/admin_api_scripts/pg_upgrade_scripts/check.sh b/ansible/files/admin_api_scripts/pg_upgrade_scripts/check.sh index f85e9571b6..2956063e42 100755 --- a/ansible/files/admin_api_scripts/pg_upgrade_scripts/check.sh +++ b/ansible/files/admin_api_scripts/pg_upgrade_scripts/check.sh @@ -8,9 +8,8 @@ set -euo pipefail STATUS_FILE="/tmp/pg-upgrade-status" if [ -f "${STATUS_FILE}" ]; then - STATUS=$(cat "${STATUS_FILE}") - echo -n "${STATUS}" + STATUS=$(cat "${STATUS_FILE}") + echo -n "${STATUS}" else - echo -n "unknown" + echo -n "unknown" fi - diff --git a/ansible/files/admin_api_scripts/pg_upgrade_scripts/common.sh b/ansible/files/admin_api_scripts/pg_upgrade_scripts/common.sh index e9e3afe8a2..a3f6f2081f 100755 --- a/ansible/files/admin_api_scripts/pg_upgrade_scripts/common.sh +++ b/ansible/files/admin_api_scripts/pg_upgrade_scripts/common.sh @@ -7,100 +7,100 @@ REPORTING_CREDENTIALS_FILE="/root/upgrade-reporting-credentials" REPORTING_ANON_KEY="" if [ -f "$REPORTING_CREDENTIALS_FILE" ]; then - REPORTING_ANON_KEY=$(cat "$REPORTING_CREDENTIALS_FILE") + REPORTING_ANON_KEY=$(cat "$REPORTING_CREDENTIALS_FILE") fi # shellcheck disable=SC2120 # Arguments are passed in other files function run_sql { - psql -h localhost -U supabase_admin -d postgres "$@" + psql -h localhost -U supabase_admin -d postgres "$@" } function ship_logs { - LOG_FILE=$1 - - if [ -z "$REPORTING_ANON_KEY" ]; then - echo "No reporting key found. Skipping log upload." - return 0 - fi - - if [ ! -f "$LOG_FILE" ]; then - echo "No log file found. Skipping log upload." - return 0 - fi - - if [ ! -s "$LOG_FILE" ]; then - echo "Log file is empty. Skipping log upload." - return 0 - fi - - HOSTNAME=$(hostname) - DERIVED_REF="${HOSTNAME##*-}" - - printf -v BODY '{ "ref": "%s", "step": "%s", "content": %s }' "$DERIVED_REF" "completion" "$(cat "$LOG_FILE" | jq -Rs '.')" - curl -sf -X POST "https://$REPORTING_PROJECT_REF.supabase.co/rest/v1/error_logs" \ - -H "apikey: ${REPORTING_ANON_KEY}" \ - -H 'Content-type: application/json' \ - -d "$BODY" + LOG_FILE=$1 + + if [ -z "$REPORTING_ANON_KEY" ]; then + echo "No reporting key found. Skipping log upload." + return 0 + fi + + if [ ! -f "$LOG_FILE" ]; then + echo "No log file found. Skipping log upload." + return 0 + fi + + if [ ! -s "$LOG_FILE" ]; then + echo "Log file is empty. Skipping log upload." + return 0 + fi + + HOSTNAME=$(hostname) + DERIVED_REF="${HOSTNAME##*-}" + + printf -v BODY '{ "ref": "%s", "step": "%s", "content": %s }' "$DERIVED_REF" "completion" "$(cat "$LOG_FILE" | jq -Rs '.')" + curl -sf -X POST "https://$REPORTING_PROJECT_REF.supabase.co/rest/v1/error_logs" \ + -H "apikey: ${REPORTING_ANON_KEY}" \ + -H 'Content-type: application/json' \ + -d "$BODY" } function retry { - local retries=$1 - shift - - local count=0 - until "$@"; do - exit=$? - wait=$((2 ** (count + 1))) - count=$((count + 1)) - if [ $count -lt "$retries" ]; then - echo "Command $* exited with code $exit, retrying..." - sleep $wait - else - echo "Command $* exited with code $exit, no more retries left." - return $exit - fi - done - return 0 + local retries=$1 + shift + + local count=0 + until "$@"; do + exit=$? + wait=$((2 ** (count + 1))) + count=$((count + 1)) + if [ $count -lt "$retries" ]; then + echo "Command $* exited with code $exit, retrying..." + sleep $wait + else + echo "Command $* exited with code $exit, no more retries left." + return $exit + fi + done + return 0 } CI_stop_postgres() { - BINDIR=$(pg_config --bindir) - ARG=${1:-""} + BINDIR=$(pg_config --bindir) + ARG=${1:-""} - if [ "$ARG" = "--new-bin" ]; then - BINDIR="/tmp/pg_upgrade_bin/$PG_MAJOR_VERSION/bin" - fi + if [ "$ARG" = "--new-bin" ]; then + BINDIR="/tmp/pg_upgrade_bin/$PG_MAJOR_VERSION/bin" + fi - su postgres -c "$BINDIR/pg_ctl stop -o '-c config_file=/etc/postgresql/postgresql.conf' -l /tmp/postgres.log" + su postgres -c "$BINDIR/pg_ctl stop -o '-c config_file=/etc/postgresql/postgresql.conf' -l /tmp/postgres.log" } CI_start_postgres() { - BINDIR=$(pg_config --bindir) - ARG=${1:-""} + BINDIR=$(pg_config --bindir) + ARG=${1:-""} - if [ "$ARG" = "--new-bin" ]; then - BINDIR="/tmp/pg_upgrade_bin/$PG_MAJOR_VERSION/bin" - fi + if [ "$ARG" = "--new-bin" ]; then + BINDIR="/tmp/pg_upgrade_bin/$PG_MAJOR_VERSION/bin" + fi - su postgres -c "$BINDIR/pg_ctl start -o '-c config_file=/etc/postgresql/postgresql.conf' -l /tmp/postgres.log" + su postgres -c "$BINDIR/pg_ctl start -o '-c config_file=/etc/postgresql/postgresql.conf' -l /tmp/postgres.log" } swap_postgres_and_supabase_admin() { - run_sql <<'EOSQL' + run_sql <<'EOSQL' alter database postgres connection limit 0; select pg_terminate_backend(pid) from pg_stat_activity where backend_type = 'client backend' and pid != pg_backend_pid(); EOSQL - if [ -z "$IS_CI" ]; then - retry 5 systemctl restart postgresql - else - CI_start_postgres "" - fi + if [ -z "$IS_CI" ]; then + retry 5 systemctl restart postgresql + else + CI_start_postgres "" + fi - retry 8 pg_isready -h localhost -U supabase_admin + retry 8 pg_isready -h localhost -U supabase_admin - run_sql <<'EOSQL' + run_sql <<'EOSQL' set statement_timeout = '600s'; begin; create role supabase_tmp superuser; diff --git a/ansible/files/admin_api_scripts/pg_upgrade_scripts/complete.sh b/ansible/files/admin_api_scripts/pg_upgrade_scripts/complete.sh index 3b629e5a7f..5bdb587088 100755 --- a/ansible/files/admin_api_scripts/pg_upgrade_scripts/complete.sh +++ b/ansible/files/admin_api_scripts/pg_upgrade_scripts/complete.sh @@ -7,58 +7,58 @@ set -eEuo pipefail -SCRIPT_DIR=$(dirname -- "$0";) +SCRIPT_DIR=$(dirname -- "$0") # shellcheck disable=SC1091 source "$SCRIPT_DIR/common.sh" IS_CI=${IS_CI:-} LOG_FILE="/var/log/pg-upgrade-complete.log" - # Wait for the volume mapped to /data to appear before attempting to mount it function wait_for_data_device { - local fstab_src dev="" - fstab_src=$(awk '$2 == "/data" {print $1}' /etc/fstab) - if [ -z "$fstab_src" ]; then - echo "No /data entry in /etc/fstab" - return 1 - fi - - echo "Waiting for /data device ($fstab_src) to appear" - for _ in $(seq 1 60); do - dev=$(findfs "$fstab_src" 2>/dev/null) || dev="" - if [ -n "$dev" ] && [ -b "$dev" ]; then - echo "/data device ($dev) is available" - return 0 - fi - sleep 1 - done - echo "Timed out waiting for /data device ($fstab_src)" - return 1 + local fstab_src dev="" + fstab_src=$(awk '$2 == "/data" {print $1}' /etc/fstab) + if [ -z "$fstab_src" ]; then + echo "No /data entry in /etc/fstab" + return 1 + fi + + echo "Waiting for /data device ($fstab_src) to appear" + for _ in $(seq 1 60); do + dev=$(findfs "$fstab_src" 2>/dev/null) || dev="" + if [ -n "$dev" ] && [ -b "$dev" ]; then + echo "/data device ($dev) is available" + return 0 + fi + sleep 1 + done + echo "Timed out waiting for /data device ($fstab_src)" + return 1 } function cleanup { - UPGRADE_STATUS=${1:-"failed"} - EXIT_CODE=${?:-0} + UPGRADE_STATUS=${1:-"failed"} + EXIT_CODE=${?:-0} - echo "$UPGRADE_STATUS" > /tmp/pg-upgrade-status + echo "$UPGRADE_STATUS" >/tmp/pg-upgrade-status - ship_logs "$LOG_FILE" || true + ship_logs "$LOG_FILE" || true - exit "$EXIT_CODE" + exit "$EXIT_CODE" } function execute_extension_upgrade_patches { - if [ -f "/var/lib/postgresql/extension/wrappers--0.3.1--0.4.1.sql" ] && [ ! -f "/usr/share/postgresql/15/extension/wrappers--0.3.0--0.4.1.sql" ]; then - cp /var/lib/postgresql/extension/wrappers--0.3.1--0.4.1.sql /var/lib/postgresql/extension/wrappers--0.3.0--0.4.1.sql - ln -s /var/lib/postgresql/extension/wrappers--0.3.0--0.4.1.sql /usr/share/postgresql/15/extension/wrappers--0.3.0--0.4.1.sql - fi + if [ -f "/var/lib/postgresql/extension/wrappers--0.3.1--0.4.1.sql" ] && [ ! -f "/usr/share/postgresql/15/extension/wrappers--0.3.0--0.4.1.sql" ]; then + cp /var/lib/postgresql/extension/wrappers--0.3.1--0.4.1.sql /var/lib/postgresql/extension/wrappers--0.3.0--0.4.1.sql + ln -s /var/lib/postgresql/extension/wrappers--0.3.0--0.4.1.sql /usr/share/postgresql/15/extension/wrappers--0.3.0--0.4.1.sql + fi } function execute_wrappers_patch { - # If upgrading to pgsodium-less Vault, Wrappers need to be updated so that - # foreign servers use `vault.secrets.id` instead of `vault.secrets.key_id` - UPDATE_WRAPPERS_SERVER_OPTIONS_QUERY=$(cat < 0 from pg_extension where extname = 'pg_net';") + # Patch pg_net grants + PG_NET_ENABLED=$(run_sql -A -t -c "select count(*) > 0 from pg_extension where extname = 'pg_net';") - if [ "$PG_NET_ENABLED" = "t" ]; then - PG_NET_GRANT_QUERY=$(cat < 0 from pg_extension where extname = 'pg_cron' and extowner::regrole::text = 'postgres';") + # Patching pg_cron ownership as it resets during upgrade + HAS_PG_CRON_OWNED_BY_POSTGRES=$(run_sql -A -t -c "select count(*) > 0 from pg_extension where extname = 'pg_cron' and extowner::regrole::text = 'postgres';") - if [ "$HAS_PG_CRON_OWNED_BY_POSTGRES" = "t" ]; then - RECREATE_PG_CRON_QUERY=$(cat < 0 from pg_extension where extname = 'pgmq';") - if [ "$HAS_PGMQ" = "t" ]; then - run_sql -c "update pg_extension set extowner = 'postgres'::regrole where extname = 'pgmq';" - fi + # Patching pgmq ownership as it resets during upgrade + HAS_PGMQ=$(run_sql -A -t -c "select count(*) > 0 from pg_extension where extname = 'pgmq';") + if [ "$HAS_PGMQ" = "t" ]; then + run_sql -c "update pg_extension set extowner = 'postgres'::regrole where extname = 'pgmq';" + fi - # Patch to handle upgrading to pgsodium-less Vault - REENCRYPT_VAULT_SECRETS_QUERY=$(cat < /tmp/pg-upgrade-status - - echo "1. Mounting data disk" - if [ -z "$IS_CI" ]; then - # Let udev finish detecting the vollume before mounting - udevadm settle --timeout=60 || true - wait_for_data_device - - retry 8 mount -a -v - - # `nofail` in /etc/fstab makes `mount -a` exit with a code of 0 even when the volume is absent - # In the offchance of the volume not being mounted or detected, explicitly fail here - if ! mountpoint -q /data; then - echo "FATAL: /data is not a mountpoint" - exit 1 - fi - else - echo "Skipping mount -a -v" - fi - - # copying custom configurations - echo "2. Copying custom configurations" - retry 3 copy_configs - - echo "3. Starting postgresql" - if [ -z "$IS_CI" ]; then - retry 3 service postgresql start - else - CI_start_postgres --new-bin - fi - - execute_extension_upgrade_patches || true - - # For this to work we need `vault.secrets` from the old project to be - # preserved, but `run_generated_sql` includes `ALTER EXTENSION - # supabase_vault UPDATE` which modifies that. So we need to run it - # beforehand. - echo "3.1. Patch Wrappers server options" - execute_wrappers_patch - - echo "4. Running generated SQL files" - retry 3 run_generated_sql - - echo "4.1. Applying patches" - execute_patches || true - - run_sql -c "ALTER USER postgres WITH NOSUPERUSER;" - - echo "4.2. Applying authentication scheme updates" - retry 3 apply_auth_scheme_updates - - sleep 5 - - echo "5. Restarting postgresql" - if [ -z "$IS_CI" ]; then - retry 3 service postgresql restart - - echo "5.1. Restarting gotrue and postgrest" - retry 3 service gotrue restart - retry 3 service postgrest restart - - else - retry 3 CI_stop_postgres || true - retry 3 CI_start_postgres - fi - - echo "6. Starting vacuum analyze" - retry 3 start_vacuum_analyze + if [ -f /tmp/pg-upgrade-status ]; then + echo "Upgrade job already started. Bailing." + exit 0 + fi + + echo "running" >/tmp/pg-upgrade-status + + echo "1. Mounting data disk" + if [ -z "$IS_CI" ]; then + # Let udev finish detecting the vollume before mounting + udevadm settle --timeout=60 || true + wait_for_data_device + + retry 8 mount -a -v + + # `nofail` in /etc/fstab makes `mount -a` exit with a code of 0 even when the volume is absent + # In the offchance of the volume not being mounted or detected, explicitly fail here + if ! mountpoint -q /data; then + echo "FATAL: /data is not a mountpoint" + exit 1 + fi + else + echo "Skipping mount -a -v" + fi + + # copying custom configurations + echo "2. Copying custom configurations" + retry 3 copy_configs + + echo "3. Starting postgresql" + if [ -z "$IS_CI" ]; then + retry 3 service postgresql start + else + CI_start_postgres --new-bin + fi + + execute_extension_upgrade_patches || true + + # For this to work we need `vault.secrets` from the old project to be + # preserved, but `run_generated_sql` includes `ALTER EXTENSION + # supabase_vault UPDATE` which modifies that. So we need to run it + # beforehand. + echo "3.1. Patch Wrappers server options" + execute_wrappers_patch + + echo "4. Running generated SQL files" + retry 3 run_generated_sql + + echo "4.1. Applying patches" + execute_patches || true + + run_sql -c "ALTER USER postgres WITH NOSUPERUSER;" + + echo "4.2. Applying authentication scheme updates" + retry 3 apply_auth_scheme_updates + + sleep 5 + + echo "5. Restarting postgresql" + if [ -z "$IS_CI" ]; then + retry 3 service postgresql restart + + echo "5.1. Restarting gotrue and postgrest" + retry 3 service gotrue restart + retry 3 service postgrest restart + + else + retry 3 CI_stop_postgres || true + retry 3 CI_start_postgres + fi + + echo "6. Starting vacuum analyze" + retry 3 start_vacuum_analyze } function copy_configs { - cp -R /data/conf/* /etc/postgresql-custom/ - chown -R postgres:postgres /var/lib/postgresql/data - chown -R postgres:postgres /data/pgdata - chmod -R 0750 /data/pgdata + cp -R /data/conf/* /etc/postgresql-custom/ + chown -R postgres:postgres /var/lib/postgresql/data + chown -R postgres:postgres /data/pgdata + chmod -R 0750 /data/pgdata } function run_generated_sql { - if [ -d /data/sql ]; then - for FILE in /data/sql/*.sql; do - if [ -f "$FILE" ]; then - run_sql -f "$FILE" || true - fi - done - fi + if [ -d /data/sql ]; then + for FILE in /data/sql/*.sql; do + if [ -f "$FILE" ]; then + run_sql -f "$FILE" || true + fi + done + fi } # Projects which had their passwords hashed using md5 need to have their passwords reset # Passwords for managed roles are already present in /etc/postgresql.schema.sql function apply_auth_scheme_updates { - PASSWORD_ENCRYPTION_SETTING=$(run_sql -A -t -c "SHOW password_encryption;") - if [ "$PASSWORD_ENCRYPTION_SETTING" = "md5" ]; then - run_sql -c "ALTER SYSTEM SET password_encryption TO 'scram-sha-256';" - run_sql -c "SELECT pg_reload_conf();" - - if [ -z "$IS_CI" ]; then - run_sql -f /etc/postgresql.schema.sql - fi - fi + PASSWORD_ENCRYPTION_SETTING=$(run_sql -A -t -c "SHOW password_encryption;") + if [ "$PASSWORD_ENCRYPTION_SETTING" = "md5" ]; then + run_sql -c "ALTER SYSTEM SET password_encryption TO 'scram-sha-256';" + run_sql -c "SELECT pg_reload_conf();" + + if [ -z "$IS_CI" ]; then + run_sql -f /etc/postgresql.schema.sql + fi + fi } function start_vacuum_analyze { - echo "complete" > /tmp/pg-upgrade-status - - # shellcheck disable=SC1091 - if [ -f "/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh" ]; then - # shellcheck disable=SC1091 - source "/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh" - fi - vacuumdb --all --analyze-in-stages -U supabase_admin -h localhost -p 5432 - echo "Upgrade job completed" + echo "complete" >/tmp/pg-upgrade-status + + # shellcheck disable=SC1091 + if [ -f "/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh" ]; then + # shellcheck disable=SC1091 + source "/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh" + fi + vacuumdb --all --analyze-in-stages -U supabase_admin -h localhost -p 5432 + echo "Upgrade job completed" } trap cleanup ERR -echo "C.UTF-8 UTF-8" > /etc/locale.gen -echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen +echo "C.UTF-8 UTF-8" >/etc/locale.gen +echo "en_US.UTF-8 UTF-8" >>/etc/locale.gen locale-gen if [ -z "$IS_CI" ]; then - complete_pg_upgrade >> $LOG_FILE 2>&1 & + complete_pg_upgrade >>$LOG_FILE 2>&1 & else - CI_stop_postgres || true + CI_stop_postgres || true - rm -f /tmp/pg-upgrade-status - mv /data_migration /data + rm -f /tmp/pg-upgrade-status + mv /data_migration /data - rm -rf /var/lib/postgresql/data - ln -s /data/pgdata /var/lib/postgresql/data + rm -rf /var/lib/postgresql/data + ln -s /data/pgdata /var/lib/postgresql/data - complete_pg_upgrade + complete_pg_upgrade fi diff --git a/ansible/files/admin_api_scripts/pg_upgrade_scripts/initiate.sh b/ansible/files/admin_api_scripts/pg_upgrade_scripts/initiate.sh index 49fec29005..64020bf04c 100755 --- a/ansible/files/admin_api_scripts/pg_upgrade_scripts/initiate.sh +++ b/ansible/files/admin_api_scripts/pg_upgrade_scripts/initiate.sh @@ -10,23 +10,23 @@ # Running an upgrade with these extensions enabled will result in errors due to # them depending on regtypes referencing system OIDs or outdated library files. EXTENSIONS_TO_DISABLE=( - "pg_graphql" - "pg_stat_monitor" - "pg_backtrace" + "pg_graphql" + "pg_stat_monitor" + "pg_backtrace" ) PG14_EXTENSIONS_TO_DISABLE=( - "wrappers" - "pgrouting" + "wrappers" + "pgrouting" ) PG13_EXTENSIONS_TO_DISABLE=( - "pgrouting" + "pgrouting" ) set -eEuo pipefail -SCRIPT_DIR=$(dirname -- "$0";) +SCRIPT_DIR=$(dirname -- "$0") # shellcheck disable=SC1091 source "$SCRIPT_DIR/common.sh" @@ -44,9 +44,9 @@ POST_UPGRADE_POSTGRES_PERMS_SCRIPT="/tmp/pg_upgrade/pg_upgrade_postgres_perms.sq OLD_PGVERSION=$(run_sql -A -t -c "SHOW server_version;") # Skip locale settings if both versions are PostgreSQL 16+ -if ! [[ "${OLD_PGVERSION%%.*}" -ge 16 && "${PGVERSION%%.*}" -ge 16 ]]; then - SERVER_LC_COLLATE=$(run_sql -A -t -c "SHOW lc_collate;") - SERVER_LC_CTYPE=$(run_sql -A -t -c "SHOW lc_ctype;") +if ! [[ ${OLD_PGVERSION%%.*} -ge 16 && ${PGVERSION%%.*} -ge 16 ]]; then + SERVER_LC_COLLATE=$(run_sql -A -t -c "SHOW lc_collate;") + SERVER_LC_CTYPE=$(run_sql -A -t -c "SHOW lc_ctype;") fi SERVER_ENCODING=$(run_sql -A -t -c "SHOW server_encoding;") @@ -59,87 +59,87 @@ NIX_INSTALLER_PATH="/tmp/persistent/nix-installer" NIX_INSTALLER_PACKAGE_PATH="$NIX_INSTALLER_PATH.tar.gz" if [ -L "$PGBINOLD/pg_upgrade" ]; then - BINARY_PATH=$(readlink -f "$PGBINOLD/pg_upgrade") - if [[ "$BINARY_PATH" == *"nix"* ]]; then - IS_NIX_BASED_SYSTEM="true" - fi + BINARY_PATH=$(readlink -f "$PGBINOLD/pg_upgrade") + if [[ $BINARY_PATH == *"nix"* ]]; then + IS_NIX_BASED_SYSTEM="true" + fi fi # If upgrading from older major PG versions, disable specific extensions -if [[ "$OLD_PGVERSION" =~ ^14.* ]]; then - EXTENSIONS_TO_DISABLE+=("${PG14_EXTENSIONS_TO_DISABLE[@]}") -elif [[ "$OLD_PGVERSION" =~ ^13.* ]]; then - EXTENSIONS_TO_DISABLE+=("${PG13_EXTENSIONS_TO_DISABLE[@]}") -elif [[ "$OLD_PGVERSION" =~ ^12.* ]]; then - POSTGRES_CONFIG_PATH="/etc/postgresql/12/main/postgresql.conf" - PGBINOLD="/usr/lib/postgresql/12/bin" +if [[ $OLD_PGVERSION =~ ^14.* ]]; then + EXTENSIONS_TO_DISABLE+=("${PG14_EXTENSIONS_TO_DISABLE[@]}") +elif [[ $OLD_PGVERSION =~ ^13.* ]]; then + EXTENSIONS_TO_DISABLE+=("${PG13_EXTENSIONS_TO_DISABLE[@]}") +elif [[ $OLD_PGVERSION =~ ^12.* ]]; then + POSTGRES_CONFIG_PATH="/etc/postgresql/12/main/postgresql.conf" + PGBINOLD="/usr/lib/postgresql/12/bin" fi if [ -n "$IS_CI" ]; then - PGBINOLD="$(pg_config --bindir)" - echo "Running in CI mode; using pg_config bindir: $PGBINOLD" - echo "PGVERSION: $PGVERSION" + PGBINOLD="$(pg_config --bindir)" + echo "Running in CI mode; using pg_config bindir: $PGBINOLD" + echo "PGVERSION: $PGVERSION" fi OLD_BOOTSTRAP_USER=$(run_sql -A -t -c "select rolname from pg_authid where oid = 10;") cleanup() { - UPGRADE_STATUS=${1:-"failed"} - EXIT_CODE=${?:-0} - - if [ "$UPGRADE_STATUS" = "failed" ]; then - EXIT_CODE=1 - fi - - if [ "$UPGRADE_STATUS" = "failed" ]; then - echo "Upgrade job failed. Cleaning up and exiting." - fi - - if [ -d "${MOUNT_POINT}/pgdata/pg_upgrade_output.d/" ]; then - echo "Copying pg_upgrade output to /var/log" - cp -R "${MOUNT_POINT}/pgdata/pg_upgrade_output.d/" /var/log/ || true - chown -R postgres:postgres /var/log/pg_upgrade_output.d/ - chmod -R 0750 /var/log/pg_upgrade_output.d/ - ship_logs "$LOG_FILE" || true - tail -n +1 /var/log/pg_upgrade_output.d/*/* > /var/log/pg_upgrade_output.d/pg_upgrade.log || true - ship_logs "/var/log/pg_upgrade_output.d/pg_upgrade.log" || true - fi - - if [ -L "/usr/share/postgresql/${PGVERSION}" ]; then - rm "/usr/share/postgresql/${PGVERSION}" - - if [ -f "/usr/share/postgresql/${PGVERSION}.bak" ]; then - mv "/usr/share/postgresql/${PGVERSION}.bak" "/usr/share/postgresql/${PGVERSION}" - fi - - if [ -d "/usr/share/postgresql/${PGVERSION}.bak" ]; then - mv "/usr/share/postgresql/${PGVERSION}.bak" "/usr/share/postgresql/${PGVERSION}" - fi - fi - - echo "Restarting postgresql" - if [ -z "$IS_CI" ]; then - systemctl enable postgresql - retry 5 systemctl restart postgresql - else - CI_start_postgres - fi - - retry 8 pg_isready -h localhost -U supabase_admin - - echo "Re-enabling extensions" - if [ -f $POST_UPGRADE_EXTENSION_SCRIPT ]; then - retry 5 run_sql -f $POST_UPGRADE_EXTENSION_SCRIPT - fi - - echo "Removing SUPERUSER grant from postgres" - retry 5 run_sql -c "ALTER USER postgres WITH NOSUPERUSER;" - - echo "Resetting postgres database connection limit" - retry 5 run_sql -c "ALTER DATABASE postgres CONNECTION LIMIT -1;" - - echo "Making sure postgres still has access to pg_shadow" - cat << EOF >> $POST_UPGRADE_POSTGRES_PERMS_SCRIPT + UPGRADE_STATUS=${1:-"failed"} + EXIT_CODE=${?:-0} + + if [ "$UPGRADE_STATUS" = "failed" ]; then + EXIT_CODE=1 + fi + + if [ "$UPGRADE_STATUS" = "failed" ]; then + echo "Upgrade job failed. Cleaning up and exiting." + fi + + if [ -d "${MOUNT_POINT}/pgdata/pg_upgrade_output.d/" ]; then + echo "Copying pg_upgrade output to /var/log" + cp -R "${MOUNT_POINT}/pgdata/pg_upgrade_output.d/" /var/log/ || true + chown -R postgres:postgres /var/log/pg_upgrade_output.d/ + chmod -R 0750 /var/log/pg_upgrade_output.d/ + ship_logs "$LOG_FILE" || true + tail -n +1 /var/log/pg_upgrade_output.d/*/* >/var/log/pg_upgrade_output.d/pg_upgrade.log || true + ship_logs "/var/log/pg_upgrade_output.d/pg_upgrade.log" || true + fi + + if [ -L "/usr/share/postgresql/${PGVERSION}" ]; then + rm "/usr/share/postgresql/${PGVERSION}" + + if [ -f "/usr/share/postgresql/${PGVERSION}.bak" ]; then + mv "/usr/share/postgresql/${PGVERSION}.bak" "/usr/share/postgresql/${PGVERSION}" + fi + + if [ -d "/usr/share/postgresql/${PGVERSION}.bak" ]; then + mv "/usr/share/postgresql/${PGVERSION}.bak" "/usr/share/postgresql/${PGVERSION}" + fi + fi + + echo "Restarting postgresql" + if [ -z "$IS_CI" ]; then + systemctl enable postgresql + retry 5 systemctl restart postgresql + else + CI_start_postgres + fi + + retry 8 pg_isready -h localhost -U supabase_admin + + echo "Re-enabling extensions" + if [ -f $POST_UPGRADE_EXTENSION_SCRIPT ]; then + retry 5 run_sql -f $POST_UPGRADE_EXTENSION_SCRIPT + fi + + echo "Removing SUPERUSER grant from postgres" + retry 5 run_sql -c "ALTER USER postgres WITH NOSUPERUSER;" + + echo "Resetting postgres database connection limit" + retry 5 run_sql -c "ALTER DATABASE postgres CONNECTION LIMIT -1;" + + echo "Making sure postgres still has access to pg_shadow" + cat <>$POST_UPGRADE_POSTGRES_PERMS_SCRIPT DO \$\$ begin if exists (select from pg_authid where rolname = 'pg_read_all_data') then @@ -150,54 +150,54 @@ end grant pg_signal_backend to postgres; EOF - if [ -f $POST_UPGRADE_POSTGRES_PERMS_SCRIPT ]; then - retry 5 run_sql -f $POST_UPGRADE_POSTGRES_PERMS_SCRIPT - fi - - if [ -z "$IS_CI" ] && [ -z "$IS_LOCAL_UPGRADE" ]; then - echo "Unmounting data disk from ${MOUNT_POINT}" - retry 3 umount $MOUNT_POINT - fi - echo "$UPGRADE_STATUS" > /tmp/pg-upgrade-status - - if [ -z "$IS_CI" ]; then - exit "$EXIT_CODE" - else - echo "CI run complete with code ${EXIT_CODE}. Exiting." - exit "$EXIT_CODE" - fi + if [ -f $POST_UPGRADE_POSTGRES_PERMS_SCRIPT ]; then + retry 5 run_sql -f $POST_UPGRADE_POSTGRES_PERMS_SCRIPT + fi + + if [ -z "$IS_CI" ] && [ -z "$IS_LOCAL_UPGRADE" ]; then + echo "Unmounting data disk from ${MOUNT_POINT}" + retry 3 umount $MOUNT_POINT + fi + echo "$UPGRADE_STATUS" >/tmp/pg-upgrade-status + + if [ -z "$IS_CI" ]; then + exit "$EXIT_CODE" + else + echo "CI run complete with code ${EXIT_CODE}. Exiting." + exit "$EXIT_CODE" + fi } function handle_extensions { - if [ -z "$IS_CI" ]; then - retry 5 systemctl restart postgresql - else - CI_start_postgres - fi + if [ -z "$IS_CI" ]; then + retry 5 systemctl restart postgresql + else + CI_start_postgres + fi - retry 8 pg_isready -h localhost -U supabase_admin + retry 8 pg_isready -h localhost -U supabase_admin - rm -f $POST_UPGRADE_EXTENSION_SCRIPT - touch $POST_UPGRADE_EXTENSION_SCRIPT + rm -f $POST_UPGRADE_EXTENSION_SCRIPT + touch $POST_UPGRADE_EXTENSION_SCRIPT - PASSWORD_ENCRYPTION_SETTING=$(run_sql -A -t -c "SHOW password_encryption;") - if [ "$PASSWORD_ENCRYPTION_SETTING" = "md5" ]; then - echo "ALTER SYSTEM SET password_encryption = 'md5';" >> $POST_UPGRADE_EXTENSION_SCRIPT - fi + PASSWORD_ENCRYPTION_SETTING=$(run_sql -A -t -c "SHOW password_encryption;") + if [ "$PASSWORD_ENCRYPTION_SETTING" = "md5" ]; then + echo "ALTER SYSTEM SET password_encryption = 'md5';" >>$POST_UPGRADE_EXTENSION_SCRIPT + fi - cat << EOF >> $POST_UPGRADE_EXTENSION_SCRIPT + cat <>$POST_UPGRADE_EXTENSION_SCRIPT ALTER SYSTEM SET jit = off; SELECT pg_reload_conf(); EOF - # Disable extensions if they're enabled - # Generate SQL script to re-enable them after upgrade - for EXTENSION in "${EXTENSIONS_TO_DISABLE[@]}"; do - EXTENSION_ENABLED=$(run_sql -A -t -c "SELECT EXISTS(SELECT 1 FROM pg_extension WHERE extname = '${EXTENSION}');") - if [ "$EXTENSION_ENABLED" = "t" ]; then - echo "Disabling extension ${EXTENSION}" - run_sql -c "DROP EXTENSION IF EXISTS ${EXTENSION} CASCADE;" - cat << EOF >> $POST_UPGRADE_EXTENSION_SCRIPT + # Disable extensions if they're enabled + # Generate SQL script to re-enable them after upgrade + for EXTENSION in "${EXTENSIONS_TO_DISABLE[@]}"; do + EXTENSION_ENABLED=$(run_sql -A -t -c "SELECT EXISTS(SELECT 1 FROM pg_extension WHERE extname = '${EXTENSION}');") + if [ "$EXTENSION_ENABLED" = "t" ]; then + echo "Disabling extension ${EXTENSION}" + run_sql -c "DROP EXTENSION IF EXISTS ${EXTENSION} CASCADE;" + cat <>$POST_UPGRADE_EXTENSION_SCRIPT DO \$\$ BEGIN IF EXISTS (SELECT 1 FROM pg_available_extensions WHERE name = '${EXTENSION}') THEN @@ -206,313 +206,314 @@ BEGIN END; \$\$; EOF - fi - done + fi + done } function initiate_upgrade { - mkdir -p "$MOUNT_POINT" - SHARED_PRELOAD_LIBRARIES=$(grep '^[[:space:]]*shared_preload_libraries' "$POSTGRES_CONFIG_PATH" | sed "s/shared_preload_libraries =\s\{0,1\}'\(.*\)'.*/\1/") - - # Wrappers officially launched in PG15; PG14 version is incompatible - if [[ "$OLD_PGVERSION" =~ 14* ]]; then - SHARED_PRELOAD_LIBRARIES=$(echo "$SHARED_PRELOAD_LIBRARIES" | sed "s/wrappers//" | xargs) - fi - - # Timescale is no longer supported for PG17+ upgrades - if [[ "$PGVERSION" != "15" ]]; then - SHARED_PRELOAD_LIBRARIES=$(echo "$SHARED_PRELOAD_LIBRARIES" | sed "s/timescaledb//" | xargs) - fi - - SHARED_PRELOAD_LIBRARIES=$(echo "$SHARED_PRELOAD_LIBRARIES" | sed "s/pg_cron//" | xargs) - SHARED_PRELOAD_LIBRARIES=$(echo "$SHARED_PRELOAD_LIBRARIES" | sed "s/pg_net//" | xargs) - SHARED_PRELOAD_LIBRARIES=$(echo "$SHARED_PRELOAD_LIBRARIES" | sed "s/check_role_membership//" | xargs) - SHARED_PRELOAD_LIBRARIES=$(echo "$SHARED_PRELOAD_LIBRARIES" | sed "s/safeupdate//" | xargs) - SHARED_PRELOAD_LIBRARIES=$(echo "$SHARED_PRELOAD_LIBRARIES" | sed "s/pg_backtrace//" | xargs) - - # Exclude empty-string entries, as well as leading/trailing commas and spaces resulting from the above lib exclusions - # i.e. " , pg_stat_statements, , pgsodium, " -> "pg_stat_statements, pgsodium" - SHARED_PRELOAD_LIBRARIES=$(echo "$SHARED_PRELOAD_LIBRARIES" | tr ',' ' ' | tr -s ' ' | tr ' ' ', ') - - # Account for trailing comma - # eg. "...,auto_explain,pg_tle,plan_filter," -> "...,auto_explain,pg_tle,plan_filter" - if [[ "${SHARED_PRELOAD_LIBRARIES: -1}" = "," ]]; then - # clean up trailing comma - SHARED_PRELOAD_LIBRARIES=$(echo "$SHARED_PRELOAD_LIBRARIES" | sed "s/.$//" | xargs) - fi - - PGDATAOLD=$(grep '^[[:space:]]*data_directory' "$POSTGRES_CONFIG_PATH" | sed "s/data_directory = '\(.*\)'.*/\1/") - - # Check if old cluster has data checksums enabled - CHECKSUM_VERSION=$("$PGBINOLD/pg_controldata" "$PGDATAOLD" | grep -i checksum | awk '{print $NF}') - if [ "$CHECKSUM_VERSION" != "0" ]; then - CHECKSUM_FLAG="--data-checksums" - else - CHECKSUM_FLAG="" - fi - - PGDATANEW="$MOUNT_POINT/pgdata" - - # running upgrade using at least 1 cpu core - WORKERS=$(nproc | awk '{ print ($1 == 1 ? 1 : $1 - 1) }') - - # To make nix-based upgrades work for testing, create a pg binaries tarball with the following contents: - # - nix_flake_version - a7189a68ed4ea78c1e73991b5f271043636cf074 - # Where the value is the commit hash of the nix flake that contains the binaries - - if [ -n "$IS_LOCAL_UPGRADE" ]; then - mkdir -p "$PG_UPGRADE_BIN_DIR" - mkdir -p /tmp/persistent/ - if [ -n "$NIX_FLAKE_VERSION" ]; then - echo "$NIX_FLAKE_VERSION" > "$PG_UPGRADE_BIN_DIR/nix_flake_version" - else - echo "a7189a68ed4ea78c1e73991b5f271043636cf074" > "$PG_UPGRADE_BIN_DIR/nix_flake_version" - fi - - tar -czf "/tmp/persistent/pg_upgrade_bin.tar.gz" -C "/tmp/pg_upgrade_bin" . - rm -rf /tmp/pg_upgrade_bin/ - fi - - echo "1. Extracting pg_upgrade binaries" - mkdir -p "/tmp/pg_upgrade_bin" - tar zxf "/tmp/persistent/pg_upgrade_bin.tar.gz" -C "/tmp/pg_upgrade_bin" - - PGSHARENEW="$PG_UPGRADE_BIN_DIR/share" - - if [ -f "$PG_UPGRADE_BIN_DIR/nix_flake_version" ]; then - IS_NIX_UPGRADE="true" - NIX_FLAKE_VERSION=$(cat "$PG_UPGRADE_BIN_DIR/nix_flake_version") - - if [ "$IS_NIX_BASED_SYSTEM" = "false" ]; then - if [ ! -f /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh ]; then - if ! command -v nix > /dev/null; then - echo "1.1. Nix is not installed; installing." - - if [ -f "$NIX_INSTALLER_PACKAGE_PATH" ]; then - echo "1.1.1. Installing Nix using the provided installer" - tar -xzf "$NIX_INSTALLER_PACKAGE_PATH" -C /tmp/persistent/ - chmod +x "$NIX_INSTALLER_PATH" - "$NIX_INSTALLER_PATH" install --no-confirm \ - --extra-conf "substituters = https://cache.nixos.org https://nix-postgres-artifacts.s3.amazonaws.com" \ - --extra-conf "trusted-public-keys = nix-postgres-artifacts:dGZlQOvKcNEjvT7QEAJbcV6b6uk7VF/hWMjhYleiaLI= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" - else - echo "1.1.1. Installing Nix using the official installer" - sh <(curl -L https://releases.nixos.org/nix/nix-2.34.6/install) --yes --daemon --nix-extra-conf-file /dev/stdin < "pg_stat_statements, pgsodium" + SHARED_PRELOAD_LIBRARIES=$(echo "$SHARED_PRELOAD_LIBRARIES" | tr ',' ' ' | tr -s ' ' | tr ' ' ', ') + + # Account for trailing comma + # eg. "...,auto_explain,pg_tle,plan_filter," -> "...,auto_explain,pg_tle,plan_filter" + if [[ ${SHARED_PRELOAD_LIBRARIES: -1} == "," ]]; then + # clean up trailing comma + SHARED_PRELOAD_LIBRARIES=$(echo "$SHARED_PRELOAD_LIBRARIES" | sed "s/.$//" | xargs) + fi + + PGDATAOLD=$(grep '^[[:space:]]*data_directory' "$POSTGRES_CONFIG_PATH" | sed "s/data_directory = '\(.*\)'.*/\1/") + + # Check if old cluster has data checksums enabled + CHECKSUM_VERSION=$("$PGBINOLD/pg_controldata" "$PGDATAOLD" | grep -i checksum | awk '{print $NF}') + if [ "$CHECKSUM_VERSION" != "0" ]; then + CHECKSUM_FLAG="--data-checksums" + else + CHECKSUM_FLAG="" + fi + + PGDATANEW="$MOUNT_POINT/pgdata" + + # running upgrade using at least 1 cpu core + WORKERS=$(nproc | awk '{ print ($1 == 1 ? 1 : $1 - 1) }') + + # To make nix-based upgrades work for testing, create a pg binaries tarball with the following contents: + # - nix_flake_version - a7189a68ed4ea78c1e73991b5f271043636cf074 + # Where the value is the commit hash of the nix flake that contains the binaries + + if [ -n "$IS_LOCAL_UPGRADE" ]; then + mkdir -p "$PG_UPGRADE_BIN_DIR" + mkdir -p /tmp/persistent/ + if [ -n "$NIX_FLAKE_VERSION" ]; then + echo "$NIX_FLAKE_VERSION" >"$PG_UPGRADE_BIN_DIR/nix_flake_version" + else + echo "a7189a68ed4ea78c1e73991b5f271043636cf074" >"$PG_UPGRADE_BIN_DIR/nix_flake_version" + fi + + tar -czf "/tmp/persistent/pg_upgrade_bin.tar.gz" -C "/tmp/pg_upgrade_bin" . + rm -rf /tmp/pg_upgrade_bin/ + fi + + echo "1. Extracting pg_upgrade binaries" + mkdir -p "/tmp/pg_upgrade_bin" + tar zxf "/tmp/persistent/pg_upgrade_bin.tar.gz" -C "/tmp/pg_upgrade_bin" + + PGSHARENEW="$PG_UPGRADE_BIN_DIR/share" + + if [ -f "$PG_UPGRADE_BIN_DIR/nix_flake_version" ]; then + IS_NIX_UPGRADE="true" + NIX_FLAKE_VERSION=$(cat "$PG_UPGRADE_BIN_DIR/nix_flake_version") + + if [ "$IS_NIX_BASED_SYSTEM" = "false" ]; then + if [ ! -f /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh ]; then + if ! command -v nix >/dev/null; then + echo "1.1. Nix is not installed; installing." + + if [ -f "$NIX_INSTALLER_PACKAGE_PATH" ]; then + echo "1.1.1. Installing Nix using the provided installer" + tar -xzf "$NIX_INSTALLER_PACKAGE_PATH" -C /tmp/persistent/ + chmod +x "$NIX_INSTALLER_PATH" + "$NIX_INSTALLER_PATH" install --no-confirm \ + --extra-conf "substituters = https://cache.nixos.org https://nix-postgres-artifacts.s3.amazonaws.com" \ + --extra-conf "trusted-public-keys = nix-postgres-artifacts:dGZlQOvKcNEjvT7QEAJbcV6b6uk7VF/hWMjhYleiaLI= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" + else + echo "1.1.1. Installing Nix using the official installer" + sh <(curl -L https://releases.nixos.org/nix/nix-2.34.6/install) --yes --daemon --nix-extra-conf-file /dev/stdin < /tmp/pg_upgrade-nix-gc.log 2>&1 || true - - # Determine system architecture - ARCH=$(uname -m) - if [ "$ARCH" = "aarch64" ]; then - SYSTEM="aarch64-linux" - elif [ "$ARCH" = "x86_64" ]; then - SYSTEM="x86_64-linux" - else - echo "ERROR: Unsupported architecture: $ARCH" - exit 1 - fi - - # Fetch store path from catalog (avoids expensive nix eval - prevents OOM on small instances) - # Each postgres version has its own catalog file: {git_sha}-psql_{version}.json - CATALOG_S3="s3://supabase-internal-artifacts/nix-catalog/${NIX_FLAKE_VERSION}-psql_${PGVERSION}-${SYSTEM}.json" - CATALOG_LOCAL="/tmp/nix-catalog-${NIX_FLAKE_VERSION}-psql_${PGVERSION}-${SYSTEM}.json" - echo "Fetching catalog from: $CATALOG_S3" - - if ! aws s3 cp "$CATALOG_S3" "$CATALOG_LOCAL" --region ap-southeast-1; then - echo "ERROR: Failed to fetch catalog from $CATALOG_S3" - exit 1 - fi - - STORE_PATH=$(jq -r ".\"${SYSTEM}\"" "$CATALOG_LOCAL") - - if [ -z "$STORE_PATH" ] || [ "$STORE_PATH" = "null" ]; then - echo "ERROR: Could not find store path in catalog for ${SYSTEM}" - echo "Catalog contents:" - jq . "$CATALOG_LOCAL" - exit 1 - fi - - echo "Store path: $STORE_PATH" - - # Realize from binary cache (no nix evaluation needed!) - nix-store -r "$STORE_PATH" - - PG_UPGRADE_BIN_DIR="$STORE_PATH" - PGSHARENEW="$PG_UPGRADE_BIN_DIR/share/postgresql" - fi - - PGBINNEW="$PG_UPGRADE_BIN_DIR/bin" - PGLIBNEW="$PG_UPGRADE_BIN_DIR/lib" - - # copy upgrade-specific pgsodium_getkey script into the share dir - chmod +x "$SCRIPT_DIR/pgsodium_getkey.sh" - mkdir -p "$PGSHARENEW/extension" - cp "$SCRIPT_DIR/pgsodium_getkey.sh" "$PGSHARENEW/extension/pgsodium_getkey" - if [ -d "/var/lib/postgresql/extension/" ]; then - cp "$SCRIPT_DIR/pgsodium_getkey.sh" "/var/lib/postgresql/extension/pgsodium_getkey" - chown postgres:postgres "/var/lib/postgresql/extension/pgsodium_getkey" - fi - - chown -R postgres:postgres "/tmp/pg_upgrade_bin/$PGVERSION" - - # upgrade job outputs a log in the cwd; needs write permissions - mkdir -p /tmp/pg_upgrade/ - chown -R postgres:postgres /tmp/pg_upgrade/ - cd /tmp/pg_upgrade/ - - # Fixing erros generated by previous dpkg executions (package upgrades et co) - echo "2. Fixing potential errors generated by dpkg" - echo "2.1 Killing off any old hanging apt-get processes" - # One hour is old enough to be bad - pkill -f apt-get --older 3600 2>/dev/null || echo "No hanging apt-get processes found" - DEBIAN_FRONTEND=noninteractive dpkg --configure -a --force-confold || true # handle errors generated by dpkg - - # Needed for PostGIS, since it's compiled with Protobuf-C support now - echo "3. Installing libprotobuf-c1 and libicu66 if missing" - if [[ ! "$(apt list --installed libprotobuf-c1 | grep "installed")" ]]; then - apt-get -o DPkg::Lock::Timeout=600 update -y # wait up to 10 minutes for any dpkg locks to clear before updating package lists - apt --fix-broken install -y libprotobuf-c1 libicu66 || true # apt has builtin 2 minute wait lock - fi - - echo "4. Setup locale if required" - if ! grep -q "^en_US.UTF-8" /etc/locale.gen ; then - echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen - fi - if ! grep -q "^C.UTF-8" /etc/locale.gen ; then - echo "C.UTF-8 UTF-8" >> /etc/locale.gen - fi - locale-gen - - if [ -z "$IS_CI" ] && [ -z "$IS_LOCAL_UPGRADE" ]; then - # DATABASE_UPGRADE_DATA_MIGRATION_DEVICE_NAME = '/dev/xvdp' can be derived from the worker mount - echo "5. Determining block device to mount" - # lsb release - UBUNTU_VERSION=$(lsb_release -rs) - # install amazon disk utilities if not present on 24.04 - if [ "${UBUNTU_VERSION}" = "24.04" ] && ! /usr/bin/dpkg-query -W amazon-ec2-utils >/dev/null 2>&1; then - apt-get -o DPkg::Lock::Timeout=600 update - apt-get -o DPkg::Lock::Timeout=600 install -y amazon-ec2-utils || true - fi - if command -v ebsnvme-id >/dev/null 2>&1 && /usr/bin/dpkg-query -W amazon-ec2-utils >/dev/null 2>&1; then - for nvme_dev in $(lsblk -dprno name,size,mountpoint,type | grep disk | awk '{print $1}'); do - if [ -b "$nvme_dev" ]; then - mapping=$(ebsnvme-id -b "$nvme_dev" 2>/dev/null) - if [[ "$mapping" == "xvdp" || $mapping == "/dev/xvdp" ]]; then - BLOCK_DEVICE="$nvme_dev" - break - fi - fi - done - fi - - # Fallback to lsblk if ebsnvme-id is not available or no mapping found, pre ubuntu 20.04 - if [ -z "${BLOCK_DEVICE:-}" ]; then - echo "No block device found using ebsnvme-id, falling back to lsblk" - # awk NF==3 prints lines with exactly 3 fields, which are the block devices currently not mounted anywhere - # excluding nvme0 since it is the root disk - BLOCK_DEVICE=$(lsblk -dprno name,size,mountpoint,type | grep "disk" | grep -v "nvme0" | awk 'NF==3 { print $1; exit }') # exit ensures we grab the first only - fi - - echo "Block device found: $BLOCK_DEVICE" - - mkdir -p "$MOUNT_POINT" - echo "6. Mounting block device" - - sleep 5 - e2fsck -pf "$BLOCK_DEVICE" - - sleep 1 - mount "$BLOCK_DEVICE" "$MOUNT_POINT" - - sleep 1 - resize2fs "$BLOCK_DEVICE" - else - mkdir -p "$MOUNT_POINT" - fi - - if [ -f "$MOUNT_POINT/pgsodium_root.key" ]; then - cp "$MOUNT_POINT/pgsodium_root.key" /etc/postgresql-custom/pgsodium_root.key - chown postgres:postgres /etc/postgresql-custom/pgsodium_root.key - chmod 600 /etc/postgresql-custom/pgsodium_root.key - fi - - echo "7. Disabling extensions and generating post-upgrade script" - handle_extensions - - echo "8.1. Granting SUPERUSER to postgres user" - run_sql -c "ALTER USER postgres WITH SUPERUSER;" - - if [ "$OLD_BOOTSTRAP_USER" = "postgres" ]; then - echo "8.2. Swap postgres & supabase_admin roles as we're upgrading a project with postgres as bootstrap user" - swap_postgres_and_supabase_admin - fi - - if [ -z "$IS_NIX_UPGRADE" ]; then - if [ -d "/usr/share/postgresql/${PGVERSION}" ]; then - mv "/usr/share/postgresql/${PGVERSION}" "/usr/share/postgresql/${PGVERSION}.bak" - fi - - ln -s "$PGSHARENEW" "/usr/share/postgresql/${PGVERSION}" - cp --remove-destination "$PGLIBNEW"/*.control "$PGSHARENEW/extension/" - cp --remove-destination "$PGLIBNEW"/*.sql "$PGSHARENEW/extension/" - - export LD_LIBRARY_PATH="${PGLIBNEW}" - fi - - echo "9. Creating new data directory, initializing database" - chown -R postgres:postgres "$MOUNT_POINT/" - rm -rf "${PGDATANEW:?}/" - - if [ "$IS_NIX_UPGRADE" = "true" ]; then - if [[ "${PGVERSION%%.*}" -ge 16 ]]; then - LC_ALL=en_US.UTF-8 LC_CTYPE=en_US.UTF-8 LC_COLLATE=en_US.UTF-8 LANGUAGE=en_US.UTF-8 LANG=en_US.UTF-8 LOCALE_ARCHIVE=/usr/lib/locale/locale-archive su -c ". /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && $PGBINNEW/initdb $CHECKSUM_FLAG --encoding=$SERVER_ENCODING --locale-provider=icu --icu-locale=en_US.UTF-8 -L $PGSHARENEW -D $PGDATANEW/ --username=supabase_admin" -s "$SHELL" postgres - else - LC_ALL=en_US.UTF-8 LC_CTYPE=$SERVER_LC_CTYPE LC_COLLATE=$SERVER_LC_COLLATE LANGUAGE=en_US.UTF-8 LANG=en_US.UTF-8 LOCALE_ARCHIVE=/usr/lib/locale/locale-archive su -c ". /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && $PGBINNEW/initdb $CHECKSUM_FLAG --encoding=$SERVER_ENCODING --lc-collate=$SERVER_LC_COLLATE --lc-ctype=$SERVER_LC_CTYPE -L $PGSHARENEW -D $PGDATANEW/ --username=supabase_admin" -s "$SHELL" postgres - fi - else - su -c "$PGBINNEW/initdb $CHECKSUM_FLAG -L $PGSHARENEW -D $PGDATANEW/ --username=supabase_admin" -s "$SHELL" postgres - - fi - - # This line avoids the need to supply the supabase_admin password on the old - # instance, since pg_upgrade connects to the db as supabase_admin using unix - # sockets, which is gated behind scram-sha-256 per pg_hba.conf.j2. The new - # instance is unaffected. - if ! grep -q "local all supabase_admin trust" /etc/postgresql/pg_hba.conf; then - echo "local all supabase_admin trust -$(cat /etc/postgresql/pg_hba.conf)" > /etc/postgresql/pg_hba.conf - run_sql -c "select pg_reload_conf();" - fi - - TMP_CONFIG="/tmp/pg_upgrade/postgresql.conf" - cp "$POSTGRES_CONFIG_PATH" "$TMP_CONFIG" - - # Check if max_slot_wal_keep_size exists in the config - # Add the setting if not found - echo "max_slot_wal_keep_size = -1" >> "$TMP_CONFIG" - - # Remove db_user_namespace if upgrading from PG15 or lower to PG16+ - if [[ "${OLD_PGVERSION%%.*}" -le 15 && "${PGVERSION%%.*}" -ge 16 ]]; then - sed -i '/^db_user_namespace/d' "$TMP_CONFIG" - fi - - chown postgres:postgres "$TMP_CONFIG" - - UPGRADE_COMMAND=$(cat </tmp/pg_upgrade-nix-gc.log 2>&1 || true + + # Determine system architecture + ARCH=$(uname -m) + if [ "$ARCH" = "aarch64" ]; then + SYSTEM="aarch64-linux" + elif [ "$ARCH" = "x86_64" ]; then + SYSTEM="x86_64-linux" + else + echo "ERROR: Unsupported architecture: $ARCH" + exit 1 + fi + + # Fetch store path from catalog (avoids expensive nix eval - prevents OOM on small instances) + # Each postgres version has its own catalog file: {git_sha}-psql_{version}.json + CATALOG_S3="s3://supabase-internal-artifacts/nix-catalog/${NIX_FLAKE_VERSION}-psql_${PGVERSION}-${SYSTEM}.json" + CATALOG_LOCAL="/tmp/nix-catalog-${NIX_FLAKE_VERSION}-psql_${PGVERSION}-${SYSTEM}.json" + echo "Fetching catalog from: $CATALOG_S3" + + if ! aws s3 cp "$CATALOG_S3" "$CATALOG_LOCAL" --region ap-southeast-1; then + echo "ERROR: Failed to fetch catalog from $CATALOG_S3" + exit 1 + fi + + STORE_PATH=$(jq -r ".\"${SYSTEM}\"" "$CATALOG_LOCAL") + + if [ -z "$STORE_PATH" ] || [ "$STORE_PATH" = "null" ]; then + echo "ERROR: Could not find store path in catalog for ${SYSTEM}" + echo "Catalog contents:" + jq . "$CATALOG_LOCAL" + exit 1 + fi + + echo "Store path: $STORE_PATH" + + # Realize from binary cache (no nix evaluation needed!) + nix-store -r "$STORE_PATH" + + PG_UPGRADE_BIN_DIR="$STORE_PATH" + PGSHARENEW="$PG_UPGRADE_BIN_DIR/share/postgresql" + fi + + PGBINNEW="$PG_UPGRADE_BIN_DIR/bin" + PGLIBNEW="$PG_UPGRADE_BIN_DIR/lib" + + # copy upgrade-specific pgsodium_getkey script into the share dir + chmod +x "$SCRIPT_DIR/pgsodium_getkey.sh" + mkdir -p "$PGSHARENEW/extension" + cp "$SCRIPT_DIR/pgsodium_getkey.sh" "$PGSHARENEW/extension/pgsodium_getkey" + if [ -d "/var/lib/postgresql/extension/" ]; then + cp "$SCRIPT_DIR/pgsodium_getkey.sh" "/var/lib/postgresql/extension/pgsodium_getkey" + chown postgres:postgres "/var/lib/postgresql/extension/pgsodium_getkey" + fi + + chown -R postgres:postgres "/tmp/pg_upgrade_bin/$PGVERSION" + + # upgrade job outputs a log in the cwd; needs write permissions + mkdir -p /tmp/pg_upgrade/ + chown -R postgres:postgres /tmp/pg_upgrade/ + cd /tmp/pg_upgrade/ + + # Fixing erros generated by previous dpkg executions (package upgrades et co) + echo "2. Fixing potential errors generated by dpkg" + echo "2.1 Killing off any old hanging apt-get processes" + # One hour is old enough to be bad + pkill -f apt-get --older 3600 2>/dev/null || echo "No hanging apt-get processes found" + DEBIAN_FRONTEND=noninteractive dpkg --configure -a --force-confold || true # handle errors generated by dpkg + + # Needed for PostGIS, since it's compiled with Protobuf-C support now + echo "3. Installing libprotobuf-c1 and libicu66 if missing" + if [[ ! "$(apt list --installed libprotobuf-c1 | grep "installed")" ]]; then + apt-get -o DPkg::Lock::Timeout=600 update -y # wait up to 10 minutes for any dpkg locks to clear before updating package lists + apt --fix-broken install -y libprotobuf-c1 libicu66 || true # apt has builtin 2 minute wait lock + fi + + echo "4. Setup locale if required" + if ! grep -q "^en_US.UTF-8" /etc/locale.gen; then + echo "en_US.UTF-8 UTF-8" >>/etc/locale.gen + fi + if ! grep -q "^C.UTF-8" /etc/locale.gen; then + echo "C.UTF-8 UTF-8" >>/etc/locale.gen + fi + locale-gen + + if [ -z "$IS_CI" ] && [ -z "$IS_LOCAL_UPGRADE" ]; then + # DATABASE_UPGRADE_DATA_MIGRATION_DEVICE_NAME = '/dev/xvdp' can be derived from the worker mount + echo "5. Determining block device to mount" + # lsb release + UBUNTU_VERSION=$(lsb_release -rs) + # install amazon disk utilities if not present on 24.04 + if [ "${UBUNTU_VERSION}" = "24.04" ] && ! /usr/bin/dpkg-query -W amazon-ec2-utils >/dev/null 2>&1; then + apt-get -o DPkg::Lock::Timeout=600 update + apt-get -o DPkg::Lock::Timeout=600 install -y amazon-ec2-utils || true + fi + if command -v ebsnvme-id >/dev/null 2>&1 && /usr/bin/dpkg-query -W amazon-ec2-utils >/dev/null 2>&1; then + for nvme_dev in $(lsblk -dprno name,size,mountpoint,type | grep disk | awk '{print $1}'); do + if [ -b "$nvme_dev" ]; then + mapping=$(ebsnvme-id -b "$nvme_dev" 2>/dev/null) + if [[ $mapping == "xvdp" || $mapping == "/dev/xvdp" ]]; then + BLOCK_DEVICE="$nvme_dev" + break + fi + fi + done + fi + + # Fallback to lsblk if ebsnvme-id is not available or no mapping found, pre ubuntu 20.04 + if [ -z "${BLOCK_DEVICE:-}" ]; then + echo "No block device found using ebsnvme-id, falling back to lsblk" + # awk NF==3 prints lines with exactly 3 fields, which are the block devices currently not mounted anywhere + # excluding nvme0 since it is the root disk + BLOCK_DEVICE=$(lsblk -dprno name,size,mountpoint,type | grep "disk" | grep -v "nvme0" | awk 'NF==3 { print $1; exit }') # exit ensures we grab the first only + fi + + echo "Block device found: $BLOCK_DEVICE" + + mkdir -p "$MOUNT_POINT" + echo "6. Mounting block device" + + sleep 5 + e2fsck -pf "$BLOCK_DEVICE" + + sleep 1 + mount "$BLOCK_DEVICE" "$MOUNT_POINT" + + sleep 1 + resize2fs "$BLOCK_DEVICE" + else + mkdir -p "$MOUNT_POINT" + fi + + if [ -f "$MOUNT_POINT/pgsodium_root.key" ]; then + cp "$MOUNT_POINT/pgsodium_root.key" /etc/postgresql-custom/pgsodium_root.key + chown postgres:postgres /etc/postgresql-custom/pgsodium_root.key + chmod 600 /etc/postgresql-custom/pgsodium_root.key + fi + + echo "7. Disabling extensions and generating post-upgrade script" + handle_extensions + + echo "8.1. Granting SUPERUSER to postgres user" + run_sql -c "ALTER USER postgres WITH SUPERUSER;" + + if [ "$OLD_BOOTSTRAP_USER" = "postgres" ]; then + echo "8.2. Swap postgres & supabase_admin roles as we're upgrading a project with postgres as bootstrap user" + swap_postgres_and_supabase_admin + fi + + if [ -z "$IS_NIX_UPGRADE" ]; then + if [ -d "/usr/share/postgresql/${PGVERSION}" ]; then + mv "/usr/share/postgresql/${PGVERSION}" "/usr/share/postgresql/${PGVERSION}.bak" + fi + + ln -s "$PGSHARENEW" "/usr/share/postgresql/${PGVERSION}" + cp --remove-destination "$PGLIBNEW"/*.control "$PGSHARENEW/extension/" + cp --remove-destination "$PGLIBNEW"/*.sql "$PGSHARENEW/extension/" + + export LD_LIBRARY_PATH="${PGLIBNEW}" + fi + + echo "9. Creating new data directory, initializing database" + chown -R postgres:postgres "$MOUNT_POINT/" + rm -rf "${PGDATANEW:?}/" + + if [ "$IS_NIX_UPGRADE" = "true" ]; then + if [[ ${PGVERSION%%.*} -ge 16 ]]; then + LC_ALL=en_US.UTF-8 LC_CTYPE=en_US.UTF-8 LC_COLLATE=en_US.UTF-8 LANGUAGE=en_US.UTF-8 LANG=en_US.UTF-8 LOCALE_ARCHIVE=/usr/lib/locale/locale-archive su -c ". /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && $PGBINNEW/initdb $CHECKSUM_FLAG --encoding=$SERVER_ENCODING --locale-provider=icu --icu-locale=en_US.UTF-8 -L $PGSHARENEW -D $PGDATANEW/ --username=supabase_admin" -s "$SHELL" postgres + else + LC_ALL=en_US.UTF-8 LC_CTYPE=$SERVER_LC_CTYPE LC_COLLATE=$SERVER_LC_COLLATE LANGUAGE=en_US.UTF-8 LANG=en_US.UTF-8 LOCALE_ARCHIVE=/usr/lib/locale/locale-archive su -c ". /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && $PGBINNEW/initdb $CHECKSUM_FLAG --encoding=$SERVER_ENCODING --lc-collate=$SERVER_LC_COLLATE --lc-ctype=$SERVER_LC_CTYPE -L $PGSHARENEW -D $PGDATANEW/ --username=supabase_admin" -s "$SHELL" postgres + fi + else + su -c "$PGBINNEW/initdb $CHECKSUM_FLAG -L $PGSHARENEW -D $PGDATANEW/ --username=supabase_admin" -s "$SHELL" postgres + + fi + + # This line avoids the need to supply the supabase_admin password on the old + # instance, since pg_upgrade connects to the db as supabase_admin using unix + # sockets, which is gated behind scram-sha-256 per pg_hba.conf.j2. The new + # instance is unaffected. + if ! grep -q "local all supabase_admin trust" /etc/postgresql/pg_hba.conf; then + echo "local all supabase_admin trust +$(cat /etc/postgresql/pg_hba.conf)" >/etc/postgresql/pg_hba.conf + run_sql -c "select pg_reload_conf();" + fi + + TMP_CONFIG="/tmp/pg_upgrade/postgresql.conf" + cp "$POSTGRES_CONFIG_PATH" "$TMP_CONFIG" + + # Check if max_slot_wal_keep_size exists in the config + # Add the setting if not found + echo "max_slot_wal_keep_size = -1" >>"$TMP_CONFIG" + + # Remove db_user_namespace if upgrading from PG15 or lower to PG16+ + if [[ ${OLD_PGVERSION%%.*} -le 15 && ${PGVERSION%%.*} -ge 16 ]]; then + sed -i '/^db_user_namespace/d' "$TMP_CONFIG" + fi + + chown postgres:postgres "$TMP_CONFIG" + + UPGRADE_COMMAND=$( + cat < /etc/postgresql/pg_hba.conf --new-options="-c config_file=$TMP_CONFIG" \ --new-options="-c shared_preload_libraries='${SHARED_PRELOAD_LIBRARIES}'" EOF - ) - - if [ "$IS_NIX_BASED_SYSTEM" = "true" ]; then - UPGRADE_COMMAND=". /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && $UPGRADE_COMMAND" - fi - - if [[ "${PGVERSION%%.*}" -ge 16 ]]; then - GRN_PLUGINS_DIR=/var/lib/postgresql/.nix-profile/lib/groonga/plugins LC_ALL=en_US.UTF-8 LANGUAGE=en_US.UTF-8 LANG=en_US.UTF-8 LOCALE_ARCHIVE=/usr/lib/locale/locale-archive su -pc "$UPGRADE_COMMAND --check" -s "$SHELL" postgres - else - GRN_PLUGINS_DIR=/var/lib/postgresql/.nix-profile/lib/groonga/plugins LC_ALL=en_US.UTF-8 LC_CTYPE=$SERVER_LC_CTYPE LC_COLLATE=$SERVER_LC_COLLATE LANGUAGE=en_US.UTF-8 LANG=en_US.UTF-8 LOCALE_ARCHIVE=/usr/lib/locale/locale-archive su -pc "$UPGRADE_COMMAND --check" -s "$SHELL" postgres - fi - - echo "10. Stopping postgres; running pg_upgrade" - # Extra work to ensure postgres is actually stopped - # Mostly needed for PG12 projects with odd systemd unit behavior - if [ -z "$IS_CI" ]; then - retry 5 systemctl restart postgresql - systemctl disable postgresql - retry 5 systemctl stop postgresql - - sleep 3 - systemctl stop postgresql - - else - CI_stop_postgres - fi - - # Start the old PostgreSQL instance with version-specific options - if [[ "${PGVERSION%%.*}" -ge 16 ]]; then - GRN_PLUGINS_DIR=/var/lib/postgresql/.nix-profile/lib/groonga/plugins LC_ALL=en_US.UTF-8 LANGUAGE=en_US.UTF-8 LANG=en_US.UTF-8 LOCALE_ARCHIVE=/usr/lib/locale/locale-archive su -pc "$UPGRADE_COMMAND" -s "$SHELL" postgres - else - GRN_PLUGINS_DIR=/var/lib/postgresql/.nix-profile/lib/groonga/plugins LC_ALL=en_US.UTF-8 LC_CTYPE=$SERVER_LC_CTYPE LC_COLLATE=$SERVER_LC_COLLATE LANGUAGE=en_US.UTF-8 LANG=en_US.UTF-8 LOCALE_ARCHIVE=/usr/lib/locale/locale-archive su -pc "$UPGRADE_COMMAND" -s "$SHELL" postgres - fi - - # copying custom configurations - echo "11. Copying custom configurations" - mkdir -p "$MOUNT_POINT/conf" - cp -R /etc/postgresql-custom/* "$MOUNT_POINT/conf/" - # removing supautils config as to allow the latest one provided by the latest image to be used - rm -f "$MOUNT_POINT/conf/supautils.conf" || true - rm -rf "$MOUNT_POINT/conf/extension-custom-scripts" || true - - # removing wal-g config as to allow it to be explicitly enabled on the new instance - rm -f "$MOUNT_POINT/conf/wal-g.conf" - - # copy sql files generated by pg_upgrade - echo "12. Copying sql files generated by pg_upgrade" - mkdir -p "$MOUNT_POINT/sql" - cp /tmp/pg_upgrade/*.sql "$MOUNT_POINT/sql/" || true - chown -R postgres:postgres "$MOUNT_POINT/sql/" - - echo "13. Cleaning up" - cleanup "complete" + ) + + if [ "$IS_NIX_BASED_SYSTEM" = "true" ]; then + UPGRADE_COMMAND=". /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && $UPGRADE_COMMAND" + fi + + if [[ ${PGVERSION%%.*} -ge 16 ]]; then + GRN_PLUGINS_DIR=/var/lib/postgresql/.nix-profile/lib/groonga/plugins LC_ALL=en_US.UTF-8 LANGUAGE=en_US.UTF-8 LANG=en_US.UTF-8 LOCALE_ARCHIVE=/usr/lib/locale/locale-archive su -pc "$UPGRADE_COMMAND --check" -s "$SHELL" postgres + else + GRN_PLUGINS_DIR=/var/lib/postgresql/.nix-profile/lib/groonga/plugins LC_ALL=en_US.UTF-8 LC_CTYPE=$SERVER_LC_CTYPE LC_COLLATE=$SERVER_LC_COLLATE LANGUAGE=en_US.UTF-8 LANG=en_US.UTF-8 LOCALE_ARCHIVE=/usr/lib/locale/locale-archive su -pc "$UPGRADE_COMMAND --check" -s "$SHELL" postgres + fi + + echo "10. Stopping postgres; running pg_upgrade" + # Extra work to ensure postgres is actually stopped + # Mostly needed for PG12 projects with odd systemd unit behavior + if [ -z "$IS_CI" ]; then + retry 5 systemctl restart postgresql + systemctl disable postgresql + retry 5 systemctl stop postgresql + + sleep 3 + systemctl stop postgresql + + else + CI_stop_postgres + fi + + # Start the old PostgreSQL instance with version-specific options + if [[ ${PGVERSION%%.*} -ge 16 ]]; then + GRN_PLUGINS_DIR=/var/lib/postgresql/.nix-profile/lib/groonga/plugins LC_ALL=en_US.UTF-8 LANGUAGE=en_US.UTF-8 LANG=en_US.UTF-8 LOCALE_ARCHIVE=/usr/lib/locale/locale-archive su -pc "$UPGRADE_COMMAND" -s "$SHELL" postgres + else + GRN_PLUGINS_DIR=/var/lib/postgresql/.nix-profile/lib/groonga/plugins LC_ALL=en_US.UTF-8 LC_CTYPE=$SERVER_LC_CTYPE LC_COLLATE=$SERVER_LC_COLLATE LANGUAGE=en_US.UTF-8 LANG=en_US.UTF-8 LOCALE_ARCHIVE=/usr/lib/locale/locale-archive su -pc "$UPGRADE_COMMAND" -s "$SHELL" postgres + fi + + # copying custom configurations + echo "11. Copying custom configurations" + mkdir -p "$MOUNT_POINT/conf" + cp -R /etc/postgresql-custom/* "$MOUNT_POINT/conf/" + # removing supautils config as to allow the latest one provided by the latest image to be used + rm -f "$MOUNT_POINT/conf/supautils.conf" || true + rm -rf "$MOUNT_POINT/conf/extension-custom-scripts" || true + + # removing wal-g config as to allow it to be explicitly enabled on the new instance + rm -f "$MOUNT_POINT/conf/wal-g.conf" + + # copy sql files generated by pg_upgrade + echo "12. Copying sql files generated by pg_upgrade" + mkdir -p "$MOUNT_POINT/sql" + cp /tmp/pg_upgrade/*.sql "$MOUNT_POINT/sql/" || true + chown -R postgres:postgres "$MOUNT_POINT/sql/" + + echo "13. Cleaning up" + cleanup "complete" } trap cleanup ERR -echo "running" > /tmp/pg-upgrade-status +echo "running" >/tmp/pg-upgrade-status if [ -z "$IS_CI" ] && [ -z "$IS_LOCAL_UPGRADE" ]; then - initiate_upgrade >> "$LOG_FILE" 2>&1 & - echo "Upgrade initiate job completed" + initiate_upgrade >>"$LOG_FILE" 2>&1 & + echo "Upgrade initiate job completed" else - rm -f /tmp/pg-upgrade-status - initiate_upgrade + rm -f /tmp/pg-upgrade-status + initiate_upgrade fi diff --git a/ansible/files/admin_api_scripts/pg_upgrade_scripts/pgsodium_getkey.sh b/ansible/files/admin_api_scripts/pg_upgrade_scripts/pgsodium_getkey.sh index 5a5a90e444..45d169cff8 100755 --- a/ansible/files/admin_api_scripts/pg_upgrade_scripts/pgsodium_getkey.sh +++ b/ansible/files/admin_api_scripts/pg_upgrade_scripts/pgsodium_getkey.sh @@ -5,8 +5,8 @@ set -euo pipefail KEY_FILE=/etc/postgresql-custom/pgsodium_root.key # if key file doesn't exist (project previously didn't use pgsodium), generate a new key -if [[ ! -f "${KEY_FILE}" ]]; then - head -c 32 /dev/urandom | od -A n -t x1 | tr -d ' \n' > $KEY_FILE +if [[ ! -f ${KEY_FILE} ]]; then + head -c 32 /dev/urandom | od -A n -t x1 | tr -d ' \n' >$KEY_FILE fi cat $KEY_FILE diff --git a/ansible/files/admin_api_scripts/unmount-volume.sh b/ansible/files/admin_api_scripts/unmount-volume.sh index 6250b8c47c..f606ecb6f4 100644 --- a/ansible/files/admin_api_scripts/unmount-volume.sh +++ b/ansible/files/admin_api_scripts/unmount-volume.sh @@ -5,39 +5,39 @@ set -euo pipefail MOUNT_POINT=${1:-} DELETE_FLAG=${2:-} -if [[ -z "$MOUNT_POINT" ]]; then - echo "Usage: $0 [--delete-dir]" - echo "Unmount only: sudo ./unmount-volume.sh /data/150008" - echo "Unmount delete dir: sudo ./unmount-volume.sh /data/150008 --delete-dir" - exit 1 +if [[ -z $MOUNT_POINT ]]; then + echo "Usage: $0 [--delete-dir]" + echo "Unmount only: sudo ./unmount-volume.sh /data/150008" + echo "Unmount delete dir: sudo ./unmount-volume.sh /data/150008 --delete-dir" + exit 1 fi # Unmount a block device from a specified mount point -# Remove the corresponding entry from /etc/fstab for persistence across reboots +# Remove the corresponding entry from /etc/fstab for persistence across reboots FSTAB_FILE="/etc/fstab" BACKUP_FILE="/etc/fstab.bak" if mountpoint -q "$MOUNT_POINT"; then - echo "Unmounting $MOUNT_POINT" - umount "$MOUNT_POINT" + echo "Unmounting $MOUNT_POINT" + umount "$MOUNT_POINT" else - echo "$MOUNT_POINT is not currently mounted — skipping umount" + echo "$MOUNT_POINT is not currently mounted — skipping umount" fi UUID=$(findmnt -no UUID "$MOUNT_POINT" 2>/dev/null || true) -if [[ -n "$UUID" ]]; then - echo "Removing UUID=$UUID from $FSTAB_FILE" - cp "$FSTAB_FILE" "$BACKUP_FILE" - sed -i "/UUID=${UUID//\//\\/}/d" "$FSTAB_FILE" +if [[ -n $UUID ]]; then + echo "Removing UUID=$UUID from $FSTAB_FILE" + cp "$FSTAB_FILE" "$BACKUP_FILE" + sed -i "/UUID=${UUID//\//\\/}/d" "$FSTAB_FILE" else - echo "Could not find UUID for $MOUNT_POINT — skipping fstab cleanup" + echo "Could not find UUID for $MOUNT_POINT — skipping fstab cleanup" fi -if [[ "$DELETE_FLAG" == "--delete-dir" ]]; then - echo "Deleting mount point directory: $MOUNT_POINT" - rm -rf "$MOUNT_POINT" +if [[ $DELETE_FLAG == "--delete-dir" ]]; then + echo "Deleting mount point directory: $MOUNT_POINT" + rm -rf "$MOUNT_POINT" fi echo "Unmount and cleanup complete for $MOUNT_POINT" diff --git a/ansible/files/start-envoy.sh b/ansible/files/start-envoy.sh index edd6fe09e4..391a20ddc4 100644 --- a/ansible/files/start-envoy.sh +++ b/ansible/files/start-envoy.sh @@ -1,10 +1,10 @@ #!/usr/bin/env bash set -eou pipefail -if [[ $(cat /sys/module/ipv6/parameters/disable) = 1 ]]; then - sed -i -e "s/address: '::'/address: '0.0.0.0'/" -e 's/ipv4_compat: true/ipv4_compat: false/' /etc/envoy/lds.yaml +if [[ $(cat /sys/module/ipv6/parameters/disable) == 1 ]]; then + sed -i -e "s/address: '::'/address: '0.0.0.0'/" -e 's/ipv4_compat: true/ipv4_compat: false/' /etc/envoy/lds.yaml else - sed -i -e "s/address: '0.0.0.0'/address: '::'/" -e 's/ipv4_compat: false/ipv4_compat: true/' /etc/envoy/lds.yaml + sed -i -e "s/address: '0.0.0.0'/address: '::'/" -e 's/ipv4_compat: false/ipv4_compat: true/' /etc/envoy/lds.yaml fi # Workaround using `tee` to get `/dev/stdout` access logging to work, see: diff --git a/ansible/files/supabase_admin_agent_config/pgdata-chown b/ansible/files/supabase_admin_agent_config/pgdata-chown.sh similarity index 57% rename from ansible/files/supabase_admin_agent_config/pgdata-chown rename to ansible/files/supabase_admin_agent_config/pgdata-chown.sh index 05af5bd7d9..56e4e243d5 100644 --- a/ansible/files/supabase_admin_agent_config/pgdata-chown +++ b/ansible/files/supabase_admin_agent_config/pgdata-chown.sh @@ -10,25 +10,25 @@ set -euo pipefail if [[ $# -ne 2 ]]; then - echo "usage: pgdata-chown " >&2 - exit 1 + echo "usage: pgdata-chown " >&2 + exit 1 fi ACTION="$1" TARGET="$2" REAL=$(realpath "$TARGET") -if [[ "$REAL" != "/data/pgdata" && "$REAL" != /data/pgdata/* ]]; then - echo "error: '${TARGET}' resolves to '${REAL}', which is not under /data/pgdata" >&2 - exit 1 +if [[ $REAL != "/data/pgdata" && $REAL != /data/pgdata/* ]]; then + echo "error: '${TARGET}' resolves to '${REAL}', which is not under /data/pgdata" >&2 + exit 1 fi case "$ACTION" in - to-pgbackrest|to-postgres) - exec /usr/bin/chown -R "${ACTION:3}:postgres" "$REAL" - ;; - *) - echo "error: unknown action '${ACTION}'; expected to-pgbackrest or to-postgres" >&2 - exit 1 - ;; +to-pgbackrest | to-postgres) + exec /usr/bin/chown -R "${ACTION:3}:postgres" "$REAL" + ;; +*) + echo "error: unknown action '${ACTION}'; expected to-pgbackrest or to-postgres" >&2 + exit 1 + ;; esac diff --git a/ansible/files/supabase_admin_agent_config/pgdata-signal b/ansible/files/supabase_admin_agent_config/pgdata-signal.sh similarity index 56% rename from ansible/files/supabase_admin_agent_config/pgdata-signal rename to ansible/files/supabase_admin_agent_config/pgdata-signal.sh index 2479dd6dc1..01839f4f25 100644 --- a/ansible/files/supabase_admin_agent_config/pgdata-signal +++ b/ansible/files/supabase_admin_agent_config/pgdata-signal.sh @@ -13,32 +13,32 @@ set -euo pipefail # prevent PostgreSQL from starting after a restore. Handled as a single-arg # command to keep the sudoers entry scoped to this script rather than allowing # a broad "rm" entry. -if [[ $# -eq 1 && "$1" == "remove-pid" ]]; then - exec /usr/bin/rm -f "/data/pgdata/postmaster.pid" +if [[ $# -eq 1 && $1 == "remove-pid" ]]; then + exec /usr/bin/rm -f "/data/pgdata/postmaster.pid" fi if [[ $# -ne 2 ]]; then - echo "usage: pgdata-signal " >&2 - echo " pgdata-signal remove-pid" >&2 - exit 1 + echo "usage: pgdata-signal " >&2 + echo " pgdata-signal remove-pid" >&2 + exit 1 fi ACTION="$1" SIGNAL_TYPE="$2" case "$SIGNAL_TYPE" in - recovery|standby) FILE="/data/pgdata/${SIGNAL_TYPE}.signal" ;; - *) - echo "error: unknown signal type '${SIGNAL_TYPE}'; expected recovery or standby" >&2 - exit 1 - ;; +recovery | standby) FILE="/data/pgdata/${SIGNAL_TYPE}.signal" ;; +*) + echo "error: unknown signal type '${SIGNAL_TYPE}'; expected recovery or standby" >&2 + exit 1 + ;; esac case "$ACTION" in - create) exec /usr/bin/touch "${FILE}" ;; - remove) exec /usr/bin/rm -f "${FILE}" ;; - *) - echo "error: unknown action '${ACTION}'; expected create or remove" >&2 - exit 1 - ;; +create) exec /usr/bin/touch "${FILE}" ;; +remove) exec /usr/bin/rm -f "${FILE}" ;; +*) + echo "error: unknown action '${ACTION}'; expected create or remove" >&2 + exit 1 + ;; esac diff --git a/ansible/files/supascan_ami.sh b/ansible/files/supascan_ami.sh index 4696191889..446d81771b 100644 --- a/ansible/files/supascan_ami.sh +++ b/ansible/files/supascan_ami.sh @@ -8,7 +8,7 @@ set -euo pipefail -BASELINES_DIR="${1:-/tmp/ansible-playbook/audit-specs/baselines/ami-build}" +BASELINES_DIR="${1:-/tmp/audit-specs/baselines/ami-build}" echo "============================================================" echo "Baseline Validation" @@ -19,8 +19,8 @@ echo "" # Check baselines directory exists if [[ ! -d $BASELINES_DIR ]]; then - echo "ERROR: Baselines directory not found: $BASELINES_DIR" - exit 1 + echo "ERROR: Baselines directory not found: $BASELINES_DIR" + exit 1 fi # Add ubuntu user's nix profile to PATH @@ -28,9 +28,9 @@ export PATH="/home/ubuntu/.nix-profile/bin:$PATH" # Verify supascan is available if ! command -v supascan &>/dev/null; then - echo "ERROR: supascan not found in PATH" - echo "PATH: $PATH" - exit 1 + echo "ERROR: supascan not found in PATH" + echo "PATH: $PATH" + exit 1 fi # Run supascan validate (it calls sudo goss internally for privileged checks) diff --git a/ansible/files/systemd-networkd/systemd-networkd-check-and-fix.sh b/ansible/files/systemd-networkd/systemd-networkd-check-and-fix.sh index af00b412b3..10e4aab832 100644 --- a/ansible/files/systemd-networkd/systemd-networkd-check-and-fix.sh +++ b/ansible/files/systemd-networkd/systemd-networkd-check-and-fix.sh @@ -6,15 +6,15 @@ journalctl --no-pager --unit systemd-networkd --since "1 minutes ago" --grep "Co NDISC_ERROR=$? if systemctl is-active --quiet systemd-networkd.service && [ "${NDISC_ERROR}" == 0 ]; then - echo "$(date) systemd-network running but NDisc routes are broken. Restarting systemd.networkd.service" - /usr/bin/systemctl restart systemd-networkd.service - exit # no need to check further + echo "$(date) systemd-network running but NDisc routes are broken. Restarting systemd.networkd.service" + /usr/bin/systemctl restart systemd-networkd.service + exit # no need to check further fi # check for routes ROUTES=$(ip -6 route list) -if ! echo "${ROUTES}" | grep default >/dev/null || ! echo "${ROUTES}" | grep "::1 dev lo">/dev/null; then - echo "IPv6 routing table messed up. Restarting systemd.networkd.service" - /usr/bin/systemctl restart systemd-networkd.service +if ! echo "${ROUTES}" | grep default >/dev/null || ! echo "${ROUTES}" | grep "::1 dev lo" >/dev/null; then + echo "IPv6 routing table messed up. Restarting systemd.networkd.service" + /usr/bin/systemctl restart systemd-networkd.service fi diff --git a/ansible/files/walg_helper_scripts/wal_change_ownership.sh b/ansible/files/walg_helper_scripts/wal_change_ownership.sh index 3f0112d2fa..01541f1605 100644 --- a/ansible/files/walg_helper_scripts/wal_change_ownership.sh +++ b/ansible/files/walg_helper_scripts/wal_change_ownership.sh @@ -4,7 +4,7 @@ set -euo pipefail filename=$1 -if [[ -z "$filename" ]]; then +if [[ -z $filename ]]; then echo "Nothing supplied. Exiting." exit 1 fi @@ -15,18 +15,18 @@ num_paths=$(readlink -f "$full_path" | wc -l) # Checks if supplied filename string contains multiple paths # For example, "correct/path /var/lib/injected/path /var/lib/etc" -if [[ "$num_paths" -gt 1 ]]; then +if [[ $num_paths -gt 1 ]]; then echo "Multiple paths supplied. Exiting." exit 1 fi base_dir=$(readlink -f "$full_path" | cut -d'/' -f2) -# Checks if directory/ file to be manipulated +# Checks if directory/ file to be manipulated # is indeed within the /tmp directory -# For example, "/tmp/../var/lib/postgresql/..." +# For example, "/tmp/../var/lib/postgresql/..." # will return "var" as the value for $base_dir -if [[ "$base_dir" != "tmp" ]]; then +if [[ $base_dir != "tmp" ]]; then echo "Attempt to manipulate a file not in /tmp. Exiting." exit 1 fi diff --git a/ansible/files/walg_helper_scripts/wal_fetch.sh b/ansible/files/walg_helper_scripts/wal_fetch.sh index 33448ac95c..0e3109f364 100644 --- a/ansible/files/walg_helper_scripts/wal_fetch.sh +++ b/ansible/files/walg_helper_scripts/wal_fetch.sh @@ -3,7 +3,7 @@ set -euo pipefail # Fetch the WAL file and temporarily store them in /tmp -sudo -u wal-g wal-g wal-fetch "$1" /tmp/wal_fetch_dir/"$1" --config /etc/wal-g/config.json +sudo -u wal-g wal-g wal-fetch "$1" /tmp/wal_fetch_dir/"$1" --config /etc/wal-g/config.json # Ensure WAL file is owned by the postgres Linux user sudo -u root /root/wal_change_ownership.sh "$1" diff --git a/ansible/playbook.yml b/ansible/playbook.yml index 73db87d7af..8d12b418ed 100644 --- a/ansible/playbook.yml +++ b/ansible/playbook.yml @@ -235,7 +235,7 @@ - name: Run supascan baseline validation become: yes shell: | - /bin/bash /tmp/ansible-playbook/ansible/files/supascan_ami.sh /tmp/ansible-playbook/audit-specs/baselines/ami-build + /bin/bash /tmp/ansible-playbook/ansible/files/supascan_ami.sh /tmp/audit-specs/baselines/ami-build when: stage2_nix and qemu_mode is not defined and ansible_architecture != "x86_64" - name: Remove supascan after validation diff --git a/ansible/tasks/internal/supabase-admin-agent.yml b/ansible/tasks/internal/supabase-admin-agent.yml index 3f4d802db1..69e7861291 100644 --- a/ansible/tasks/internal/supabase-admin-agent.yml +++ b/ansible/tasks/internal/supabase-admin-agent.yml @@ -41,7 +41,7 @@ - name: supabase-admin-agent - pgdata-chown script copy: - src: files/supabase_admin_agent_config/pgdata-chown + src: files/supabase_admin_agent_config/pgdata-chown.sh dest: /usr/local/lib/supabase-admin-agent/pgdata-chown owner: root group: root @@ -50,7 +50,7 @@ - name: supabase-admin-agent - pgdata-signal script copy: - src: files/supabase_admin_agent_config/pgdata-signal + src: files/supabase_admin_agent_config/pgdata-signal.sh dest: /usr/local/lib/supabase-admin-agent/pgdata-signal owner: root group: root diff --git a/ansible/vars.yml b/ansible/vars.yml index aca4f67ac8..78b61ef919 100644 --- a/ansible/vars.yml +++ b/ansible/vars.yml @@ -10,9 +10,9 @@ postgres_major: # Full version strings for each major version postgres_release: - postgresorioledb-17: "17.6.0.089-orioledb" - postgres17: "17.6.1.132" - postgres15: "15.14.1.132" + postgresorioledb-17: "17.6.0.089-orioledb-push-spuxztvtwozk-1" + postgres17: "17.6.1.132-push-spuxztvtwozk-1" + postgres15: "15.14.1.132-push-spuxztvtwozk-1" # Non Postgres Extensions pgbouncer_release: 1.25.1 diff --git a/ci/extensions-diff.sh b/ci/extensions-diff.sh index 0965a08d54..de3f6cd9bb 100755 --- a/ci/extensions-diff.sh +++ b/ci/extensions-diff.sh @@ -350,13 +350,13 @@ analyze_variant_extension_deps() { echo "
" echo "Raw Dependency Tree" echo "" - echo "\`\`\`" + echo '```' echo "Old ($old_so):" echo "$old_deps" echo "" echo "New ($new_so):" echo "$new_deps" - echo "\`\`\`" + echo '```' echo "" echo "
" echo "" @@ -406,7 +406,7 @@ SUMMARY_CONTENT=$(generate_summary) # Insert summary after the header but before PostgreSQL version sections # We need to insert it after the header (line with "Analysis Date") and before first "##" heading -if [[ "$OSTYPE" == "darwin"* ]]; then +if [[ $OSTYPE == "darwin"* ]]; then # macOS - create temp file with proper structure { # Read header (including bullet point lines) diff --git a/ci/postgresql-diff.sh b/ci/postgresql-diff.sh index 08a3331f3b..3f807977fe 100755 --- a/ci/postgresql-diff.sh +++ b/ci/postgresql-diff.sh @@ -341,7 +341,7 @@ analyze_variant_deps() { echo "
" echo "Raw Dependency Closure" echo "" - echo "\`\`\`" + echo '```' echo "Old Dependencies (closure: ${old_closure_mb:-?} MB):" while read -r path; do dep_size=$(nix path-info -S "$path" --json 2>/dev/null | jq -r '.[].narSize' 2>/dev/null || echo "") @@ -363,7 +363,7 @@ analyze_variant_deps() { echo " $path" fi done <"/tmp/new-$variant-deps-$$.txt" - echo "\`\`\`" + echo '```' echo "" echo "
" echo "" diff --git a/development-arm.vars.pkr.hcl b/development-arm.vars.pkr.hcl index 3a07e0b53b..e729bc3035 100644 --- a/development-arm.vars.pkr.hcl +++ b/development-arm.vars.pkr.hcl @@ -1,7 +1,6 @@ -arch = "arm64" -ami_regions = ["ap-southeast-1"] -environment = "dev" +arch = "arm64" +ami-regions = ["ap-southeast-1"] +environment = "dev" instance-type = "c6g.4xlarge" -region= "ap-southeast-1" -ubuntu-2004 = "ami-0b49a4a6e8e22fa16" - +region = "ap-southeast-1" +ubuntu-2004 = "ami-0b49a4a6e8e22fa16" diff --git a/development-x86.vars.pkr.hcl b/development-x86.vars.pkr.hcl index 9167010cd5..7e4ca311d1 100644 --- a/development-x86.vars.pkr.hcl +++ b/development-x86.vars.pkr.hcl @@ -1,5 +1,5 @@ -arch = "amd64" -ami_regions = ["ap-southeast-1"] -environment = "dev" +arch = "amd64" +ami-regions = ["ap-southeast-1"] +environment = "dev" instance-type = "c6i.4xlarge" -region = "ap-southeast-1" +region = "ap-southeast-1" diff --git a/docker/nix/build_nix.sh b/docker/nix/build_nix.sh index 118fdf61d9..018075d78f 100755 --- a/docker/nix/build_nix.sh +++ b/docker/nix/build_nix.sh @@ -3,7 +3,7 @@ set -eou pipefail nix --version if [ -d "/workspace" ]; then - cd /workspace + cd /workspace fi nix run "github:Mic92/nix-fast-build?rev=b1dae483ab7d4139a6297e02b6de9e5d30e43d48" -- --skip-cached --no-nom --flake ".#checks" diff --git a/docker/pgctld/pgctld-wrapper b/docker/pgctld/pgctld-wrapper.sh similarity index 92% rename from docker/pgctld/pgctld-wrapper rename to docker/pgctld/pgctld-wrapper.sh index 9683d33f00..b5537589c3 100644 --- a/docker/pgctld/pgctld-wrapper +++ b/docker/pgctld/pgctld-wrapper.sh @@ -28,5 +28,5 @@ mkdir -p /var/log/postgresql 2>/dev/null || true ln -sf /proc/1/fd/1 /var/log/postgresql/postgresql.json exec /nix/var/nix/profiles/default/bin/pgctld \ - --postgres-config-template "${POSTGRES_CONFIG_TEMPLATE_PATH:-/etc/pgctld-custom/postgresql.conf.tmpl}" \ - "$@" + --postgres-config-template "${POSTGRES_CONFIG_TEMPLATE_PATH:-/etc/pgctld-custom/postgresql.conf.tmpl}" \ + "$@" diff --git a/ebssurrogate/USAGE.md b/ebssurrogate/USAGE.md index 9a63a082cb..7f467e4f47 100644 --- a/ebssurrogate/USAGE.md +++ b/ebssurrogate/USAGE.md @@ -1,50 +1,32 @@ ## Ext4 amd64 AMI creation `packer build -var "aws_access_key=$AWS_ACCESS_KEY_ID" -var "aws_secret_key=$AWS_SECRET_ACCESS_KEY" -var "region=$AWS_REGION" \ --var "docker_passwd=$DOCKER_PASSWD" -var "docker_user=$DOCKER_USER" -var "docker_image=$DOCKER_IMAGE" -var "docker_image_tag=$DOCKER_IMAGE_TAG" \ amazon-amd64.pkr.hcl` ## Ext4 arm64 AMI creation `packer build -var "aws_access_key=$AWS_ACCESS_KEY_ID" -var "aws_secret_key=$AWS_SECRET_ACCESS_KEY" -var "region=$AWS_REGION" \ --var "docker_passwd=$DOCKER_PASSWD" -var "docker_user=$DOCKER_USER" -var "docker_image=$DOCKER_IMAGE" -var "docker_image_tag=$DOCKER_IMAGE_TAG" \ amazon-arm64.pkr.hcl` -## Docker Image - - DOCKER_IMAGE is used to store ccache data during build process. This can be any image, you can create your image using: - - ``` - docker pull ubuntu - docker tag ubuntu /ccache - docker push /ccache - ``` - - For ARM64 builds - - ``` - docker pull arm64v8/ubuntu - docker tag arm64v8/ubuntu:latest /ccache-arm64v8 - docker push /ccache-arm64v8 - ``` - - Now set DOCKER_IMAGE="/ccache" or DOCKER_IMAGE="/ccache-arm64v8" based on your AMI architecture. - - ## EBS-Surrogate File layout ``` $ tree ebssurrogate/ ebssurrogate/ -├── files -│   ├── 70-ec2-nvme-devices.rules -│   ├── cloud.cfg # cloud.cfg for cloud-init -│   ├── ebsnvme-id -│   ├── sources-arm64.cfg # apt/sources.list for arm64 -│   ├── sources.cfg # apt/sources.list for amd64 -│   ├── vector.timer # systemd-timer to delay vectore execution -│   └── zfs-growpart-root.cfg -└── scripts - ├── chroot-bootstrap.sh # Installs grub and other required packages for build. Configures target AMI settings - └── surrogate-bootstrap.sh # Formats disk and setups chroot environment. Runs Ansible tasks within chrooted environment. +├── files/ +│   ├── apparmor_profiles # apparmor config files +│   ├── 70-ec2-nvme-devices.rules # udev rules for ebs volumes +│   ├── cloud.cfg # cloud.cfg for cloud-init +│   ├── ebsnvme-id # gets ebs volume info +│   ├── sources-arm64.cfg # apt/sources.list for arm64 +│   ├── sources.cfg # apt/sources.list for amd64 +│   ├── vector.timer # systemd-timer to delay vectore execution +└── scripts/ + ├── 90-cleanup-qemu.sh # Runs qemu specific clean up tasks + ├── 90-cleanup.sh # Runs AWS specific clean up tasks + ├── chroot-bootstrap-nix.sh # Installs grub and other required packages for build. Configures target AMI settings + ├── nix-provision.sh # Installs nix and runs stage-2 Ansible playbook + ├── qemu-bootstrap-nix.sh # Installs nix, runs stage-2 Ansible playbook, runs qemu specific tasks + └── surrogate-bootstrap-nix.sh # Formats disk and setups chroot environment. Runs Ansible tasks within chrooted environment. + ``` diff --git a/ebssurrogate/scripts/90-cleanup-qemu.sh b/ebssurrogate/scripts/90-cleanup-qemu.sh new file mode 100644 index 0000000000..7d8259fe40 --- /dev/null +++ b/ebssurrogate/scripts/90-cleanup-qemu.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash + +# DigitalOcean Marketplace Image Validation Tool +# © 2021 DigitalOcean LLC. +# This code is licensed under Apache 2.0 license (see LICENSE.md for details) + +set -euxo pipefail + +# Ensure /tmp exists and has the proper permissions before +# checking for security updates +# https://github.com/digitalocean/marketplace-partners/issues/94 +if [[ ! -d /tmp ]]; then + mkdir /tmp +fi +chmod 1777 /tmp + +if [ -n "$(command -v yum)" ]; then + yum update -y + yum clean all +elif [ -n "$(command -v apt-get)" ]; then + # Cleanup more packages + apt-get -y remove --purge \ + automake \ + autoconf \ + autotools-dev \ + cmake-data \ + cpp-9 \ + cpp-10 \ + gcc-9 \ + gcc-10 \ + git \ + git-man \ + ansible \ + libicu-dev \ + libcgal-dev \ + libgcc-9-dev \ + libgcc-8-dev \ + ansible \ + snapd + + # add-apt-repository --yes --remove ppa:ansible/ansible + + source /etc/os-release + + apt-mark manual libevent-2.1-7t64 + + apt-get remove -y --purge ansible-core apport appstream bash-completion bcache-tools bind9-dnsutils bind9-host bind9-libs bolt btrfs-progs byobu command-not-found console-setup distro-info eject fonts-ubuntu-console friendly-recovery ftp fwupd gawk gdisk keyboard-configuration libvolume-key1 libssl-dev lvm2 lxd-agent-loader man-db mdadm modemmanager mtd-utils nano netcat-openbsd nfs-common ntfs-3g parted pastebinit screen strace thin-provisioning-tools tmux usb-modeswitch vim vim-runtime wget whiptail xfsprogs + + apt remove -y --purge libc6-dev linux-libc-dev libevent-dev libpcre3-dev libsystemd-dev packagekit multipath-tools unattended-upgrades plymouth gnupg open-vm-tools xauth lxd-installer publicsuffix libclang-cpp18 python3-twisted python-babel-localedata libicu74 python3-pygments fonts-dejavu* python3-botocore + + apt-get remove -y --purge linux-headers* + + # remove old kernels + # CURRENT_KERNEL="$(uname -r | sed 's/-generic//')" + # INSTALLED_KERNELS=$(dpkg -l | awk '{print $2}' | grep -Eo 'linux-(image|headers|modules|tools)-[0-9]+' | sed -E 's/linux-(image|modules|tools)-//' | sort -Vu) + # REMOVE_KERNELS=$(echo "$INSTALLED_KERNELS" | grep -v -e "$CURRENT_KERNEL") + # for VER in $REMOVE_KERNELS; do + # for PREFIX in linux-image linux-modules linux-tools; do + # for PKG in $(dpkg -l | awk '{print $2}' | grep "^$PREFIX-$VER"); do + # apt-get purge -y "$PKG" + # done + # done + # done + # update-grub + + apt-get -y autoremove + apt-get -y autoclean + + apt-get -y update + apt-get -y upgrade + +fi + +systemctl set-default multi-user.target +systemctl disable getty@tty1.service +systemctl mask getty@tty1.service +systemctl mask graphical.target + +rm -rf /tmp/* /var/tmp/* +history -c +cat /dev/null >/root/.bash_history +unset HISTFILE + +journalctl --rotate +journalctl --vacuum-time=1s +find /var/log -mtime -1 -type f -exec truncate -s 0 {} \; +rm -rf /var/log/*.gz /var/log/*.[0-9] /var/log/*-???????? +rm -rf /var/lib/cloud/instances/* +rm -f /root/.ssh/authorized_keys /etc/ssh/*key* +touch /etc/ssh/revoked_keys +chmod 600 /etc/ssh/revoked_keys + +cat /dev/null >/var/log/lastlog +cat /dev/null >/var/log/wtmp + +dd if=/dev/zero of=/zerofile & +PID=$! +while [ -d /proc/$PID ]; do + printf "." + sleep 5 +done +sync +rm /zerofile +sync + +fstrim / diff --git a/scripts/90-cleanup.sh b/ebssurrogate/scripts/90-cleanup.sh similarity index 63% rename from scripts/90-cleanup.sh rename to ebssurrogate/scripts/90-cleanup.sh index ecb63a8d67..8ac5cbc6da 100644 --- a/scripts/90-cleanup.sh +++ b/ebssurrogate/scripts/90-cleanup.sh @@ -1,53 +1,53 @@ -#!/bin/bash +#!/usr/bin/env bash # DigitalOcean Marketplace Image Validation Tool # © 2021 DigitalOcean LLC. # This code is licensed under Apache 2.0 license (see LICENSE.md for details) -set -o errexit +set -euxo pipefail # Ensure /tmp exists and has the proper permissions before # checking for security updates # https://github.com/digitalocean/marketplace-partners/issues/94 if [[ ! -d /tmp ]]; then - mkdir /tmp + mkdir /tmp fi chmod 1777 /tmp if [ -n "$(command -v yum)" ]; then - yum update -y - yum clean all + yum update -y + yum clean all elif [ -n "$(command -v apt-get)" ]; then - # Cleanup more packages - apt-get -y remove --purge \ - automake \ - autoconf \ - autotools-dev \ - cmake-data \ - cpp-9 \ - cpp-10 \ - gcc-9 \ - gcc-10 \ - git \ - git-man \ - ansible \ - libicu-dev \ - libcgal-dev \ - libgcc-9-dev \ - ansible + # Cleanup more packages + apt-get -y remove --purge \ + automake \ + autoconf \ + autotools-dev \ + cmake-data \ + cpp-9 \ + cpp-10 \ + gcc-9 \ + gcc-10 \ + git \ + git-man \ + ansible \ + libicu-dev \ + libcgal-dev \ + libgcc-9-dev \ + ansible - # add-apt-repository --yes --remove ppa:ansible/ansible + # add-apt-repository --yes --remove ppa:ansible/ansible - source /etc/os-release - - apt-get -y update - apt-get -y upgrade - apt-get -y autoremove - apt-get -y autoclean + source /etc/os-release + + apt-get -y update + apt-get -y upgrade + apt-get -y autoremove + apt-get -y autoclean fi rm -rf /tmp/* /var/tmp/* history -c -cat /dev/null > /root/.bash_history +cat /dev/null >/root/.bash_history unset HISTFILE find /var/log -mtime -1 -type f -exec truncate -s 0 {} \; rm -rf /var/log/*.gz /var/log/*.[0-9] /var/log/*-???????? @@ -67,11 +67,13 @@ The secure erase will complete successfully when you see:${NC} Beginning secure erase now\n" dd if=/dev/zero of=/zerofile & - PID=$! - while [ -d /proc/$PID ] - do - printf "." - sleep 5 - done -sync; rm /zerofile; sync -cat /dev/null > /var/log/lastlog; cat /dev/null > /var/log/wtmp +PID=$! +while [ -d /proc/$PID ]; do + printf "." + sleep 5 +done +sync +rm /zerofile +sync +cat /dev/null >/var/log/lastlog +cat /dev/null >/var/log/wtmp diff --git a/ebssurrogate/scripts/chroot-bootstrap-nix.sh b/ebssurrogate/scripts/chroot-bootstrap-nix.sh index 3a58d73ba7..1ac58adbae 100755 --- a/ebssurrogate/scripts/chroot-bootstrap-nix.sh +++ b/ebssurrogate/scripts/chroot-bootstrap-nix.sh @@ -4,9 +4,7 @@ # Configuration file. # -set -o errexit -set -o pipefail -set -o xtrace +set -euxo pipefail export DEBIAN_FRONTEND=noninteractive @@ -16,18 +14,13 @@ export APT_OPTIONS="-oAPT::Install-Recommends=false \ # Prevent services from starting during package installation in chroot # This avoids hangs from cloud-init, dbus, etc. trying to start services -cat > /usr/sbin/policy-rc.d <<'EOF' +cat >/usr/sbin/policy-rc.d <<'EOF' #!/bin/sh exit 101 EOF chmod +x /usr/sbin/policy-rc.d -if [ $(dpkg --print-architecture) = "amd64" ]; -then - ARCH="amd64"; -else - ARCH="arm64"; -fi +ARCH=$(dpkg --print-architecture) # Get current mirror from sources.list function get_current_mirror { @@ -196,8 +189,6 @@ function apt_install_with_fallback { return 1 } - - function update_install_packages { source /etc/os-release @@ -213,7 +204,7 @@ function update_install_packages { if [ "${ARCH}" = "amd64" ]; then echo 'grub-pc grub-pc/install_devices_empty select true' | debconf-set-selections echo 'grub-pc grub-pc/install_devices select' | debconf-set-selections - # Install various packages needed for a booting system (with mirror fallback) + # Install various packages needed for a booting system (with mirror fallback) if ! apt_install_with_fallback install -y linux-aws grub-pc e2fsprogs; then echo "FATAL: Failed to install boot packages" exit 1 @@ -277,11 +268,11 @@ function update_install_packages { } function setup_locale { -cat << EOF >> /etc/locale.gen + cat <>/etc/locale.gen en_US.UTF-8 UTF-8 EOF -cat << EOF > /etc/default/locale + cat </etc/default/locale LANG="C.UTF-8" LC_CTYPE="C.UTF-8" EOF @@ -289,11 +280,11 @@ EOF } function setup_postgesql_env { - # Create the directory if it doesn't exist - sudo mkdir -p /etc/environment.d - - # Define the contents of the PostgreSQL environment file - cat </dev/null + # Create the directory if it doesn't exist + sudo mkdir -p /etc/environment.d + + # Define the contents of the PostgreSQL environment file + cat </dev/null LOCALE_ARCHIVE=/usr/lib/locale/locale-archive LANG="en_US.UTF-8" LANGUAGE="en_US.UTF-8" @@ -304,15 +295,15 @@ EOF function install_packages_for_build { apt-get install -y --no-install-recommends linux-libc-dev \ - acl \ - magic-wormhole sysstat \ - build-essential libreadline-dev zlib1g-dev flex bison libxml2-dev libxslt-dev libssl-dev libsystemd-dev libpq-dev libxml2-utils uuid-dev xsltproc ssl-cert \ - gcc-10 g++-10 \ - libgeos-dev libproj-dev libgdal-dev libjson-c-dev libboost-all-dev libcgal-dev libmpfr-dev libgmp-dev cmake \ - libkrb5-dev \ - maven default-jre default-jdk \ - curl gpp apt-transport-https cmake libc++-dev libc++abi-dev libc++1 libglib2.0-dev libtinfo5 libc++abi1 ninja-build python \ - liblzo2-dev + acl \ + magic-wormhole sysstat \ + build-essential libreadline-dev zlib1g-dev flex bison libxml2-dev libxslt-dev libssl-dev libsystemd-dev libpq-dev libxml2-utils uuid-dev xsltproc ssl-cert \ + gcc-10 g++-10 \ + libgeos-dev libproj-dev libgdal-dev libjson-c-dev libboost-all-dev libcgal-dev libmpfr-dev libgmp-dev cmake \ + libkrb5-dev \ + maven default-jre default-jdk \ + curl gpp apt-transport-https cmake libc++-dev libc++abi-dev libc++1 libglib2.0-dev libtinfo5 libc++abi1 ninja-build python \ + liblzo2-dev source /etc/os-release @@ -332,7 +323,7 @@ function setup_apparmor { } function setup_grub_conf { -cat << EOF > /etc/default/grub + cat </etc/default/grub GRUB_DEFAULT=0 GRUB_TIMEOUT=0 GRUB_TIMEOUT_STYLE="hidden" @@ -363,10 +354,10 @@ function disable_fsck { # Don't request hostname during boot but set hostname function setup_hostname { # Set the static hostname - echo "ubuntu" > /etc/hostname + echo "ubuntu" >/etc/hostname chmod 644 /etc/hostname # Update netplan configuration to not send hostname - cat << EOF > /etc/netplan/01-hostname.yaml + cat </etc/netplan/01-hostname.yaml network: version: 2 ethernets: @@ -381,7 +372,7 @@ EOF # Set options for the default interface function setup_eth0_interface { -cat << EOF > /etc/netplan/eth0.yaml + cat </etc/netplan/eth0.yaml network: version: 2 ethernets: @@ -394,8 +385,8 @@ EOF function disable_sshd_passwd_auth { sed -i -E -e 's/^#?\s*PasswordAuthentication\s+(yes|no)\s*$/PasswordAuthentication no/g' \ - -e 's/^#?\s*ChallengeResponseAuthentication\s+(yes|no)\s*$/ChallengeResponseAuthentication no/g' \ - /etc/ssh/sshd_config + -e 's/^#?\s*ChallengeResponseAuthentication\s+(yes|no)\s*$/ChallengeResponseAuthentication no/g' \ + /etc/ssh/sshd_config } function create_admin_account { @@ -413,7 +404,7 @@ function setup_ccache { apt-get install ccache -y mkdir -p /tmp/ccache export PATH=/usr/lib/ccache:$PATH - echo "PATH=$PATH" >> /etc/environment + echo "PATH=$PATH" >>/etc/environment } # Clear apt caches diff --git a/ebssurrogate/scripts/nix-provision.sh b/ebssurrogate/scripts/nix-provision.sh new file mode 100644 index 0000000000..2a4453e6d2 --- /dev/null +++ b/ebssurrogate/scripts/nix-provision.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash + +set -euxo pipefail + +function install_packages { + # Setup Ansible on host VM + sudo apt-get update && sudo apt-get install -y software-properties-common + + # Install EC2-specific packages that were deferred from stage 1 + # These packages have post-install scripts that need EC2 metadata service access + # which only works on a real running EC2 instance (not in chroot) + sudo apt-get install -y ec2-hibinit-agent ec2-instance-connect hibagent + + # Manually add GPG key with explicit keyserver + sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 93C4A3FD7BB9C367 + + # Add repository and install + # TODO (darora): temporarily disabling while Launchpad is under ddos attack and very frequently timing out + # sudo add-apt-repository --yes ppa:ansible/ansible + # sudo apt-get update + sudo apt-get install -y ansible + + ansible-galaxy collection install community.general +} + +function install_nix() { + sudo su -c "sh <(curl -L https://releases.nixos.org/nix/nix-2.34.6/install) --yes --daemon --nix-extra-conf-file /dev/stdin < sda - - # Create /dev/xvd* device symlink - if [[ ! -z "$mapping" ]] && [[ -b "${blkdev}" ]] && [[ ! -L "${mapping}" ]]; then - ln -s "$blkdev" "$mapping" - - blkdev_mappings["$blkdev"]="$mapping" - fi + for blkdev in $( # /dev/nvme*n* + nvme list | awk '/^\/dev/ { print $1 }' + ); do + # Mapping info from disk headers + header=$(nvme id-ctrl --raw-binary "${blkdev}" | cut -c3073-3104 | tr -s ' ' | sed 's/ $//g' | sed 's!/dev/!!') + mapping="/dev/${header%%[0-9]}" # normalize sda1 => sda + + # Create /dev/xvd* device symlink + if [[ -n $mapping ]] && [[ -b ${blkdev} ]] && [[ ! -L ${mapping} ]]; then + ln -s "$blkdev" "$mapping" + + blkdev_mappings["$blkdev"]="$mapping" + fi done create_partition_table # NVMe EBS launch device partition mappings (symlinks): /dev/nvme*n*p* to /dev/xvd*[0-9]+ declare -A partdev_mappings - for blkdev in "${!blkdev_mappings[@]}"; do # /dev/nvme*n* - mapping="${blkdev_mappings[$blkdev]}" + for blkdev in "${!blkdev_mappings[@]}"; do # /dev/nvme*n* + mapping="${blkdev_mappings[$blkdev]}" - # Create /dev/xvd*[0-9]+ partition device symlink - for partdev in "${blkdev}"p*; do - partnum=${partdev##*p} - if [[ ! -L "${mapping}${partnum}" ]]; then - ln -s "${blkdev}p${partnum}" "${mapping}${partnum}" + # Create /dev/xvd*[0-9]+ partition device symlink + for partdev in "${blkdev}"p*; do + partnum=${partdev##*p} + if [[ ! -L "${mapping}${partnum}" ]]; then + ln -s "${blkdev}p${partnum}" "${mapping}${partnum}" - partdev_mappings["${blkdev}p${partnum}"]="${mapping}${partnum}" - fi - done + partdev_mappings["${blkdev}p${partnum}"]="${mapping}${partnum}" + fi + done done } - #Download and install latest e2fsprogs for fast_commit feature,if required. function format_and_mount_rootfs { mkfs.ext4 -m0.1 /dev/xvdf2 @@ -224,11 +218,6 @@ function create_swapfile { function format_build_partition { mkfs.ext4 -O ^has_journal /dev/xvdc } -function pull_docker { - apt-get install -y docker.io - docker run -itd --name ccachedata "${DOCKER_IMAGE}:${DOCKER_IMAGE_TAG}" sh - docker exec -itd ccachedata mkdir -p /build/ccache -} # Create fstab function create_fstab { @@ -248,17 +237,17 @@ function create_fstab { [ -n "${EFI_LINE}" ] && echo "${EFI_LINE}" echo "${DATA_LINE}" echo "${SWAP_LINE}" - } > "/mnt/etc/fstab" + } >"/mnt/etc/fstab" unset FMT } function setup_chroot_environment { UBUNTU_VERSION=$(lsb_release -cs) # 'noble' for Ubuntu 24.04 - # sometimes debootstrap will get stuck on a download for a long time - # the default read timeout in wget is 900s, which can cause a ~15min increase in build time - # this forces the process to fail-fast and retry - cat < ~/.wgetrc + # sometimes debootstrap will get stuck on a download for a long time + # the default read timeout in wget is 900s, which can cause a ~15min increase in build time + # this forces the process to fail-fast and retry + cat <~/.wgetrc read_timeout = 30 timeout = 35 tries = 5 @@ -285,7 +274,7 @@ EOF mount --rbind /proc /mnt/proc mount --rbind /sys /mnt/sys - # Create build mount point and mount + # Create build mount point and mount mkdir -p /mnt/tmp mount /dev/xvdc /mnt/tmp chmod 777 /mnt/tmp @@ -301,10 +290,10 @@ EOF cp /tmp/chroot-bootstrap-nix.sh /mnt/tmp/chroot-bootstrap-nix.sh chroot /mnt /tmp/chroot-bootstrap-nix.sh rm -f /mnt/tmp/chroot-bootstrap-nix.sh - echo "${POSTGRES_SUPABASE_VERSION}" > /mnt/root/supabase-release + echo "${POSTGRES_SUPABASE_VERSION}" >/mnt/root/supabase-release # Copy the AMI version into the /etc/supabase-release file - echo "${POSTGRES_SUPABASE_VERSION}" > /mnt/etc/supabase-release + echo "${POSTGRES_SUPABASE_VERSION}" >/mnt/etc/supabase-release chmod 644 /mnt/etc/supabase-release # Copy the nvme identification script into /sbin inside the chroot @@ -324,13 +313,9 @@ EOF sleep 2 } -function download_ccache { - docker cp ccachedata:/build/ccache/. /mnt/tmp/ccache -} - function execute_playbook { sudo mkdir -p /etc/ansible -tee /etc/ansible/ansible.cfg < /dev/null 2>&1 && pwd ) +db=$(cd -- "$(dirname -- "$0")" >/dev/null 2>&1 && pwd) if [ -z "${USE_DBMATE:-}" ]; then - psql -v ON_ERROR_STOP=1 --no-password --no-psqlrc -U supabase_admin <> $PGDATA/postgresql.conf - echo "unix_socket_directories='$PGHOST'" >> $PGDATA/postgresql.conf - echo "unix_socket_permissions=0700" >> $PGDATA/postgresql.conf + echo 'Initializing postgresql database...' + initdb $PGDATA --locale=C --username $PGUSER -A md5 --pwfile=<(echo $PGPASS) --auth=trust + echo "listen_addresses='*'" >>$PGDATA/postgresql.conf + echo "unix_socket_directories='$PGHOST'" >>$PGDATA/postgresql.conf + echo "unix_socket_permissions=0700" >>$PGDATA/postgresql.conf fi chmod o-rwx $PGDATA diff --git a/nix/packages/build-ami.nix b/nix/packages/build-ami.nix index c847f47a41..ec62b36d67 100644 --- a/nix/packages/build-ami.nix +++ b/nix/packages/build-ami.nix @@ -18,7 +18,6 @@ let (root + "/ebssurrogate") (root + "/ansible") (root + "/migrations") - (root + "/scripts") (root + "/amazon-amd64-nix.pkr.hcl") (root + "/amazon-arm64-nix.pkr.hcl") (root + "/development-arm.vars.pkr.hcl") diff --git a/nix/packages/cli-config/pgsodium_getkey.sh b/nix/packages/cli-config/pgsodium_getkey.sh index 9a074363bb..bc4da10fd4 100755 --- a/nix/packages/cli-config/pgsodium_getkey.sh +++ b/nix/packages/cli-config/pgsodium_getkey.sh @@ -8,7 +8,7 @@ KEY_DIR="$(dirname "$KEY_FILE")" # Create directory if it doesn't exist mkdir -p "$KEY_DIR" -if [[ ! -f "${KEY_FILE}" ]]; then - head -c 32 /dev/urandom | od -A n -t x1 | tr -d ' \n' > "${KEY_FILE}" +if [[ ! -f ${KEY_FILE} ]]; then + head -c 32 /dev/urandom | od -A n -t x1 | tr -d ' \n' >"${KEY_FILE}" fi cat "$KEY_FILE" diff --git a/nix/packages/cli-config/supabase-postgres-init.sh b/nix/packages/cli-config/supabase-postgres-init.sh index 1af0691df1..8f90f4c8a4 100755 --- a/nix/packages/cli-config/supabase-postgres-init.sh +++ b/nix/packages/cli-config/supabase-postgres-init.sh @@ -19,172 +19,173 @@ PGBIN="$BUNDLE_DIR/bin" # Logging functions postgres_log() { - local type="$1"; shift - printf '%s [%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$type" "$*" + local type="$1" + shift + printf '%s [%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$type" "$*" } postgres_note() { - postgres_log Note "$@" + postgres_log Note "$@" } postgres_error() { - postgres_log ERROR "$@" >&2 + postgres_log ERROR "$@" >&2 } # Check if PGDATA is initialized postgres_is_initialized() { - [ -s "$PGDATA/PG_VERSION" ] + [ -s "$PGDATA/PG_VERSION" ] } # Setup initial database postgres_setup_db() { - postgres_note "Initializing database in $PGDATA" + postgres_note "Initializing database in $PGDATA" - # Create PGDATA directory if it doesn't exist - mkdir -p "$PGDATA" + # Create PGDATA directory if it doesn't exist + mkdir -p "$PGDATA" - # Run initdb - "$PGBIN/initdb" \ - -D "$PGDATA" \ - -U "$POSTGRES_USER" \ - --encoding=UTF8 \ - --locale=C \ - --no-instructions + # Run initdb + "$PGBIN/initdb" \ + -D "$PGDATA" \ + -U "$POSTGRES_USER" \ + --encoding=UTF8 \ + --locale=C \ + --no-instructions - postgres_note "Database initialized" + postgres_note "Database initialized" } # Setup configuration files postgres_setup_config() { - postgres_note "Setting up configuration files" + postgres_note "Setting up configuration files" - # Copy config templates - cp "$BUNDLE_DIR/share/supabase-cli/config/postgresql.conf.template" "$PGDATA/postgresql.conf" - cp "$BUNDLE_DIR/share/supabase-cli/config/pg_hba.conf.template" "$PGDATA/pg_hba.conf" - cp "$BUNDLE_DIR/share/supabase-cli/config/pg_ident.conf.template" "$PGDATA/pg_ident.conf" + # Copy config templates + cp "$BUNDLE_DIR/share/supabase-cli/config/postgresql.conf.template" "$PGDATA/postgresql.conf" + cp "$BUNDLE_DIR/share/supabase-cli/config/pg_hba.conf.template" "$PGDATA/pg_hba.conf" + cp "$BUNDLE_DIR/share/supabase-cli/config/pg_ident.conf.template" "$PGDATA/pg_ident.conf" - # Set absolute path to getkey script in postgresql.conf - GETKEY_SCRIPT="$BUNDLE_DIR/share/supabase-cli/config/pgsodium_getkey.sh" + # Set absolute path to getkey script in postgresql.conf + GETKEY_SCRIPT="$BUNDLE_DIR/share/supabase-cli/config/pgsodium_getkey.sh" - # Ensure getkey script is executable - if [ -f "$GETKEY_SCRIPT" ]; then - chmod +x "$GETKEY_SCRIPT" - fi + # Ensure getkey script is executable + if [ -f "$GETKEY_SCRIPT" ]; then + chmod +x "$GETKEY_SCRIPT" + fi - cat >> "$PGDATA/postgresql.conf" << EOF + cat >>"$PGDATA/postgresql.conf" < "$KEY_FILE" +if [[ ! -f $KEY_FILE ]]; then + head -c 32 /dev/urandom | od -A n -t x1 | tr -d ' \n' >"$KEY_FILE" fi cat $KEY_FILE diff --git a/nix/tests/util/pgsodium_getkey_arb.sh b/nix/tests/util/pgsodium_getkey_arb.sh index 446dbba2f7..46614d4aff 100755 --- a/nix/tests/util/pgsodium_getkey_arb.sh +++ b/nix/tests/util/pgsodium_getkey_arb.sh @@ -1 +1 @@ -echo -n 8359dafbba5c05568799c1c24eb6c2fbff497654bc6aa5e9a791c666768875a1 \ No newline at end of file +echo -n 8359dafbba5c05568799c1c24eb6c2fbff497654bc6aa5e9a791c666768875a1 diff --git a/qemu-arm64-nix.pkr.hcl b/qemu-arm64-nix.pkr.hcl index 17cca3a6eb..3bfca2bec3 100644 --- a/qemu-arm64-nix.pkr.hcl +++ b/qemu-arm64-nix.pkr.hcl @@ -1,39 +1,30 @@ -variable "ansible_arguments" { - type = string - default = "--skip-tags install-postgrest,install-pgbouncer,install-supabase-internal" -} - variable "environment" { type = string default = "prod" } -variable "git_sha" { - type = string +variable "git-sha" { + type = string } -locals { - creator = "packer" +variable "git-head-version" { + type = string } -variable "postgres-version" { +variable "packer-execution-id" { type = string - default = "" } -variable "postgres-major-version" { +variable "postgres-version" { type = string - default = "" } -variable "git-head-version" { +variable "postgres-major-version" { type = string - default = "unknown" } -variable "packer-execution-id" { - type = string - default = "unknown" +locals { + creator = "packer" } packer { @@ -80,7 +71,7 @@ source "qemu" "cloudimg" { qemu_img_args { convert = ["-o", "compression_type=zstd"] } - qemu_binary = "qemu-system-aarch64" + qemu_binary = "qemu-system-aarch64" qemuargs = [ ["-machine", "virt,gic-version=3"], ["-cpu", "host"], @@ -105,36 +96,31 @@ build { name = "cloudimg.image" sources = ["source.qemu.cloudimg"] - # Copy ansible playbook - provisioner "shell" { - inline = ["mkdir /tmp/ansible-playbook"] - } - provisioner "file" { - source = "ansible" - destination = "/tmp/ansible-playbook" + source = "ansible" + destination = "/tmp/" } provisioner "file" { - source = "scripts" - destination = "/tmp/ansible-playbook" + source = "ebssurrogate/scripts/90-cleanup-qemu.sh" + destination = "/tmp/" } provisioner "file" { - source = "migrations" - destination = "/tmp" + source = "migrations" + destination = "/tmp/" } provisioner "shell" { environment_vars = [ "POSTGRES_MAJOR_VERSION=${var.postgres-major-version}", "POSTGRES_SUPABASE_VERSION=${var.postgres-version}", - "GIT_SHA=${var.git_sha}" + "GIT_SHA=${var.git-sha}" ] - use_env_var_file = true - script = "ebssurrogate/scripts/qemu-bootstrap-nix.sh" - execute_command = "sudo -S sh -c '. {{.EnvVarFile}} && cd /tmp/ansible-playbook && {{.Path}}'" + use_env_var_file = true + script = "ebssurrogate/scripts/qemu-bootstrap-nix.sh" + execute_command = "sudo -S sh -c '. {{.EnvVarFile}} && {{.Path}}'" start_retry_timeout = "5m" - skip_clean = true + skip_clean = true } } diff --git a/scripts/00-python_install.sh b/scripts/00-python_install.sh deleted file mode 100644 index 3a7bb75608..0000000000 --- a/scripts/00-python_install.sh +++ /dev/null @@ -1,3 +0,0 @@ -sudo apt-get update -sudo apt-get install python -y -sudo apt-get install python-pip -y \ No newline at end of file diff --git a/scripts/01-postgres_check.sh b/scripts/01-postgres_check.sh deleted file mode 100644 index d131528eed..0000000000 --- a/scripts/01-postgres_check.sh +++ /dev/null @@ -1,72 +0,0 @@ -#!/bin/bash -# -# Scripts in this directory are run during the build process. -# each script will be uploaded to /tmp on your build droplet, -# given execute permissions and run. The cleanup process will -# remove the scripts from your build system after they have run -# if you use the build_image task. -# -echo "Commencing Checks" - -function check_database_is_ready { - echo -e "\nChecking if database is ready and accepting connections:" - if [ "$(pg_isready)" = "/tmp:5432 - accepting connections" ]; then - echo "Database is ready" - else - echo "Error: Database is not ready. Exiting" - exit 1 - fi -} - -function check_postgres_owned_dir_exists { - DIR=$1 - USER="postgres" - - echo -e "\nChecking if $DIR exists and owned by postgres user:" - - if [ -d "$DIR" ]; then - echo "$DIR exists" - if [ $(stat -c '%U' $DIR) = "$USER" ]; then - echo "$DIR is owned by $USER" - else - echo "Error: $DIR is not owned by $USER" - exit 1 - fi - else - echo "Error: ${DIR} not found. Exiting." - exit 1 - fi -} - -function check_lse_enabled { - ARCH=$(uname -m) - if [ $ARCH = "aarch64" ]; then - echo -e "\nArchitecture is $ARCH. Checking for LSE:" - - LSE_COUNT=$(objdump -d /usr/lib/postgresql/bin/postgres | grep -i 'ldxr\|ldaxr\|stxr\|stlxr' | wc -l) - MOUTLINE_ATOMICS_COUNT=$(nm /usr/lib/postgresql/bin/postgres | grep __aarch64_have_lse_atomics | wc -l) - - # Checking for load and store exclusives - if [ $LSE_COUNT -gt 0 ]; then - echo "Postgres has LSE enabled" - else - echo "Error: Postgres failed to be compiled with LSE. Exiting" - exit 1 - fi - - # Checking if successfully compiled with -moutline-atomics - if [ $MOUTLINE_ATOMICS_COUNT -gt 0 ]; then - echo "Postgres has been compiled with -moutline-atomics" - else - echo "Error: Postgres failed to be compiled with -moutline-atomics. Exiting" - exit 1 - fi - else - echo "Architecture is $ARCH. Not checking for LSE." - fi -} - -check_database_is_ready -check_postgres_owned_dir_exists "/var/lib/postgresql" -check_postgres_owned_dir_exists "/etc/postgresql" -check_lse_enabled \ No newline at end of file diff --git a/scripts/02-credentials_cleanup.sh b/scripts/02-credentials_cleanup.sh deleted file mode 100644 index a7b966f037..0000000000 --- a/scripts/02-credentials_cleanup.sh +++ /dev/null @@ -1 +0,0 @@ -sudo rm /home/ubuntu/.ssh/authorized_keys diff --git a/scripts/11-lemp.sh b/scripts/11-lemp.sh deleted file mode 100644 index c340f5e9fd..0000000000 --- a/scripts/11-lemp.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -# DigitalOcean Marketplace Image Validation Tool -# © 2021 DigitalOcean LLC. -# This code is licensed under Apache 2.0 license (see LICENSE.md for details) - -rm -rvf /etc/nginx/sites-enabled/default - -ln -s /etc/nginx/sites-available/digitalocean \ - /etc/nginx/sites-enabled/digitalocean - -rm -rf /var/www/html/index*debian.html - -chown -R www-data: /var/www \ No newline at end of file diff --git a/scripts/12-ufw-nginx.sh b/scripts/12-ufw-nginx.sh deleted file mode 100644 index 7c47366cd9..0000000000 --- a/scripts/12-ufw-nginx.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh - -# DigitalOcean Marketplace Image Validation Tool -# © 2021 DigitalOcean LLC. -# This code is licensed under Apache 2.0 license (see LICENSE.md for details) - -ufw limit ssh -ufw allow 'Nginx Full' - -ufw --force enable \ No newline at end of file diff --git a/scripts/13-force-ssh-logout.sh b/scripts/13-force-ssh-logout.sh deleted file mode 100644 index 99e28c180a..0000000000 --- a/scripts/13-force-ssh-logout.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh - -# DigitalOcean Marketplace Image Validation Tool -# © 2021 DigitalOcean LLC. -# This code is licensed under Apache 2.0 license (see LICENSE.md for details) - -cat >> /etc/ssh/sshd_config < /root/.bash_history -unset HISTFILE - -journalctl --rotate -journalctl --vacuum-time=1s -find /var/log -mtime -1 -type f -exec truncate -s 0 {} \; -rm -rf /var/log/*.gz /var/log/*.[0-9] /var/log/*-???????? -rm -rf /var/lib/cloud/instances/* -rm -f /root/.ssh/authorized_keys /etc/ssh/*key* -touch /etc/ssh/revoked_keys -chmod 600 /etc/ssh/revoked_keys - -cat /dev/null > /var/log/lastlog -cat /dev/null > /var/log/wtmp - -dd if=/dev/zero of=/zerofile & - PID=$! - while [ -d /proc/$PID ] - do - printf "." - sleep 5 - done -sync; rm /zerofile; sync - -fstrim / diff --git a/scripts/91-log_cleanup.sh b/scripts/91-log_cleanup.sh deleted file mode 100644 index 24073afcb8..0000000000 --- a/scripts/91-log_cleanup.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash -#Erasing all logs -# -echo "Clearing all log files" -rm -rf /var/log/* - -# creating system stats directory -mkdir /var/log/sysstat - -# https://github.com/fail2ban/fail2ban/issues/1593 -touch /var/log/auth.log - -touch /var/log/pgbouncer.log -chown pgbouncer:postgres /var/log/pgbouncer.log - -mkdir /var/log/postgresql -chown postgres:postgres /var/log/postgresql - -mkdir /var/log/wal-g -cd /var/log/wal-g -touch backup-push.log backup-fetch.log wal-push.log wal-fetch.log pitr.log -chown -R postgres:postgres /var/log/wal-g -chmod -R 0300 /var/log/wal-g - diff --git a/scripts/99-img_check.sh b/scripts/99-img_check.sh deleted file mode 100755 index ac958a5fc3..0000000000 --- a/scripts/99-img_check.sh +++ /dev/null @@ -1,682 +0,0 @@ -#!/bin/bash - -# DigitalOcean Marketplace Image Validation Tool -# © 2021 DigitalOcean LLC. -# This code is licensed under Apache 2.0 license (see LICENSE.md for details) - -VERSION="v. 1.6" -RUNDATE=$( date ) - -# Script should be run with SUDO -if [ "$EUID" -ne 0 ] - then echo "[Error] - This script must be run with sudo or as the root user." - exit 1 -fi - -STATUS=0 -PASS=0 -WARN=0 -FAIL=0 - -# $1 == command to check for -# returns: 0 == true, 1 == false -cmdExists() { - if command -v "$1" > /dev/null 2>&1; then - return 0 - else - return 1 - fi -} - -function getDistro { - if [ -f /etc/os-release ]; then - # freedesktop.org and systemd - . /etc/os-release - OS=$NAME - VER=$VERSION_ID -elif type lsb_release >/dev/null 2>&1; then - # linuxbase.org - OS=$(lsb_release -si) - VER=$(lsb_release -sr) -elif [ -f /etc/lsb-release ]; then - # For some versions of Debian/Ubuntu without lsb_release command - . /etc/lsb-release - OS=$DISTRIB_ID - VER=$DISTRIB_RELEASE -elif [ -f /etc/debian_version ]; then - # Older Debian/Ubuntu/etc. - OS=Debian - VER=$(cat /etc/debian_version) -elif [ -f /etc/SuSe-release ]; then - # Older SuSE/etc. - : -elif [ -f /etc/redhat-release ]; then - # Older Red Hat, CentOS, etc. - VER=$( cat /etc/redhat-release | cut -d" " -f3 | cut -d "." -f1) - d=$( cat /etc/redhat-release | cut -d" " -f1 | cut -d "." -f1) - if [[ $d == "CentOS" ]]; then - OS="CentOS Linux" - fi -else - # Fall back to uname, e.g. "Linux ", also works for BSD, etc. - OS=$(uname -s) - VER=$(uname -r) -fi -} -function loadPasswords { -SHADOW=$(cat /etc/shadow) -} - -function checkAgent { - # Check for the presence of the do-agent in the filesystem - if [ -d /var/opt/digitalocean/do-agent ];then - echo -en "\e[41m[FAIL]\e[0m DigitalOcean Monitoring Agent detected.\n" - ((FAIL++)) - STATUS=2 - if [[ $OS == "CentOS Linux" ]]; then - echo "The agent can be removed with 'sudo yum remove do-agent' " - elif [[ $OS == "Ubuntu" ]]; then - echo "The agent can be removed with 'sudo apt-get purge do-agent' " - fi - else - echo -en "\e[32m[PASS]\e[0m DigitalOcean Monitoring agent was not found\n" - ((PASS++)) - fi -} - -function checkLogs { - cp_ignore="/var/log/cpanel-install.log" - echo -en "\nChecking for log files in /var/log\n\n" - # Check if there are log archives or log files that have not been recently cleared. - for f in /var/log/*-????????; do - [[ -e $f ]] || break - if [ $f != $cp_ignore ]; then - echo -en "\e[93m[WARN]\e[0m Log archive ${f} found\n" - ((WARN++)) - if [[ $STATUS != 2 ]]; then - STATUS=1 - fi - fi - done - for f in /var/log/*.[0-9];do - [[ -e $f ]] || break - echo -en "\e[93m[WARN]\e[0m Log archive ${f} found\n" - ((WARN++)) - if [[ $STATUS != 2 ]]; then - STATUS=1 - fi - done - for f in /var/log/*.log; do - [[ -e $f ]] || break - if [[ "${f}" = '/var/log/lfd.log' && "$( cat "${f}" | egrep -v '/var/log/messages has been reset| Watching /var/log/messages' | wc -c)" -gt 50 ]]; then - if [ $f != $cp_ignore ]; then - echo -en "\e[93m[WARN]\e[0m un-cleared log file, ${f} found\n" - ((WARN++)) - if [[ $STATUS != 2 ]]; then - STATUS=1 - fi - fi - elif [[ "${f}" != '/var/log/lfd.log' && "$( cat "${f}" | wc -c)" -gt 50 ]]; then - if [ $f != $cp_ignore ]; then - echo -en "\e[93m[WARN]\e[0m un-cleared log file, ${f} found\n" - ((WARN++)) - if [[ $STATUS != 2 ]]; then - STATUS=1 - fi - fi - fi - done -} -function checkTMP { - # Check the /tmp directory to ensure it is empty. Warn on any files found. - return 1 -} -function checkRoot { - user="root" - uhome="/root" - for usr in $SHADOW - do - IFS=':' read -r -a u <<< "$usr" - if [[ "${u[0]}" == "${user}" ]]; then - if [[ ${u[1]} == "!" ]] || [[ ${u[1]} == "!!" ]] || [[ ${u[1]} == "*" ]]; then - echo -en "\e[32m[PASS]\e[0m User ${user} has no password set.\n" - ((PASS++)) - else - echo -en "\e[41m[FAIL]\e[0m User ${user} has a password set on their account.\n" - ((FAIL++)) - STATUS=2 - fi - fi - done - if [ -d ${uhome}/ ]; then - if [ -d ${uhome}/.ssh/ ]; then - if ls ${uhome}/.ssh/*> /dev/null 2>&1; then - for key in ${uhome}/.ssh/* - do - if [ "${key}" == "${uhome}/.ssh/authorized_keys" ]; then - - if [ "$( cat "${key}" | wc -c)" -gt 50 ]; then - echo -en "\e[41m[FAIL]\e[0m User \e[1m${user}\e[0m has a populated authorized_keys file in \e[93m${key}\e[0m\n" - akey=$(cat ${key}) - echo "File Contents:" - echo $akey - echo "--------------" - ((FAIL++)) - STATUS=2 - fi - elif [ "${key}" == "${uhome}/.ssh/id_rsa" ]; then - if [ "$( cat "${key}" | wc -c)" -gt 0 ]; then - echo -en "\e[41m[FAIL]\e[0m User \e[1m${user}\e[0m has a private key file in \e[93m${key}\e[0m\n" - akey=$(cat ${key}) - echo "File Contents:" - echo $akey - echo "--------------" - ((FAIL++)) - STATUS=2 - else - echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has empty private key file in \e[93m${key}\e[0m\n" - ((WARN++)) - if [[ $STATUS != 2 ]]; then - STATUS=1 - fi - fi - elif [ "${key}" != "${uhome}/.ssh/known_hosts" ]; then - echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has a file in their .ssh directory at \e[93m${key}\e[0m\n" - ((WARN++)) - if [[ $STATUS != 2 ]]; then - STATUS=1 - fi - else - if [ "$( cat "${key}" | wc -c)" -gt 50 ]; then - echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has a populated known_hosts file in \e[93m${key}\e[0m\n" - ((WARN++)) - if [[ $STATUS != 2 ]]; then - STATUS=1 - fi - fi - fi - done - else - echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m has no SSH keys present\n" - fi - else - echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m does not have an .ssh directory\n" - fi - if [ -f /root/.bash_history ];then - - BH_S=$( cat /root/.bash_history | wc -c) - - if [[ $BH_S -lt 200 ]]; then - echo -en "\e[32m[PASS]\e[0m ${user}'s Bash History appears to have been cleared\n" - ((PASS++)) - else - echo -en "\e[41m[FAIL]\e[0m ${user}'s Bash History should be cleared to prevent sensitive information from leaking\n" - ((FAIL++)) - STATUS=2 - fi - - return 1; - else - echo -en "\e[32m[PASS]\e[0m The Root User's Bash History is not present\n" - ((PASS++)) - fi - else - echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m does not have a directory in /home\n" - fi - echo -en "\n\n" - return 1 -} - -function checkUsers { - # Check each user-created account - for user in $(awk -F: '$3 >= 1000 && $1 != "nobody" {print $1}' /etc/passwd;) - do - # Skip some other non-user system accounts - if [[ $user == "centos" ]]; then - : - elif [[ $user == "nfsnobody" ]]; then - : - else - echo -en "\nChecking user: ${user}...\n" - for usr in $SHADOW - do - IFS=':' read -r -a u <<< "$usr" - if [[ "${u[0]}" == "${user}" ]]; then - if [[ ${u[1]} == "!" ]] || [[ ${u[1]} == "!!" ]] || [[ ${u[1]} == "*" ]]; then - echo -en "\e[32m[PASS]\e[0m User ${user} has no password set.\n" - ((PASS++)) - else - echo -en "\e[41m[FAIL]\e[0m User ${user} has a password set on their account. Only system users are allowed on the image.\n" - ((FAIL++)) - STATUS=2 - fi - fi - done - #echo "User Found: ${user}" - uhome="/home/${user}" - if [ -d "${uhome}/" ]; then - if [ -d "${uhome}/.ssh/" ]; then - if ls "${uhome}/.ssh/*"> /dev/null 2>&1; then - for key in ${uhome}/.ssh/* - do - if [ "${key}" == "${uhome}/.ssh/authorized_keys" ]; then - if [ "$( cat "${key}" | wc -c)" -gt 50 ]; then - echo -en "\e[41m[FAIL]\e[0m User \e[1m${user}\e[0m has a populated authorized_keys file in \e[93m${key}\e[0m\n" - akey=$(cat ${key}) - echo "File Contents:" - echo $akey - echo "--------------" - ((FAIL++)) - STATUS=2 - fi - elif [ "${key}" == "${uhome}/.ssh/id_rsa" ]; then - if [ "$( cat "${key}" | wc -c)" -gt 0 ]; then - echo -en "\e[41m[FAIL]\e[0m User \e[1m${user}\e[0m has a private key file in \e[93m${key}\e[0m\n" - akey=$(cat ${key}) - echo "File Contents:" - echo $akey - echo "--------------" - ((FAIL++)) - STATUS=2 - else - echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has empty private key file in \e[93m${key}\e[0m\n" - ((WARN++)) - if [[ $STATUS != 2 ]]; then - STATUS=1 - fi - fi - elif [ "${key}" != "${uhome}/.ssh/known_hosts" ]; then - - echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has a file in their .ssh directory named \e[93m${key}\e[0m\n" - ((WARN++)) - if [[ $STATUS != 2 ]]; then - STATUS=1 - fi - - else - if [ "$( cat "${key}" | wc -c)" -gt 50 ]; then - echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has a known_hosts file in \e[93m${key}\e[0m\n" - ((WARN++)) - if [[ $STATUS != 2 ]]; then - STATUS=1 - fi - fi - fi - - - done - else - echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m has no SSH keys present\n" - fi - else - echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m does not have an .ssh directory\n" - fi - else - echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m does not have a directory in /home\n" - fi - - # Check for an uncleared .bash_history for this user - if [ -f "${uhome}/.bash_history" ]; then - BH_S=$( cat "${uhome}/.bash_history" | wc -c ) - - if [[ $BH_S -lt 200 ]]; then - echo -en "\e[32m[PASS]\e[0m ${user}'s Bash History appears to have been cleared\n" - ((PASS++)) - else - echo -en "\e[41m[FAIL]\e[0m ${user}'s Bash History should be cleared to prevent sensitive information from leaking\n" - ((FAIL++)) - STATUS=2 - - fi - echo -en "\n\n" - fi - fi - done -} -function checkFirewall { - - if [[ $OS == "Ubuntu" ]]; then - fw="ufw" - ufwa=$(ufw status |head -1| sed -e "s/^Status:\ //") - if [[ $ufwa == "active" ]]; then - FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" - ((PASS++)) - else - FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" - ((WARN++)) - fi - elif [[ $OS == "CentOS Linux" ]]; then - if [ -f /usr/lib/systemd/system/csf.service ]; then - fw="csf" - if [[ $(systemctl status $fw >/dev/null 2>&1) ]]; then - - FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" - ((PASS++)) - elif cmdExists "firewall-cmd"; then - if [[ $(systemctl is-active firewalld >/dev/null 2>&1 && echo 1 || echo 0) ]]; then - FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" - ((PASS++)) - else - FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" - ((WARN++)) - fi - else - FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" - ((WARN++)) - fi - else - fw="firewalld" - if [[ $(systemctl is-active firewalld >/dev/null 2>&1 && echo 1 || echo 0) ]]; then - FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" - ((PASS++)) - else - FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" - ((WARN++)) - fi - fi - elif [[ "$OS" =~ Debian.* ]]; then - # user could be using a number of different services for managing their firewall - # we will check some of the most common - if cmdExists 'ufw'; then - fw="ufw" - ufwa=$(ufw status |head -1| sed -e "s/^Status:\ //") - if [[ $ufwa == "active" ]]; then - FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" - ((PASS++)) - else - FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" - ((WARN++)) - fi - elif cmdExists "firewall-cmd"; then - fw="firewalld" - if [[ $(systemctl is-active --quiet $fw) ]]; then - FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" - ((PASS++)) - else - FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" - ((WARN++)) - fi - else - # user could be using vanilla iptables, check if kernel module is loaded - fw="iptables" - if [[ $(lsmod | grep -q '^ip_tables' 2>/dev/null) ]]; then - FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" - ((PASS++)) - else - FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" - ((WARN++)) - fi - fi - fi - -} -function checkUpdates { - if [[ $OS == "Ubuntu" ]] || [[ "$OS" =~ Debian.* ]]; then - # Ensure /tmp exists and has the proper permissions before - # checking for security updates - # https://github.com/digitalocean/marketplace-partners/issues/94 - if [[ ! -d /tmp ]]; then - mkdir /tmp - fi - chmod 1777 /tmp - - echo -en "\nUpdating apt package database to check for security updates, this may take a minute...\n\n" - apt-get -y update > /dev/null - - uc=$(apt-get --just-print upgrade | grep -i "security" | wc -l) - if [[ $uc -gt 0 ]]; then - update_count=$(( ${uc} / 2 )) - else - update_count=0 - fi - - if [[ $update_count -gt 0 ]]; then - echo -en "\e[41m[FAIL]\e[0m There are ${update_count} security updates available for this image that have not been installed.\n" - echo -en - echo -en "Here is a list of the security updates that are not installed:\n" - sleep 2 - apt-get --just-print upgrade | grep -i security | awk '{print $2}' | awk '!seen[$0]++' - echo -en - ((FAIL++)) - STATUS=2 - else - echo -en "\e[32m[PASS]\e[0m There are no pending security updates for this image.\n\n" - fi - elif [[ $OS == "CentOS Linux" ]]; then - echo -en "\nChecking for available security updates, this may take a minute...\n\n" - - update_count=$(yum check-update --security --quiet | wc -l) - if [[ $update_count -gt 0 ]]; then - echo -en "\e[41m[FAIL]\e[0m There are ${update_count} security updates available for this image that have not been installed.\n" - ((FAIL++)) - STATUS=2 - else - echo -en "\e[32m[PASS]\e[0m There are no pending security updates for this image.\n" - ((PASS++)) - fi - else - echo "Error encountered" - exit 1 - fi - - return 1; -} -function checkCloudInit { - - if hash cloud-init 2>/dev/null; then - CI="\e[32m[PASS]\e[0m Cloud-init is installed.\n" - ((PASS++)) - else - CI="\e[41m[FAIL]\e[0m No valid verison of cloud-init was found.\n" - ((FAIL++)) - STATUS=2 - fi - return 1 -} -function checkMongoDB { - # Check if MongoDB is installed - # If it is, verify the version is allowed (non-SSPL) - - if [[ $OS == "Ubuntu" ]] || [[ "$OS" =~ Debian.* ]]; then - - if [[ -f "/usr/bin/mongod" ]]; then - version=$(/usr/bin/mongod --version --quiet | grep "db version" | sed -e "s/^db\ version\ v//") - - if version_gt $version 4.0.0; then - if version_gt $version 4.0.3; then - echo -en "\e[41m[FAIL]\e[0m An SSPL version of MongoDB is present, ${version}" - ((FAIL++)) - STATUS=2 - else - echo -en "\e[32m[PASS]\e[0m The version of MongoDB installed, ${version} is not under the SSPL" - ((PASS++)) - fi - else - if version_gt $version 3.6.8; then - echo -en "\e[41m[FAIL]\e[0m An SSPL version of MongoDB is present, ${version}" - ((FAIL++)) - STATUS=2 - else - echo -en "\e[32m[PASS]\e[0m The version of MongoDB installed, ${version} is not under the SSPL" - ((PASS++)) - fi - fi - - - else - echo -en "\e[32m[PASS]\e[0m MongoDB is not installed" - ((PASS++)) - fi - - elif [[ $OS == "CentOS Linux" ]]; then - - if [[ -f "/usr/bin/mongod" ]]; then - version=$(/usr/bin/mongod --version --quiet | grep "db version" | sed -e "s/^db\ version\ v//") - - - if version_gt $version 4.0.0; then - if version_gt $version 4.0.3; then - echo -en "\e[41m[FAIL]\e[0m An SSPL version of MongoDB is present" - ((FAIL++)) - STATUS=2 - else - echo -en "\e[32m[PASS]\e[0m The version of MongoDB installed is not under the SSPL" - ((PASS++)) - fi - else - if version_gt $version 3.6.8; then - echo -en "\e[41m[FAIL]\e[0m An SSPL version of MongoDB is present" - ((FAIL++)) - STATUS=2 - else - echo -en "\e[32m[PASS]\e[0m The version of MongoDB installed is not under the SSPL" - ((PASS++)) - fi - fi - - - - else - echo -en "\e[32m[PASS]\e[0m MongoDB is not installed" - ((PASS++)) - fi - - else - echo "ERROR: Unable to identify distribution" - ((FAIL++)) - STATUS 2 - return 1 - fi - - -} - -function version_gt() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; } - - -clear -echo "DigitalOcean Marketplace Image Validation Tool ${VERSION}" -echo "Executed on: ${RUNDATE}" -echo "Checking local system for Marketplace compatibility..." - -getDistro - -echo -en "\n\e[1mDistribution:\e[0m ${OS}\n" -echo -en "\e[1mVersion:\e[0m ${VER}\n\n" - -ost=0 -osv=0 - -if [[ $OS == "Ubuntu" ]]; then - ost=1 - if [[ $VER == "24.04" ]]; then - osv=1 - elif [[ $VER == "18.04" ]]; then - osv=1 - elif [[ $VER == "16.04" ]]; then - osv=1 - else - osv=0 - fi - -elif [[ "$OS" =~ Debian.* ]]; then - ost=1 - case "$VER" in - 9) - osv=1 - ;; - 10) - osv=1 - ;; - *) - osv=2 - ;; - esac - -elif [[ $OS == "CentOS Linux" ]]; then - ost=1 - if [[ $VER == "8" ]]; then - osv=1 - elif [[ $VER == "7" ]]; then - osv=1 - elif [[ $VER == "6" ]]; then - osv=1 - else - osv=2 - fi -else - ost=0 -fi - -if [[ $ost == 1 ]]; then - echo -en "\e[32m[PASS]\e[0m Supported Operating System Detected: ${OS}\n" - ((PASS++)) -else - echo -en "\e[41m[FAIL]\e[0m ${OS} is not a supported Operating System\n" - ((FAIL++)) - STATUS=2 -fi - -if [[ $osv == 1 ]]; then - echo -en "\e[32m[PASS]\e[0m Supported Release Detected: ${VER}\n" - ((PASS++)) -elif [[ $ost == 1 ]]; then - echo -en "\e[41m[FAIL]\e[0m ${OS} ${VER} is not a supported Operating System Version\n" - ((FAIL++)) - STATUS=2 -else - echo "Exiting..." - exit 1 -fi - -checkCloudInit - -echo -en "${CI}" - -checkFirewall - -echo -en "${FW_VER}" - -checkUpdates - -loadPasswords - -checkLogs - -echo -en "\n\nChecking all user-created accounts...\n" -checkUsers - -echo -en "\n\nChecking the root account...\n" -checkRoot - -checkAgent - -checkMongoDB - - -# Summary -echo -en "\n\n---------------------------------------------------------------------------------------------------\n" - -if [[ $STATUS == 0 ]]; then - echo -en "Scan Complete.\n\e[32mAll Tests Passed!\e[0m\n" -elif [[ $STATUS == 1 ]]; then - echo -en "Scan Complete. \n\e[93mSome non-critical tests failed. Please review these items.\e[0m\e[0m\n" -else - echo -en "Scan Complete. \n\e[41mOne or more tests failed. Please review these items and re-test.\e[0m\n" -fi -echo "---------------------------------------------------------------------------------------------------" -echo -en "\e[1m${PASS} Tests PASSED\e[0m\n" -echo -en "\e[1m${WARN} WARNINGS\e[0m\n" -echo -en "\e[1m${FAIL} Tests FAILED\e[0m\n" -echo -en "---------------------------------------------------------------------------------------------------\n" - -if [[ $STATUS == 0 ]]; then - echo -en "We did not detect any issues with this image. Please be sure to manually ensure that all software installed on the base system is functional, secure and properly configured (or facilities for configuration on first-boot have been created).\n\n" - exit 0 -elif [[ $STATUS == 1 ]]; then - echo -en "Please review all [WARN] items above and ensure they are intended or resolved. If you do not have a specific requirement, we recommend resolving these items before image submission\n\n" - exit 0 -else - echo -en "Some critical tests failed. These items must be resolved and this scan re-run before you submit your image to the DigitalOcean Marketplace.\n\n" - exit 1 -fi \ No newline at end of file diff --git a/scripts/nix-provision.sh b/scripts/nix-provision.sh deleted file mode 100644 index dfca0326aa..0000000000 --- a/scripts/nix-provision.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env bash -# shellcheck shell=bash - -set -o errexit -set -o pipefail -set -o xtrace - -function install_packages { - # Setup Ansible on host VM - sudo apt-get update && sudo apt-get install -y software-properties-common - - # Install EC2-specific packages that were deferred from stage 1 - # These packages have post-install scripts that need EC2 metadata service access - # which only works on a real running EC2 instance (not in chroot) - sudo apt-get install -y ec2-hibinit-agent ec2-instance-connect hibagent - - # Manually add GPG key with explicit keyserver - sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 93C4A3FD7BB9C367 - - # Add repository and install - # TODO (darora): temporarily disabling while Launchpad is under ddos attack and very frequently timing out - # sudo add-apt-repository --yes ppa:ansible/ansible - # sudo apt-get update - sudo apt-get install -y ansible - - ansible-galaxy collection install community.general -} - - - -function install_nix() { - sudo su -c "sh <(curl -L https://releases.nixos.org/nix/nix-2.34.6/install) --yes --daemon --nix-extra-conf-file /dev/stdin < [INITIAL_PG_VERSION]" - exit 1 + echo "Usage: $0 [INITIAL_PG_VERSION]" + exit 1 fi INITIAL_PG_VERSION=${2:-15.1.1.60} @@ -20,11 +20,11 @@ LATEST_VERSION_SCRIPTS="scripts/pg_upgrade_scripts-${LATEST_PG_VERSION}.tar.gz" LATEST_VERSION_BIN="scripts/pg_upgrade_bin-${LATEST_PG_VERSION}.tar.gz" if [ ! -f "$LATEST_VERSION_SCRIPTS" ]; then - aws s3 cp "s3://${ARTIFACTS_BUCKET_NAME}/upgrades/postgres/supabase-postgres-${LATEST_PG_VERSION}/pg_upgrade_scripts.tar.gz" "$LATEST_VERSION_SCRIPTS" + aws s3 cp "s3://${ARTIFACTS_BUCKET_NAME}/upgrades/postgres/supabase-postgres-${LATEST_PG_VERSION}/pg_upgrade_scripts.tar.gz" "$LATEST_VERSION_SCRIPTS" fi if [ ! -f "$LATEST_VERSION_BIN" ]; then - aws s3 cp "s3://${ARTIFACTS_BUCKET_NAME}/upgrades/postgres/supabase-postgres-${LATEST_PG_VERSION}/24.04.tar.gz" "$LATEST_VERSION_BIN" + aws s3 cp "s3://${ARTIFACTS_BUCKET_NAME}/upgrades/postgres/supabase-postgres-${LATEST_PG_VERSION}/24.04.tar.gz" "$LATEST_VERSION_BIN" fi rm -rf scripts/pg_upgrade_scripts @@ -34,23 +34,23 @@ cp "$LATEST_VERSION_BIN" scripts/pg_upgrade_bin.tar.gz docker rm -f pg_upgrade_test || true docker run -t --name pg_upgrade_test --env-file .env \ - -v "$(pwd)/scripts:/tmp/upgrade" \ - --entrypoint /tmp/upgrade/entrypoint.sh -d \ - -p 5432:5432 \ - "supabase/postgres:${INITIAL_PG_VERSION}" + -v "$(pwd)/scripts:/tmp/upgrade" \ + --entrypoint /tmp/upgrade/entrypoint.sh -d \ + -p 5432:5432 \ + "supabase/postgres:${INITIAL_PG_VERSION}" sleep 3 while ! docker exec -it pg_upgrade_test bash -c "pg_isready"; do - echo "Waiting for postgres to start..." - sleep 1 + echo "Waiting for postgres to start..." + sleep 1 done echo "Running migrations" docker cp ../../migrations/db/migrations "pg_upgrade_test:/docker-entrypoint-initdb.d/" docker exec -it pg_upgrade_test bash -c '/docker-entrypoint-initdb.d/migrate.sh > /tmp/migrate.log 2>&1; exit $?' if [ $? -ne 0 ]; then - echo "Running migrations failed. Exiting." - exit 1 + echo "Running migrations failed. Exiting." + exit 1 fi echo "Running tests" @@ -62,19 +62,18 @@ psql -f "./tests/99-fixtures.sql" echo "Initiating pg_upgrade" docker exec -it pg_upgrade_test bash -c '/tmp/upgrade/pg_upgrade_scripts/initiate.sh "$PG_MAJOR_VERSION"; exit $?' if [ $? -ne 0 ]; then - echo "Initiating pg_upgrade failed. Exiting." - exit 1 + echo "Initiating pg_upgrade failed. Exiting." + exit 1 fi sleep 3 echo "Completing pg_upgrade" docker exec -it pg_upgrade_test bash -c 'rm -f /tmp/pg-upgrade-status; /tmp/upgrade/pg_upgrade_scripts/complete.sh; exit $?' if [ $? -ne 0 ]; then - echo "Completing pg_upgrade failed. Exiting." - exit 1 + echo "Completing pg_upgrade failed. Exiting." + exit 1 fi pg_prove tests/01-schema.sql pg_prove tests/02-data.sql pg_prove tests/03-settings.sql - diff --git a/tests/pg_upgrade/scripts/entrypoint.sh b/tests/pg_upgrade/scripts/entrypoint.sh index d9d80acd9e..7f4e784b72 100755 --- a/tests/pg_upgrade/scripts/entrypoint.sh +++ b/tests/pg_upgrade/scripts/entrypoint.sh @@ -1,8 +1,8 @@ #!/bin/bash -set -e +set -e -SCRIPT_DIR=$(dirname -- "$0";) +SCRIPT_DIR=$(dirname -- "$0") ls -la "$SCRIPT_DIR" @@ -21,5 +21,5 @@ su postgres -c "$(pg_config --bindir)/pg_ctl start -o '-c config_file=/etc/postg RECEIVED_EXIT_SIGNAL=false trap 'RECEIVED_EXIT_SIGNAL=true' SIGINT SIGTERM SIGUSR1 while ! ((RECEIVED_EXIT_SIGNAL)); do - sleep 5 + sleep 5 done