#!/bin/bash
set -u

# Version ID Block. Relies on +k filetype modifier.
#------------------------------------------------------------------------------
# shellcheck disable=SC2016
declare VersionID='$Id: //p4-sdp/r26.1.0.BETA/Server/Unix/p4/common/cloud/aws/bin/snapshot.sh#1 $ $Change: 33444 $'
declare VersionStream=${VersionID#*//}; VersionStream=${VersionStream#*/}; VersionStream=${VersionStream%%/*};
declare VersionCL=${VersionID##*: }; VersionCL=${VersionCL%% *}
declare Version=${VersionStream}.${VersionCL}
[[ "$VersionStream" == r* ]] || Version="${Version^^}"

# Get EBS volumes with Name tag of <host>-root, <host>-p4depots, and <host>-p4logs,
# e.g. perforce-01-root, perforce-01-p4depots, and perforce-01-p4logs. Take snapshots,
# and tag them with the current journal counter.
#
# IMPORTANT: These are the exact "Name" tag values this script looks for on
# real AWS EBS volumes. They must be kept in sync with whatever "Name" tags
# are actually applied to the EBS volumes backing live production P4 servers
# -- if a volume's real tag doesn't match one of these, this script will not
# find it and will skip snapshotting it (see the errmsg() below; not
# completely silent, but easy to miss if nobody's watching cron output).
# When the SDP's default mount-point naming changes (as it did for 2026.1,
# /hxdepots -> /mnt/p4depots and /hxlogs -> /mnt/p4logs, see SDP-1379),
# real, already-deployed EBS volumes tagged under the old convention need to
# either be re-tagged to match, or -- as a stopgap -- recognized via
# LegacyVolumeBaseName below so they don't silently stop being backed up.

declare ThisScript="${0##*/}"
declare ThisHost=${HOSTNAME%%.*}
declare VolumeBaseName=
declare VolumeName=
declare LegacyVolumeName=
declare SnapshotName=
declare VolumeId=
declare SnapshotId=
declare Cmd=
declare -i ExitCode=0
declare CurrentJournal=
declare SnapshotAgeToExpire=
declare CurrentDate=

# One release's worth of backward compatibility for EBS volumes not yet
# re-tagged after the 2026.1 mount-name rebrand (see the comment above).
# Maps the current volume-base-name to the legacy name it replaced; "root"
# has no legacy alias, since its name didn't change.
declare -A LegacyVolumeBaseName=( [p4depots]=hxdepots [p4logs]=hxlogs )

function msg () { echo -e "$*"; }
function errmsg () { msg "\\nError: ${1:-Unknown Error}\\n"; ExitCode=1; }
function warnmsg () { msg "\\nWarning: ${1:-Unknown Warning}\\n"; }
function bail () { errmsg "${1:-Unknown Error}"; exit "${2:-1}"; }

# Login to the server so the next command will work properly when testing the script in isolation
/p4/common/bin/p4login

# Get the latest journal version from the db.counters database
CurrentJournal=$("$P4DBIN" -r "$P4ROOT" -k db.counters -jd - 2>&1 | grep @journal@ | cut -d '@' -f 8)

# Set the 'aging off' duration, in days; snapshots older than this will be deleted
SnapshotAgeToExpire=90

msg "Started ${0##*/} version $Version at $(date)."

for VolumeBaseName in root p4depots p4logs; do
   VolumeName="${ThisHost}-${VolumeBaseName}"
   VolumeId=$(aws ec2 describe-volumes --filters Name=tag:Name,Values="$VolumeName" --query 'Volumes[*].{ID:VolumeId}' --output text)

   if [[ -z "$VolumeId" && -n "${LegacyVolumeBaseName[$VolumeBaseName]:-}" ]]; then
      LegacyVolumeName="${ThisHost}-${LegacyVolumeBaseName[$VolumeBaseName]}"
      VolumeId=$(aws ec2 describe-volumes --filters Name=tag:Name,Values="$LegacyVolumeName" --query 'Volumes[*].{ID:VolumeId}' --output text)
      if [[ -n "$VolumeId" ]]; then
         warnmsg "Volume tagged '$LegacyVolumeName' (legacy Name tag) instead of '$VolumeName'. Using it for now, but please re-tag this volume to '$VolumeName' -- this fallback is only intended to be temporary."
         VolumeName="$LegacyVolumeName"
      fi
   fi

   if [[ -z "$VolumeId" ]]; then
      errmsg "Could not determine VolumeId for $VolumeName. Skipping it."
      continue
   fi

   msg "Snapshotting volume $VolumeName [$VolumeId]."

   Cmd=$(aws ec2 create-snapshot --description "${VolumeName} snapshot created by ${ThisScript} on main p4d instance" --volume-id "$VolumeId" --query SnapshotId --output text)
   msg "Running: ${Cmd[*]}"
   SnapshotId=$("${Cmd[@]}")

# The tag "Contents" with value "Perforce Checkpoints and Archives" is used in the following section
# to identify snapshots that are specific to Perforce, so they can be deleted when they expire.

   if [[ -n "$SnapshotId" ]]; then
      msg "Snapshot created for $VolumeName on $ThisHost with Id: $SnapshotId."
      SnapshotName="${VolumeName}-${CurrentJournal}"
      Cmd=$(aws ec2 create-tags --resources "$SnapshotId" \
         --tags Key=Host,Value="$ThisHost" \
                Key=Contents,Value="Perforce Checkpoints and Archives" \
                Key=Name,Value="$SnapshotName" \
                Key=Backup,Value="true" \
                Key=Lifecycle,Value="Managed by /p4/common/cloud/aws/bin/snapshot.sh on main p4d instance" \
                --output text)
      if "${Cmd[@]}"; then
         msg "Verified: Resource tags applied."
      else
         errmsg "Failed to apply tags to Snapshot $SnapshotId."
      fi
   else
      errmsg "Failed to create snapshot for $VolumeName."
   fi
done

#############################################################
# This section automatically deletes snapshots that are     #
# older than $SnapshotAgeToExpire days. This replaces       #
# the lifecycle management portion of AWS's Snapshot        #
# automation, since the snapshots are generated externally. #
#############################################################

# Fetching snapshot IDs and their creation dates where tag Contents is 'Perforce Checkpoints and Archives'
snapshots_to_check=$(aws ec2 describe-snapshots --query "Snapshots[?Tags[?Key=='Contents' && Value=='Perforce Checkpoints and Archives']].[SnapshotId,StartTime]" --output text)

CurrentDate=$(date +%s)

while read -r snapshot_id creation_date; do
    # Converting snapshot creation date to seconds
    snapshot_date=$(date -d "$creation_date" +%s)

    # Calculate age of snapshot
    snapshot_age=$(( (CurrentDate - snapshot_date) / 86400 )) # 86400 seconds in a day

    # Check if snapshot is older than specified days
    if [ "$snapshot_age" -ge "$SnapshotAgeToExpire" ]; then
        echo "Deleting snapshot $snapshot_id which is $snapshot_age days old."
        aws ec2 delete-snapshot --snapshot-id "$snapshot_id"
    fi
done <<< "$snapshots_to_check"

if [[ "$ExitCode" -eq 0 ]]; then
   msg "Processing completed OK."
else
   msg "Processing completed WITH ERRORS. Review the output above."
fi

exit $ExitCode
