Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Commit new executable
Tom Scavo
committed
May 28, 2017
1 parent
6d7a590
commit 20731fc
Showing
2 changed files
with
383 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,382 @@ | ||
#!/bin/bash | ||
|
||
####################################################################### | ||
# Copyright 2017 Internet2 | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
####################################################################### | ||
|
||
####################################################################### | ||
# Help message | ||
####################################################################### | ||
|
||
display_help () { | ||
/bin/cat <<- HELP_MSG | ||
This script applies an arbitrary sequence of XSLT scripts | ||
against a SAML metadata aggregate. The output files will | ||
be written to the output directory specified on the | ||
command line. | ||
The script depends on cached metadata. It will not fetch | ||
a metadata file from the server. | ||
Usage: ${0##*/} [-hv] -u MD_LOCATION -d OUT_DIR "XSL_FILENAME [OUTPUT_FILENAME]" ... | ||
The script takes an arbitrary sequence of compound command-line | ||
arguments. The second sub-argument of each compound argument is | ||
OPTIONAL. If no OUTPUT_FILENAME is given for a particular | ||
XSL_FILENAME, the script computes an output filename as best | ||
it can. | ||
Options: | ||
-h Display this help message | ||
-v Enable DEBUG mode | ||
-u Specify the metadata location | ||
-d Specify the output directory | ||
Option -h is mutually exclusive of all other options. | ||
Option -u specifies the location of the metadata file on the | ||
network. The script uses the location to retrieve the file | ||
from cache. If the file is not cached, the script will fail. | ||
This option is REQUIRED. | ||
Option -d specifies the ultimate output directory, which is | ||
usually a web directory. This option is REQUIRED. | ||
Output is all or none. The output files are computed | ||
sequentially and assembled one-by-one in a temporary | ||
directory. All of the output files are moved to the | ||
destination directory at the same time. If even one output | ||
file can not be computed---for whatever reason---none are | ||
written to the output directory. | ||
ENVIRONMENT | ||
This script leverages a handful of environment variables: | ||
LIB_DIR A source library directory | ||
CACHE_DIR A persistent HTTP cache | ||
TMPDIR A temporary directory | ||
LOG_FILE A persistent log file | ||
LOG_LEVEL The global log level [0..5] | ||
All of the above environment variables are REQUIRED | ||
except LOG_LEVEL, which defaults to LOG_LEVEL=3. | ||
The following environment variables are REQUIRED: | ||
$( printf " %s\n" ${env_vars[*]} ) | ||
The following directories MUST exist: | ||
$( printf " %s\n" ${dir_paths[*]} ) | ||
The following files MUST exist: | ||
$( printf " %s\n" $LOG_FILE ) | ||
CONFIGURATION | ||
The following source library files MUST be installed in LIB_DIR: | ||
$( printf " %s\n" ${lib_filenames[*]} ) | ||
EXAMPLES | ||
\$ ${0##*/} -h | ||
\$ md_location=http://md.incommon.org/InCommon/InCommon-metadata-export.xml | ||
\$ out_dir=/home/htdocs/www.incommonfederation.org/federation/metadata/ | ||
\$ ${0##*/} -u \$md_location -d \$out_dir \\ | ||
"list_all_IdPs_csv.xsl all_IdPs_exported.csv" \\ | ||
"list_all_SPs_csv.xsl all_SPs_exported.csv" | ||
HELP_MSG | ||
} | ||
|
||
####################################################################### | ||
# Bootstrap | ||
####################################################################### | ||
|
||
script_name=${0##*/} # equivalent to basename $0 | ||
|
||
# required environment variables | ||
env_vars[1]="LIB_DIR" | ||
env_vars[2]="CACHE_DIR" | ||
env_vars[3]="TMPDIR" | ||
env_vars[4]="LOG_FILE" | ||
|
||
# check environment variables | ||
for env_var in ${env_vars[*]}; do | ||
eval "env_var_val=\${$env_var}" | ||
if [ -z "$env_var_val" ]; then | ||
echo "ERROR: $script_name requires env var $env_var" >&2 | ||
exit 2 | ||
fi | ||
done | ||
|
||
# required directories | ||
dir_paths[1]="$LIB_DIR" | ||
dir_paths[2]="$CACHE_DIR" | ||
dir_paths[3]="$TMPDIR" | ||
|
||
# check required directories | ||
for dir_path in ${dir_paths[*]}; do | ||
if [ ! -d "$dir_path" ]; then | ||
echo "ERROR: $script_name: directory does not exist: $dir_path" >&2 | ||
exit 2 | ||
fi | ||
done | ||
|
||
# check the log file | ||
# devices such as /dev/tty and /dev/null are allowed | ||
if [ ! -f "$LOG_FILE" ] && [[ $LOG_FILE != /dev/* ]]; then | ||
echo "ERROR: $script_name: file does not exist: $LOG_FILE" >&2 | ||
exit 2 | ||
fi | ||
|
||
# default to INFO logging | ||
if [ -z "$LOG_LEVEL" ]; then | ||
LOG_LEVEL=3 | ||
fi | ||
|
||
# library filenames | ||
lib_filenames[1]="core_lib.sh" | ||
lib_filenames[2]="http_tools.sh" | ||
|
||
# check lib files | ||
for lib_filename in ${lib_filenames[*]}; do | ||
lib_file="$LIB_DIR/$lib_filename" | ||
if [ ! -f "$lib_file" ]; then | ||
echo "ERROR: $script_name: lib file does not exist: $lib_file" >&2 | ||
exit 2 | ||
fi | ||
done | ||
|
||
####################################################################### | ||
# Process command-line options and arguments | ||
####################################################################### | ||
|
||
help_mode=false; local_opts= | ||
while getopts ":hvu:d:" opt; do | ||
case $opt in | ||
h) | ||
help_mode=true | ||
;; | ||
v) | ||
LOG_LEVEL=4 | ||
local_opts="$local_opts -$opt" | ||
;; | ||
u) | ||
md_location="$OPTARG" | ||
;; | ||
d) | ||
out_dir="$OPTARG" | ||
;; | ||
\?) | ||
echo "ERROR: $script_name: Unrecognized option: -$OPTARG" >&2 | ||
exit 2 | ||
;; | ||
:) | ||
echo "ERROR: $script_name: Option -$OPTARG requires an argument" >&2 | ||
exit 2 | ||
;; | ||
esac | ||
done | ||
|
||
if $help_mode; then | ||
display_help | ||
exit 0 | ||
fi | ||
|
||
# check the metadata location | ||
if [ -z "$md_location" ]; then | ||
echo "ERROR: $script_name: no metadata location specified (option -u)" >&2 | ||
exit 2 | ||
fi | ||
|
||
# check the output directory | ||
if [ -z "$out_dir" ]; then | ||
echo "ERROR: $script_name: no output directory specified (option -d)" >&2 | ||
exit 2 | ||
fi | ||
if [ ! -d "$out_dir" ]; then | ||
echo "ERROR: $script_name: directory does not exist: $out_dir" >&2 | ||
exit 2 | ||
fi | ||
|
||
# check command-line arguments | ||
shift $(( OPTIND - 1 )) | ||
if [ $# -eq 0 ]; then | ||
echo "ERROR: $script_name: wrong number of arguments: $# (at least one required)" >&2 | ||
exit 2 | ||
fi | ||
|
||
####################################################################### | ||
# Functions | ||
####################################################################### | ||
|
||
# process a compound command-line argument | ||
# present that argument to this function as a pair of arguments: | ||
# XSL_FILENAME [OUTPUT_FILENAME] | ||
# if the latter is omitted, the function computes a suitable output filename | ||
process_arg () { | ||
|
||
local xsl_file | ||
local base_filename | ||
local output_filename | ||
|
||
# check the command-line arguments | ||
if [ $# -lt 1 -o $# -gt 2 ]; then | ||
echo "ERROR: $FUNCNAME: incorrect number of arguments: $# (1 or 2 required)" >&2 | ||
return 2 | ||
fi | ||
|
||
# the first arg is an XSL filename | ||
# the second arg is an (optional) output filename | ||
|
||
# does the first arg end in .xsl? | ||
if [[ $1 != *.xsl ]]; then | ||
echo "ERROR: $FUNCNAME: XSL filename does not end in .xsl: $1" >&2 | ||
return 3 | ||
fi | ||
|
||
# does the corresponding file exist? | ||
xsl_file="$LIB_DIR/$1" | ||
if [ ! -f "$xsl_file" ]; then | ||
echo "ERROR: $FUNCNAME: lib file does not exist: $xsl_file" >&2 | ||
exit 4 | ||
fi | ||
|
||
# capture array elements | ||
xsl_filenames+=("$1") | ||
xsl_files+=("$xsl_file") | ||
|
||
# determine the output filename | ||
output_filename="$2" | ||
if [ -z "$output_filename" ]; then | ||
|
||
# compute the output filename | ||
|
||
# if the XSL filename is of the form | ||
# base_filename_csv.xsl | ||
# or | ||
# base_filename_json.xsl | ||
# then construct the output filename with the corresponding extension: | ||
# base_filename.csv | ||
# base_filename_.son | ||
# otherwise the output filename is the XSL filename sans the .xsl extension | ||
base_filename="${1%%.*}" | ||
if [[ $base_filename =~ _(csv|json)$ ]]; then | ||
output_filename=$( echo "$base_filename" | $_SED -e 's/^\(.*\)_\([^_]*\)$/\1.\2/' ) | ||
else | ||
output_filename="$base_filename" | ||
fi | ||
fi | ||
|
||
# capture remaining array elements | ||
out_filenames+=("$output_filename") | ||
out_files+=("${tmp_dir}/$output_filename") | ||
} | ||
|
||
####################################################################### | ||
# Initialization | ||
####################################################################### | ||
|
||
# source lib files | ||
for lib_filename in ${lib_filenames[*]}; do | ||
lib_file="$LIB_DIR/$lib_filename" | ||
source "$lib_file" | ||
status_code=$? | ||
if [ $status_code -ne 0 ]; then | ||
echo "ERROR: $script_name failed ($status_code) to source lib file $lib_file" >&2 | ||
exit 2 | ||
fi | ||
done | ||
|
||
# create a temporary subdirectory | ||
tmp_dir="${TMPDIR%%/}/${script_name%%.*}_$$" | ||
/bin/mkdir "$tmp_dir" | ||
status_code=$? | ||
if [ $status_code -ne 0 ]; then | ||
echo "ERROR: $script_name failed ($status_code) to create tmp dir $tmp_dir" >&2 | ||
exit 2 | ||
fi | ||
|
||
# specify input file | ||
xml_file="${tmp_dir}/saml-metadata.xml" | ||
|
||
# declare arrays | ||
xsl_filenames=() | ||
xsl_files=() | ||
out_filenames=() | ||
out_files=() | ||
|
||
# iterate over the command-line arguments | ||
num_args=$# # TODO: simplify this loop | ||
for (( i = 0; i < num_args; i++ )); do | ||
|
||
# process the next command-line arg | ||
# (do not quote the arg) | ||
process_arg $1 | ||
status_code=$? | ||
if [ $status_code -ne 0 ]; then | ||
echo "ERROR: $script_name failed ($status_code) to process arg $1" >&2 | ||
exit 2 | ||
fi | ||
|
||
shift | ||
done | ||
|
||
####################################################################### | ||
# Main processing | ||
####################################################################### | ||
|
||
print_log_message -I "$script_name BEGIN" | ||
|
||
# get a cached metadata file | ||
print_log_message -I "$script_name retrieving cached metadata file: $md_location" | ||
conditional_get $local_opts -C -d "$CACHE_DIR" -T "$tmp_dir" "$md_location" > "$xml_file" | ||
status_code=$? | ||
if [ $status_code -eq 1 ]; then | ||
# metadata must be cached | ||
print_log_message -E "$script_name: metadata file not cached: $md_location" | ||
clean_up_and_exit -d "$tmp_dir" 1 | ||
fi | ||
if [ $status_code -gt 1 ]; then | ||
print_log_message -E "$script_name: conditional_get failed ($status_code) on location: $md_location" | ||
clean_up_and_exit -d "$tmp_dir" $status_code | ||
fi | ||
print_log_message -D "$script_name using XML file: $xml_file" | ||
|
||
# create the output files | ||
for i in ${!out_files[*]}; do | ||
print_log_message -I "$script_name writing output file: ${out_filenames[$i]}" | ||
/usr/bin/xsltproc ${xsl_files[$i]} $xml_file > ${out_files[$i]} | ||
status_code=$? | ||
if [ $status_code -ne 0 ]; then | ||
print_log_message -E "$script_name: xsltproc failed ($status_code) on stylesheet: ${xsl_files[$i]}" | ||
clean_up_and_exit -d "$tmp_dir" $status_code | ||
fi | ||
done | ||
|
||
# move the output files to the web directory | ||
print_log_message -I "$script_name moving output files to dir: $out_dir" | ||
/bin/mv $( echo -n ${out_files[*]} ) $out_dir | ||
status_code=$? | ||
if [ $status_code -ne 0 ]; then | ||
print_log_message -E "$script_name: mv failed ($status_code) to dir: $out_dir" | ||
clean_up_and_exit -d "$tmp_dir" $status_code | ||
fi | ||
|
||
print_log_message -I "$script_name END" | ||
clean_up_and_exit -d "$tmp_dir" 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters