#!/bin/sh
#
# Example code how to retrieve an object from the P5 Object Archive
# using publicly available AWS CLI utility.
# Uploading files require no special treatment.
#
# It is recommended to create separate profile for AWS CLI for accessing
# files on the P5 Object Archive. Note: when creating profiles with the
# AWS configure utility, leave the region name and output format to "None".
#
# Usage:
#
#   sh aws_restore.sh URL Bucket_Name File_Path Destination_Path AWS_Profile
#
# Notes:
#
# URL is in form http://ip:port or https://ip:port
# Standard for P5 Object Archive: http port is 8000, https 8443.
#
# Bucket_Name is the name of the P5 Object Bucket.
#
# File_Path is the name of the object to be retrieved.
# It must be passed in relative format (must not begin with '/').

# Destination_Path is where the object will be stored on the filesystem.
#
# AWS_Profile is optional, will use default AWS profile if ommited.
#
# An example of how to retrieve object from P5 Object Archive:
#
#   sh aws_restore.sh http://192.168.1.200:8000 MyBucket MyFile.zip . p5-s3
#
# See the file "license.txt" for information on usage and
# redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
#############################################################################

#
# Check usage and identify parameters
#

if test $# -le 3; then
    echo "Usage: url bucket path destination profile=default"
    exit 1
fi

url=$1
bucket=$2
path=$3
destination=$4

if test $# -eq 5; then
    profile=$5
else
    profile=default
fi

#
# Get attributes of the object identified by path/object-ID
#

result=`aws s3api head-object --profile $profile --endpoint-url $url --bucket $bucket --key $path`
if test $? -ne 0; then
    echo $result
    exit 1
fi

#
#  Examples for states of objects that are subject
#  to archive/restore process.
#  Note that only relevant parts of the response is
#  shown. The real response may include additional
#  information which is not shown here.
#
#  1.
#
#  Objects that have been recently uploaded and have
#  not yet been processed by the archive process yet.
#  Those can be imediately downloaded.
#
#    {
#        "LastModified": "2024-01-25T23:05:17+00:00",
#        "ContentLength": 50750346284,
#        "ETag": "\"84975a9e8fe2707042a1c00e73efe720-48\"",
#        "ContentType": "application/octet-stream",
#    }
#
#  2.
#
#  Objects that were archived and are not available for the
#  immediate download, but the restore process is started.
#  Restore process may take undefinite time.
#
#    {
#        "Restore": "ongoing-request=\"true\"",
#        "StorageClass": "DEEP_ARCHIVE"
#    }
#
#  3.
#
#  Objects that have been restored. Such objects have
#  temporary lifetime as stated in expiry-date value.
#
#     {
#        "Restore": "ongoing-request=\"false\", expiry-date=\"Tue, 30 Jan 2024 11:38:32 GMT\"",
#     }
#

#
# Obtain the storage class of the requested object.
# Storage class decides wether the object is immediately available
# for download, or if some extra action has to be made.
#

storageClass=`echo $result | sed -e 's/[{}]/''/g' | sed s/\"//g | awk -v RS=',' -F: '/StorageClass/ {print $2}' | tr -d " \t\n\r"`

if test "$storageClass" = "GLACIER"; then

    #
    # This class allows expedited retrieval (fast)
    #

    retrivalMode="Expedited"

elif test "$storageClass" = "DEEP_ARCHIVE"; then

    #
    # This implies potentially very long retrieval time
    #

    retrivalMode="Standard"

else

    #
    # For any other storage class, object should be
    # available for retrieval immediately.
    #

    aws --profile $profile --endpoint-url $url s3 cp s3://$bucket/$path $destination
    exit 0
fi

#
# Make sure object is pulled back from it's deep storage.
# We might have to wait and loop at this place for sometime.
#

restore=`echo $result | sed -e 's/[{}]//g' | awk -F: '/Restore/ {print $3}'`
if test -z "$restore" -o -n "`echo $restore | grep null`"; then

    #
    # Initate restore process on the server.
    # Instruct to keep restored file for 1 day.
    #

    request='{"Days":1,"GlacierJobParameters":{"Tier":"'$retrivalMode'"}}'
    aws s3api restore-object --profile $profile --endpoint-url $url --restore-request $request --bucket $bucket --key $path

elif test -n "`echo $restore | grep expiry-date`"; then

    #
    # Object is retrievable temporarily and will stay so
    # for the duration of "Days" as given by the restore request.
    # After that time, object can be garbage-collected by the
    # system anytime.
    #

    aws --profile $profile --endpoint-url $url s3 cp s3://$bucket/$path $destination
    exit 0
fi

#
# At this point we know the object is not immediately available
# but we initiated the process of moving the data from the deep
# storage back online. This may take a while.
# Keep testing the status of the object until it gets restored.
# The key element are these lines from the HEAD response:
#
#    "Restore": "ongoing-request=\"true\"",
# This one signalizes restore request is still underway.
#
#    "Restore": "ongoing-request=\"false\", expiry-date=\"Tue, 30 Jan 2024 11:38:32 GMT\"",
# This one signalizes restore is done so one can download the object.
#

while true
do
    result=`aws s3api head-object --profile $profile --endpoint-url $url --bucket $bucket --key $path`
    restore=`echo $result | sed -e 's/[{}]//g' | awk -F: '/Restore/ {print $3}'`
    if test -n "`echo "$restore" | grep true`" -o -z "`echo "$restore" | grep expiry-date`"; then
        echo "Restore is still underway. Please wait..."
        sleep 60
    else
        aws --profile $profile --endpoint-url $url s3 cp s3://$bucket/$path $destination
        break
    fi
done

exit 0
