| 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 |
|