diff --git a/ansible/files/admin_api_scripts/mount-volume.sh b/ansible/files/admin_api_scripts/mount-volume.sh new file mode 100644 index 000000000..5f4277f2d --- /dev/null +++ b/ansible/files/admin_api_scripts/mount-volume.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash + +set -euo pipefail + +DEVICE=${1:-} +MOUNT_POINT=${2:-} + +if [[ -z "$DEVICE" || -z "$MOUNT_POINT" ]]; then + echo "Usage: $0 " + echo "Example: sudo ./mount-volume.sh /dev/nvme1n1 /data/150008" + exit 1 +fi + +# Mount a block device to a specified mount point +# If the device is not formatted, format it as ext4 +# Set ownership to postgres:postgres and permissions to 750 +# Add the mount entry to /etc/fstab for persistence across reboots + +OWNER="postgres:postgres" +PERMISSIONS="750" +FSTYPE="ext4" +MOUNT_OPTS="defaults" +FSTAB_FILE="/etc/fstab" + +if [ ! -b "$DEVICE" ]; then + echo "Error: Block device '$DEVICE' does not exist." + exit 2 +fi + +if ! blkid "$DEVICE" >/dev/null 2>&1; then + echo "Device $DEVICE appears unformatted. Formatting as $FSTYPE..." + mkfs."$FSTYPE" -F "$DEVICE" +else + echo "$DEVICE already has a filesystem — skipping format." +fi + +mkdir -p "$MOUNT_POINT" + +e2fsck -pf "$DEVICE" + +if ! mountpoint -q "$MOUNT_POINT"; then + echo "Mounting $DEVICE to $MOUNT_POINT" + mount -t "$FSTYPE" -o "$MOUNT_OPTS" "$DEVICE" "$MOUNT_POINT" +else + echo "$MOUNT_POINT is already mounted" +fi + +echo "Setting ownership and permissions on $MOUNT_POINT" +chown "$OWNER" "$MOUNT_POINT" +chmod "$PERMISSIONS" "$MOUNT_POINT" + +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 + echo "Adding $FSTAB_LINE to $FSTAB_FILE" + echo "$FSTAB_LINE" >> "$FSTAB_FILE" +else + echo "UUID $UUID already in $FSTAB_FILE — skipping" +fi + +echo "Mounted $DEVICE at $MOUNT_POINT with postgres:postgres and mode $PERMISSIONS" diff --git a/ansible/files/admin_api_scripts/unmount-volume.sh b/ansible/files/admin_api_scripts/unmount-volume.sh new file mode 100644 index 000000000..6250b8c47 --- /dev/null +++ b/ansible/files/admin_api_scripts/unmount-volume.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +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 +fi + +# Unmount a block device from a specified mount point +# 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" +else + 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" +else + 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" +fi + +echo "Unmount and cleanup complete for $MOUNT_POINT" diff --git a/ansible/files/adminapi.sudoers.conf b/ansible/files/adminapi.sudoers.conf index 531d47ca1..904377c29 100644 --- a/ansible/files/adminapi.sudoers.conf +++ b/ansible/files/adminapi.sudoers.conf @@ -5,6 +5,8 @@ Cmnd_Alias GOTRUE = /bin/systemctl start gotrue.service, /bin/systemctl stop got Cmnd_Alias PGBOUNCER = /bin/systemctl start pgbouncer.service, /bin/systemctl stop pgbouncer.service, /bin/systemctl restart pgbouncer.service, /bin/systemctl disable pgbouncer.service, /bin/systemctl enable pgbouncer.service, /bin/systemctl reload pgbouncer.service, /bin/systemctl try-restart pgbouncer.service %adminapi ALL= NOPASSWD: /root/grow_fs.sh +%adminapi ALL= NOPASSWD: /root/mount-volume.sh +%adminapi ALL= NOPASSWD: /root/unmount-volume.sh %adminapi ALL= NOPASSWD: /root/manage_readonly_mode.sh %adminapi ALL= NOPASSWD: /etc/adminapi/pg_upgrade_scripts/prepare.sh %adminapi ALL= NOPASSWD: /etc/adminapi/pg_upgrade_scripts/initiate.sh diff --git a/ansible/tasks/internal/admin-api.yml b/ansible/tasks/internal/admin-api.yml index 5eb6fd276..5844b3f54 100644 --- a/ansible/tasks/internal/admin-api.yml +++ b/ansible/tasks/internal/admin-api.yml @@ -14,6 +14,8 @@ - { file: "grow_fs.sh" } - { file: "manage_readonly_mode.sh" } - { file: "pg_egress_collect.pl" } + - { file: "mount-volume.sh" } + - { file: "unmount-volume.sh" } - name: give adminapi user permissions copy: