Subversion Repositories DevTools

Rev

Rev 6128 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5608 dpurdie 1
#!/bin/bash
2
#   This script will restore a package from S3 into dpkg_archive
3
#   See savePkgToS3.sh
4
#
5
#   The source bucket is: aupera-dpkg-quarantine
6
#   
7
#   The package version is expeced to be tar-zipped
8
#
9
#   The resulatant tar-zip will be transferred to S3
10
#
11
#       Reduced redundancy is used
12
#
13
#       Credentials: s3_dpkg user 
14
#
15
#       Usage:  getPkgFromS3.sh /PathTo/pkgName/pkgVersion
16
#
17
function doHelp {
18
cat <<endOfHelp
19
    Command: getPkgFromS3
20
 
21
    This program will retrieve tar-zip Package/Version from an Amazon S3 bucket
22
    and store it into a subdirectory specified
23
 
24
    Options
25
    -h, --help              - Display this message
26
    -v, --verbose           - Increase verbosity
27
    -q, --quiet             - No status messages
28
    -b, --bucket=name       - Specifies the name of the target bucket
29
    -p, --path=PVPath       - Specifies the path to the Package-Version to restore
30
    -f, --force             - Delete target and force package download
31
    -k, --key=keyVar        - Name of the EnvVar that conains the AWS key
32
                              Default is AWSKEY
33
    -s, --secret=secretVar  - Name of the EnvVar that conains the AWS secret
34
                              Default is AWSSECRET
6129 dpurdie 35
    -t, --test              - Do not copy, do not request Glacier restore
5608 dpurdie 36
 
37
   Example:
38
    getPkgFromS3.sh -p \$GBE_DPKG/AcceptanceTestFramework/1.0.10000.cr
39
endOfHelp
40
}
41
 
42
#
43
#   Init defaults
44
#
45
ProgName=getPkgFromS3
46
awsKeyVar=AWSKEY
47
awsSecretVar=AWSSECRET
48
bucket=aupera-dpkg-quarantine
49
verbose=1
50
forceDelete=0
6129 dpurdie 51
doOps=true
5608 dpurdie 52
 
53
# Note that we use `"$@"' to let each command-line parameter expand to a 
54
# separate word. The quotes around `$@' are essential!
55
# We need TEMP as the `eval set --' would nuke the return value of getopt.
6129 dpurdie 56
TEMP=$( getopt -n ${ProgName} -o qfvhb:p:k:s:t --long quiet,force,verbose,help,bucket:,path:,key:,secret:,test -- "$@" )
5608 dpurdie 57
 
58
if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
59
 
60
# Note the quotes around `$TEMP': they are essential!
61
eval set -- "$TEMP"
62
 
63
while true ; do
64
    case "$1" in
65
        -h|--help)    doHelp; exit 0;;
66
        -f|--force)   let forceDelete++; shift 1;;
67
        -q|--quiet)   verbose=0; shift 1;;
68
        -v|--verbose) let verbose++; shift 1;;
69
        -b|--bucket)  bucket="$2" ; shift 2 ;;
70
        -p|--path)    dpkgPath="$2" ; shift 2 ;;
71
        -k|--key)     awsKeyVar="$2" ; shift 2 ;;
72
        -s|--secret)  awsSecretVar="$2" ; shift 2 ;;
6129 dpurdie 73
        -t|--test)   doOps=false ; shift 1 ;;
5608 dpurdie 74
        --) shift ; break ;;
75
        *) echo "Internal error!" ; exit 1 ;;
76
    esac
77
done
78
 
79
if [ $verbose -gt 1 ] ; then
80
    echo bucket      :$bucket
81
    echo dpkgPath    :$dpkgPath
82
    echo awsKeyVar   :$awsKeyVar
83
    echo awsSecretVar:$awsSecretVar
84
 
85
    echo "Remaining arguments:"
86
    for arg do echo '--> '"\`$arg'" ; done
87
fi
88
 
89
: ${bucket:?No Bucket Specified}
90
: ${dpkgPath:?No Package Version Path}
91
: ${awsKeyVar:?No AWS Key specified}
92
: ${awsSecretVar:?No AWS Secret specified}
93
 
94
#
95
#   The KEY and the Secret are passed via EnvVars
96
#   The name of the vars are passed on the command line
97
#
98
aws_access_key_id=${!awsKeyVar}
99
aws_secret_access_key=${!awsSecretVar}
100
 
101
: ${aws_access_key_id:?No AWS Key found}
102
: ${aws_secret_access_key:?No AWS Secret found}
103
 
104
if [ $verbose -gt 1 ] ; then
105
    echo aws_access_key_id:$aws_access_key_id
106
    echo aws_secret_access_key:$aws_secret_access_key
107
fi
108
 
109
#
110
#   Determine
111
#       dpkgPath    - Cleanup the user arg
112
#       pkgBase     - Base of the package
113
#       pkgName     - Package Name
114
#       pkgVer      - Package Version
115
#
116
 
117
dpkgPath=${dpkgPath%/}
118
 
119
pkgBase=${dpkgPath%/*}
120
pkgBase=${pkgBase%/*}
121
 
122
pkgVer=${dpkgPath##*/}
123
 
124
pkgName=${dpkgPath%/*}
125
pkgName=${pkgName##*/}
126
 
127
if [ $verbose -gt 0 ] ; then
128
    echo Bucket  : $bucket
129
    echo pkgBase : $pkgBase
130
    echo pkgName : $pkgName
131
    echo pkgVer  : $pkgVer
132
fi
133
 
134
if [  ! -d $pkgBase ] ; then
135
    echo "Error: Package archive base does not exist: $pkgBase"
136
    exit 1
137
fi
138
 
139
# Force version deletion - more for test.
140
if [ $forceDelete -gt 0 ] ; then 
141
    [ $verbose -gt 0 ] && echo "Force removal of $pkgName/$pkgVer"
142
    if [ -d $dpkgPath ] ; then
6129 dpurdie 143
        if $doOps ; then
144
            chmod -R +w $dpkgPath
145
            rm -rf $dpkgPath
146
        else
147
            echo "TestMode: Did not remove: $pkgName/$pkgVer"
148
        fi     
5608 dpurdie 149
    fi
150
fi
151
 
152
if [  -d $dpkgPath ] ; then
153
    echo "Error: Target PV Path already exists: $dpkgPath"
6129 dpurdie 154
    echo "TestMode: $doOps"
155
    if ! $doOps ; then
156
        echo "TestMode: Error ignored"
157
    else
158
        exit 1
159
    fi
5608 dpurdie 160
fi
161
 
162
#
163
#   Create the source file name
164
#   Format: Quarantined/PkgName_PkgVersion.tgz
165
file="Quarantined/${pkgName}_${pkgVer}.tgz"
166
 
167
# Basic transfer requirements
168
resource="/${bucket}/${file}"
169
dateValue=$(date -R)
170
 
171
 
172
#############################################################
173
#   Fetch file info, just to be sure that the file is there
174
#   Get data about the file
175
#
176
# Calculate the HEAD signature.
177
#   Note the need for a triple \n
178
#   Is that because there is no contentType ?
179
#
180
stringToSign="HEAD\n\n\n${dateValue}\n${resource}"
181
signature=$(
182
    echo -en "${stringToSign}" |
183
    openssl sha1 -hmac "${aws_secret_access_key}" -binary |
184
    base64
185
)
186
 
187
#set -x
188
fileTest=0
189
[ $verbose -gt 1 ] && echo "Testing file presence: ${file}"
190
results=$(curl -I -X HEAD \
191
        -s \
192
         --insecure \
193
        -H "Host: ${bucket}.s3.amazonaws.com" \
194
        -H "Date: ${dateValue}" \
195
        -H "Authorization: AWS ${aws_access_key_id}:${signature}" \
196
        "https://${bucket}.s3.amazonaws.com/${file}" \
197
        )
6129 dpurdie 198
if [ $verbose -gt 2 ] ; then
199
    echo "Testing file response"
200
    echo "$results" | fold -w100 | awk '{print "    " $0}'
201
fi
202
 
5608 dpurdie 203
if [[ "$results" =~ "HTTP/1.1 200 OK" ]]; then
204
    fileTest=1
205
fi
206
 
207
# Display results
208
if [ $fileTest -gt 0 ]; then
209
    if [ $verbose -gt 1 ] ; then
210
        echo "${ProgName}: Package Version Exists: $pkgName/$pkgVer" 
211
    fi
212
else
213
    echo "${ProgName}: Error cannot access $pkgName/$pkgVer in S3 bucket ${bucket}"
214
    exit 1
215
fi
216
 
217
# Ensure correct storage class
6128 dpurdie 218
#   STANDARD_IA - Good
219
#   REDUCED_REDUNDANCY - Good
220
#   GLACIER - May be good
221
#       If it has been restored, then its good
222
#       Else its an error
223
#       Restored status is held in x-amz-restore attribute
224
#           When it exists the file is restored or is being restored
225
#           When the 'ongoing-request' is false, then it has been restored
226
canGet=false
227
mustRestore=false
228
message=""
5608 dpurdie 229
storageClass=$( echo $results | tr '\r' '\n' | awk -F: '/x-amz-storage-class/{print $2}')
230
[ $verbose -gt 0 ] && echo storageClass : $storageClass
5805 dpurdie 231
if [[ "$storageClass" != " REDUCED_REDUNDANCY" &&  "$storageClass" != " STANDARD_IA" ]]; then
6128 dpurdie 232
    if [[ "$storageClass" == " GLACIER" ]]; then
233
        [ $verbose -gt 1 ] && echo "$pkgName/$pkgVer has been transferred to glacier"
234
        glacierState="In Glacier"
235
        RestoreData=$( echo $results | tr '\r' '\n' | awk -F: '/x-amz-restore/{print $2,$3,$4,$5,$6,$7,$8,$9}')
236
        if [ -n "$RestoreData" ] ; then
237
            [ $verbose -gt 1 ] && echo "$pkgName/$pkgVer Restored progress: $RestoreData"
238
            ongoingRequest=$( echo "$RestoreData" | sed -n 's/.*ongoing-request="\([^"]*\)".*'/\\1/p)
239
            expiryDate=$( echo "$RestoreData" | sed -n 's/.*expiry-date="\([^"]*\)".*'/\\1/p )
240
            [ $verbose -gt 1 ] && echo "$pkgName/$pkgVer Restored State: $ongoingRequest"
241
            [ $verbose -gt 1 ] && echo "$pkgName/$pkgVer Restored Expiry Date: $expiryDate"
242
            if [ "$ongoingRequest" != "false" ] ; then
243
                glacierState="Restore in progress"
244
                message="Restore not complete: ongoing-request=$ongoingRequest"
245
            else
246
                glacierState="Restored"
247
                canGet=true
248
            fi
249
        else
250
            message="Incorrect storage class: '$storageClass'"
251
            mustRestore="true"        
252
        fi
253
        [ $verbose -gt 0 ] && echo "glacierState : $glacierState"
254
    else
255
        message="Unhandled storage class: '$storageClass'"        
256
    fi
257
else
258
    canGet=true
5608 dpurdie 259
fi
260
 
6128 dpurdie 261
##############################################################
262
#   Initiate a Restore from Glacier
263
#
264
if $mustRestore ; then
6129 dpurdie 265
    if $doOps ; then
6128 dpurdie 266
        [ $verbose -gt 0 ] && echo "Initiate restore from Glacier $pkgName/$pkgVer"
267
 
268
        # Generate a Restore Request
269
        #   And an MD5 over the data
270
        tmpData=$( mktemp )
271
        echo > $tmpData '<RestoreRequest>'
272
        echo >>$tmpData '  <Days>1</Days>'
273
        echo >>$tmpData '  <GlacierJobParameters>'
274
        echo >>$tmpData '    <Tier>Standard</Tier>'
275
        echo >>$tmpData '  </GlacierJobParameters>'
276
        echo >>$tmpData '</RestoreRequest>'
277
 
278
        md5Value=$(
279
            openssl md5 -binary $tmpData |
280
            base64
281
        )
282
 
283
        # Generate the request signature
284
        contentType="application/xml"
285
        stringToSign="POST\n${md5Value}\n${contentType}\n${dateValue}\n${resource}?restore"
286
        signature=$(
287
            echo -en "${stringToSign}" |
288
            openssl sha1 -hmac "${aws_secret_access_key}" -binary |
289
            base64
290
        )
291
 
292
        #set -x
293
        tmpResult=$( mktemp )
294
        results=$(curl -s -w '%{http_code}' -o $tmpResult\
295
             --insecure \
296
             --data @$tmpData \
297
            -H "Host: ${bucket}.s3.amazonaws.com" \
298
            -H "Date: ${dateValue}" \
299
            -H "Content-MD5: ${md5Value}" \
300
            -H "Authorization: AWS ${aws_access_key_id}:${signature}" \
301
            -H "Content-Type: ${contentType}" \
302
            "https://${bucket}.s3.amazonaws.com/${file}?restore"
303
            )
304
 
305
        canGet=false
306
        if [[ "$results" == "200" ]] ; then
307
            canGet=true
308
        elif [[ "$results" == "202" ]] ; then
309
            message="Restore from Glacier initiated"
310
        elif [[ "$results" == "409" ]] ; then
311
            message="Restore already in progress"
312
        elif [[ "$results" == "503" ]] ; then
313
            message="Glacier expedited retrievals are currently not available"
314
        else
315
            mesage="Error previously reported"
316
            echo "Glacier restore error code: $results"
6129 dpurdie 317
            tail -n+2 $tmpResult | fold -w100 | awk '{print "    " $0}'
6128 dpurdie 318
        fi                              
319
        set +x
320
        rm -rf $tmpData $tmpResult
321
 
6129 dpurdie 322
    else
323
        echo "TestMode: Do not request Glacier Restore"
6128 dpurdie 324
    fi
325
fi
326
 
327
if ! $canGet; then
328
        echo "${ProgName}: Error cannot access $pkgName/$pkgVer. $message"
329
        echo "Resource: $resource"
330
        exit 1
331
fi
332
 
5608 dpurdie 333
#############################################################
334
# GET!
335
 
336
# Calculate the signature.
337
#   Note the need for a triple \n
338
#   Needed becase there is no content type
339
stringToSign="GET\n\n\n${dateValue}\n${resource}"
340
signature=$(
341
    echo -en "${stringToSign}" |
342
    openssl sha1 -hmac "${aws_secret_access_key}" -binary |
343
    base64
344
)
345
 
346
#echo dateValue: ${dateValue} 
347
#echo stringToSign: ${stringToSign}
348
#echo signature: ${signature}
349
#exit 1
350
 
351
mkdir -p $dpkgPath
352
if [  ! -d $dpkgPath ] ; then
353
    echo "Error: Could not create: $dpkgPath"
354
    exit 1
355
fi
356
 
6129 dpurdie 357
if $doOps ; then
358
    [ $verbose -gt 0 ] && echo "Transfer $pkgName/$pkgVer from bucket $bucket"
359
    #set -x
360
        curl -s \
361
            -X GET \
362
             --insecure \
363
            -H "Host: ${bucket}.s3.amazonaws.com" \
364
            -H "Date: ${dateValue}" \
365
            -H "Authorization: AWS ${aws_access_key_id}:${signature}" \
366
            "https://${bucket}.s3.amazonaws.com/${file}" \
367
            | tar -xz --strip=2 -C $dpkgPath
5608 dpurdie 368
 
6129 dpurdie 369
    if [ ! -f "$dpkgPath/descpkg" ] ; then
370
        echo "Error: Target PV did not populate as expected: $dpkgPath"
5608 dpurdie 371
 
6129 dpurdie 372
        # Remove if not correctly formatted
373
        chmod -R +w $dpkgPath
374
        rm -rf $dpkgPath
375
        exit 1
376
    else
377
        # Package extracted
378
        # Touch the top directory so that it will not be quarantined immediatly
379
        chmod +w "$dpkgPath"
380
        chmod -w "$dpkgPath"
381
    fi
6128 dpurdie 382
else
6129 dpurdie 383
    echo "TestNode: Did not transfer $pkgName/$pkgVer from bucket $bucket"
5608 dpurdie 384
fi
385
 
386
[ $verbose -gt 0 ] && echo "Transfer complete"
387
 
388
 
389
 
390