From d26845d7be6dad30c52152f933d8dafd64904f9b Mon Sep 17 00:00:00 2001 From: Tom Scavo <trscavo@internet2.edu> Date: Sat, 10 Jun 2017 15:55:14 -0400 Subject: [PATCH] Improve error handling --- bin/compute_vital_statistics.sh | 182 ++++++++++++++++++++++++++------ 1 file changed, 149 insertions(+), 33 deletions(-) diff --git a/bin/compute_vital_statistics.sh b/bin/compute_vital_statistics.sh index 1f44f6a..44afa56 100755 --- a/bin/compute_vital_statistics.sh +++ b/bin/compute_vital_statistics.sh @@ -22,9 +22,12 @@ display_help () { /bin/cat <<- HELP_MSG - This script parses one or more SAML metadata aggregates and - produces a JSON file of vital statistics (such as validUntil, - creationInstant, etc.) + This script parses one or more SAML metadata files and + produces a JSON file of vital statistics. Each metadata file + must contain the following attributes: + + /md:EntitiesDescriptor/@validUntil + /md:EntitiesDescriptor/md:Extensions/mdrpi:PublicationInfo/@creationInstant The script depends on cached metadata. It will not fetch a metadata file from the server. @@ -86,21 +89,28 @@ display_help () { OUTPUT - The script outputs a JSON file containing a single array. - Each array element is a JavaScript object with the following - fields: - - metadataLocation: location - currentTime: dateTime - validUntil: dateTime - creationInstant: dateTime - validityInterval: duration - untilInvalid: duration - sinceCreation: duration + The script outputs a JSON file to OUT_DIR: + + $out_filename + + The JSON file contains a single array. Each array element is + a JavaScript object with the following fields: + + successFlag boolean success or failure? + message string message string + metadataLocation string HTTP location + currentTime string ISO 8601 dateTime + validUntil dateTime ISO 8601 dateTime + creationInstant dateTime ISO 8601 dateTime + validityInterval duration ISO 8601 duration + untilInvalid duration ISO 8601 duration + sinceCreation duration ISO 8601 duration For example: { + "successFlag": true, + "message": "Integrity of compressed metadata confirmed", "metadataLocation": "http://md.incommon.org/InCommon/InCommon-metadata.xml", "currentTime": "2017-06-06T23:57:54Z", "validUntil": "2017-06-16T18:41:12Z", @@ -190,6 +200,9 @@ if [ ! -f "$xsl_path" ]; then exit 2 fi +# output filename +out_filename="md_vital_statistics.json" + ####################################################################### # Process command-line options and arguments ####################################################################### @@ -266,7 +279,6 @@ fi # specify temporary files xml_path="${tmp_dir}/saml-metadata.xml" -out_filename=md_vital_statistics.json out_file="${tmp_dir}/$out_filename" ####################################################################### @@ -281,6 +293,7 @@ escape_special_json_chars () { } append_json_object () { + local message=$( escape_special_json_chars "$message" ) local metadataLocation=$( escape_special_json_chars "$md_location" ) local currentTime=$( escape_special_json_chars "$now" ) local validUntil=$( escape_special_json_chars "$validUntil" ) @@ -289,8 +302,13 @@ append_json_object () { local untilInvalid=$( escape_special_json_chars "$untilInvalid" ) local sinceCreation=$( escape_special_json_chars "$sinceCreation" ) + local boolean_value="true" + ! $success && boolean_value="false" + /bin/cat <<- JSON_OBJECT { + "successFlag": $boolean_value, + "message": "$message", "metadataLocation": "$metadataLocation", "currentTime": "$currentTime", "validUntil": "$validUntil", @@ -302,7 +320,9 @@ append_json_object () { JSON_OBJECT } -parse_metadata () { +get_metadata () { + + local status_code md_location="$1" @@ -311,73 +331,169 @@ parse_metadata () { status_code=$? if [ $status_code -eq 1 ]; then # metadata must be cached + success=false + message="Metadata not found" print_log_message -E "$script_name: metadata file not cached: $md_location" - clean_up_and_exit -d "$tmp_dir" 1 + return 1 fi if [ $status_code -gt 1 ]; then + success=false + message="Request for metadata failed" print_log_message -E "$script_name: conditional_get failed ($status_code) on location: $md_location" - clean_up_and_exit -d "$tmp_dir" $status_code + return 3 fi + + return 0 +} + +parse_metadata () { + + local status_code + local tstamps + local validityIntervalSecs + local secsUntilInvalid + local secsSinceCreation + print_log_message -I "$script_name parsing cached metadata file: $md_location" # extract @ID, @creationInstant, @validUntil (in that order) tstamps=$( /usr/bin/xsltproc $xsl_path $xml_path ) + status_code=$? + if [ $status_code -ne 0 ]; then + success=false + message="Unable to parse metadata" + print_log_message -E "$script_name: xsltproc failed ($status_code) on script: $xsl_path" + return 0 + fi - # If @validUntil missing, then FAIL + # get @validUntil validUntil=$( echo "$tstamps" | $_CUT -f3 ) + status_code=$? + if [ $status_code -ne 0 ]; then + success=false + message="Unable to parse @validUntil" + print_log_message -E "$script_name: cut failed ($status_code)" + return 0 + fi + + # if @validUntil is missing, then FAIL if [ -z "$validUntil" ]; then + success=false + message="XML attribute @validUntil not found" print_log_message -E "$script_name: @validUntil not found" - clean_up_and_exit -d "$tmp_dir" 4 + return 0 fi print_log_message -D "$script_name found @validUntil: $validUntil" - # If @creationInstant missing, then FAIL + # get @creationInstant creationInstant=$( echo "$tstamps" | $_CUT -f2 ) + status_code=$? + if [ $status_code -ne 0 ]; then + success=false + message="Unable to parse @creationInstant" + print_log_message -E "$script_name: cut failed ($status_code)" + return 0 + fi + + # if @creationInstant is missing, then FAIL if [ -z "$creationInstant" ]; then + success=false + message="XML attribute @creationInstant not found" print_log_message -E "$script_name: @creationInstant not found" - clean_up_and_exit -d "$tmp_dir" 5 + return 0 fi print_log_message -D "$script_name found @creationInstant: $creationInstant" - # If validityInterval > 14 days, then FAIL + # compute validityInterval validityIntervalSecs=$( secsUntil -b $creationInstant $validUntil ) + status_code=$? + if [ $status_code -ne 0 ]; then + success=false + message="Unable to compute validity interval" + print_log_message -E "$script_name: secsUntil failed ($status_code)" + return 0 + fi + + # if validityInterval > 14 days, then FAIL # TODO: Generalize if (( validityIntervalSecs > 14*24*60*60 )); then + success=false + message="Validity interval too large" print_log_message -E "$script_name: validity interval exceeds maximum: $validityIntervalSecs" - clean_up_and_exit -d "$tmp_dir" 6 + return 0 fi validityInterval=$( secs2duration $validityIntervalSecs ) print_log_message -D "$script_name computed validity interval: $validityInterval" # compute NOW now=$( dateTime_now_canonical ) + status_code=$? + if [ $status_code -ne 0 ]; then + success=false + message="Unable to compute current time" + print_log_message -E "$script_name: dateTime_now_canonical failed ($status_code)" + return 0 + fi - # If secsUntilInvalid <= 0, then FAIL + # compute secsUntilInvalid secsUntilInvalid=$( echo $validUntil | secsUntil -b $now ) + status_code=$? + if [ $status_code -ne 0 ]; then + success=false + message="Unable to compute time to expiration" + print_log_message -E "$script_name: secsUntil failed ($status_code)" + return 0 + fi + + # if secsUntilInvalid <= 0, then FAIL if (( secsUntilInvalid <= 0 )); then - print_log_message -E "$script_name: seconds until invalid not positive: $secsUntilInvalid" - clean_up_and_exit -d "$tmp_dir" 7 + success=false + message="Metadata is expired" + print_log_message -C "$script_name: seconds until invalid not positive: $secsUntilInvalid" + return 0 fi untilInvalid=$( secs2duration "$secsUntilInvalid" ) print_log_message -D "$script_name computed time until invalid: $untilInvalid" - # If secsSinceCreation <= 0, then FAIL + # compute secsSinceCreation secsSinceCreation=$( echo $creationInstant | secsSince -e $now ) + status_code=$? + if [ $status_code -ne 0 ]; then + success=false + message="Unable to compute time since creation" + print_log_message -E "$script_name: secsSince failed ($status_code)" + return 0 + fi + + # if secsSinceCreation <= 0, then FAIL if (( secsSinceCreation <= 0 )); then - print_log_message -E "$script_name: seconds since creation not positive: $secsSinceCreation" - clean_up_and_exit -d "$tmp_dir" 8 + success=false + message="Metadata is not valid" + print_log_message -C "$script_name: seconds since creation not positive: $secsSinceCreation" + return 0 fi sinceCreation=$( secs2duration "$secsSinceCreation" ) print_log_message -D "$script_name computed time since creation: $sinceCreation" + + # success + message="Metadata successfully parsed" } -print_vital_statistics () { +print_output_file () { + + local status_code # begin output list printf "[\n" while true; do - parse_metadata "$1" + success=true + + get_metadata "$1" + status_code=$? + if [ $status_code -eq 0 ]; then + parse_metadata + fi append_json_object shift; (( "$#" )) || break @@ -397,7 +513,7 @@ print_vital_statistics () { print_log_message -I "$script_name BEGIN" # create the JSON output -print_vital_statistics "$@" > "$out_file" +print_output_file "$@" > "$out_file" print_log_message -I "$script_name writing output file: $out_filename" # move the output file to the web directory