From 204f8603b85d996d6c1517f195e83fcda86447c7 Mon Sep 17 00:00:00 2001 From: Radeck Date: Tue, 13 Feb 2018 19:59:04 +0000 Subject: [PATCH] Added validation --- configuration/aws-automation/aws-setup.sh | 5 ++- .../aws-automation/lib/functions_ec2.sh | 39 ++++++++++--------- .../aws-automation/lib/functions_io.sh | 28 +++++++------ .../aws-automation/lib/functions_wrapper.sh | 4 +- .../aws-automation/lib/scenario_instance.sh | 17 ++++---- .../lib/scenario_master_instance.sh | 2 +- .../aws-automation/lib/util_functions.sh | 16 +------- .../aws-automation/lib/validation.sh | 27 +++++++++++++ 8 files changed, 82 insertions(+), 56 deletions(-) create mode 100644 configuration/aws-automation/lib/validation.sh diff --git a/configuration/aws-automation/aws-setup.sh b/configuration/aws-automation/aws-setup.sh index 5ca926ffd96..b183154c3c5 100755 --- a/configuration/aws-automation/aws-setup.sh +++ b/configuration/aws-automation/aws-setup.sh @@ -27,7 +27,7 @@ function trapCleanup() { function safeExit() { deleteTemp trap - INT TERM EXIT - exit + exit 77 } function deleteTemp () { @@ -265,6 +265,9 @@ if ${strict}; then set -o nounset ; fi # This way you can catch the error in case mysqldump fails in `mysqldump |gzip`, for example. set -o pipefail +set -E +trap '[ "$?" -ne 77 ] || exit 77' ERR + # Invoke the checkDependenices function to test for Bash packages. Uncomment if needed. # checkDependencies diff --git a/configuration/aws-automation/lib/functions_ec2.sh b/configuration/aws-automation/lib/functions_ec2.sh index 36a6cd97466..8ba369f8418 100644 --- a/configuration/aws-automation/lib/functions_ec2.sh +++ b/configuration/aws-automation/lib/functions_ec2.sh @@ -5,8 +5,9 @@ # @param $1 instance id # @return public dns name # ----------------------------------------------------------- -function query_public_dns_name(){ - aws_wrapper ec2 describe-instances --instance-ids $1 --output text --query 'Reservations[*].Instances[*].PublicDnsName' +function get_public_dns_name(){ + local public_dns_name=$(aws_wrapper ec2 describe-instances --instance-ids $1 --output text --query 'Reservations[*].Instances[*].PublicDnsName') + exit_on_fail validate_hostname $public_dns_name } # ----------------------------------------------------------- @@ -41,25 +42,23 @@ function get_default_vpc_id(){ # ----------------------------------------------------------- function get_instance_id(){ local_echo "Querying for the instance id of $1..." - aws_wrapper ec2 describe-instances --query "Reservations[*].Instances[?PublicDnsName=='$1'].InstanceId" --output text + local instance_id=$(aws_wrapper ec2 describe-instances --query "Reservations[*].Instances[?PublicDnsName=='$1'].InstanceId" --output text) + exit_on_fail validate_instance_id $instance_id } # ----------------------------------------------------------- # Returns the instance id part of e.g. arn:aws:ec2:eu-west-2:017363970217:instance/i-096a32ca8c28bedbb # param $1 resource arn -# @return instance id +# @return id part of arn # ----------------------------------------------------------- function get_resource_id(){ cut -d/ -f2 <<< $1 } -function is_resource_arn(){ - [[ $1 == arn:* ]] -} - function get_public_ip(){ local_echo "Querying for the public ip of $1..." - aws_wrapper ec2 describe-instances --query "Reservations[*].Instances[?PublicIpAddress=='$1'].InstanceId" --output text + local ip_address=$(aws_wrapper ec2 describe-instances --query "Reservations[*].Instances[?PublicIpAddress=='$1'].InstanceId" --output text) + exit_on_fail validate_ipaddress $ip_address } # ----------------------------------------------------------- @@ -108,19 +107,19 @@ function wait_for_ssh_connection(){ } function run_instance(){ - exit_on_fail aws_wrapper ec2 run-instances --image-id $(get_resource_id $image_id) --count 1 --instance-type $instance_type --key-name $key_name \ + local instance_id=$(aws_wrapper ec2 run-instances --image-id $(get_resource_id $image_id) --count 1 --instance-type $instance_type --key-name $key_name \ --security-group-ids $(get_resource_id $instance_security_group_id) --user-data "$1" \ - --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=$instance_name}]" + --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=$instance_name}]" | get_attribute '.Instances[0].InstanceId') + exit_on_fail validate_instance_id $instance_id } - # ----------------------------------------------------------- # Get user data of instance with specific instance id # @param $1 instance id # @return user data of instance # ----------------------------------------------------------- function get_user_data_from_instance() { - aws_wrapper ec2 describe-instance-attribute --instance-id $1 --attribute userData --output text --query "UserData.Value" | sanitize + aws_wrapper ec2 describe-instance-attribute --instance-id $1 --attribute userData --output text --query "UserData.Value" | sanitize } # ----------------------------------------------------------- @@ -129,12 +128,14 @@ function get_user_data_from_instance() { # ----------------------------------------------------------- function create_instance(){ local_echo -e "Creating instance with following specifications:\n\nRegion: $region\nName: $instance_name\nShort name: $instance_short_name\nType: $instance_type\nBuild: $build_version\n\nUser data:\n${1}\n" - json_instance=$(run_instance "$1") - instance_id=$(echo "$json_instance" | get_attribute '.Instances[0].InstanceId') + instance_id=$(run_instance "$1") wait_instance_exists $instance_id - aws_wrapper --region $region ec2 describe-instances --instance-ids $instance_id \ - --query "Reservations[*].Instances[0].{InstanceId:InstanceId, ImageId:ImageId, Type:InstanceType, PublicDNS:PublicDnsName, KeyName:KeyName, PrivateDnsName:PrivateDnsName, PrivateIpAddress:PrivateIpAddress}"\ - --output table - + print_instance_description $instance_id echo $instance_id } + +function print_instance_description(){ + aws_wrapper ec2 describe-instances --instance-ids $1 \ + --query "Reservations[*].Instances[0].{InstanceId:InstanceId, ImageId:ImageId, Type:InstanceType, PublicDNS:PublicDnsName, KeyName:KeyName, PrivateDnsName:PrivateDnsName, PrivateIpAddress:PrivateIpAddress}"\ + --output table 1>&2 +} diff --git a/configuration/aws-automation/lib/functions_io.sh b/configuration/aws-automation/lib/functions_io.sh index ef779658169..e3dbbb39b61 100644 --- a/configuration/aws-automation/lib/functions_io.sh +++ b/configuration/aws-automation/lib/functions_io.sh @@ -35,7 +35,7 @@ function require_input(){ else if [ "$4" == "true" ]; then read -e -s -p "$1" -i "$2" $3 - # print new line after read -s + # print new line after read -s echo else read -e -p "$1" -i "$2" $3 @@ -132,6 +132,7 @@ function get_names_for_resources(){ echo ${names[@]} } + function update_resources(){ local resources_file=./lib/resources-$region.sh > $resources_file @@ -257,11 +258,15 @@ function require_instance_short_name(){ } function require_key_name(){ - require_variable "$key_name_param" key_name "$default_key_name" "$key_name_ask_message" "true" "false" + if [ -z ${key_file+x} ] || [ ! -z "$key_file" ]; then + require_variable "$key_name_param" key_name "$default_key_name" "$key_name_ask_message" "true" "false" + fi } function require_key_file(){ - require_variable "$key_file_param" key_file "$default_key_file" "$key_file_ask_message" "true" "false" + if [ -z ${key_name+x} ] || [ ! -z "$key_name" ]; then + require_variable "$key_file_param" key_file "$default_key_file" "$key_file_ask_message" "true" "false" + fi } function require_new_admin_password(){ @@ -269,11 +274,13 @@ function require_new_admin_password(){ } function require_user_username(){ - require_variable "$user_username_param" user_username "$default_user_username" "$user_username_ask_message" "true" "false" + if [ ! -z ${user_password+x} ] || [ ! -z "$user_password" ]; then + require_variable "$user_username_param" user_username "$default_user_username" "$user_username_ask_message" "true" "false" + fi } function require_user_password(){ - if [ ! -z "$user_name" ]; then + if [ ! -z ${user_name+x} ] || [ ! -z "$user_name" ]; then require_variable "$user_password_param" user_password "$default_user_password" "$user_password_ask_message" "true" "true" fi } @@ -292,7 +299,7 @@ function require_super_instance(){ disable_aws_success_output if is_resource_arn $super_instance; then local instance_id=$(get_resource_id $super_instance) - super_instance=$(query_public_dns_name $instance_id) + super_instance=$(get_public_dns_name $instance_id) fi enable_aws_success_output } @@ -313,12 +320,12 @@ function require_build_version(){ require_variable "$build_version_param" build_version "$latest_release" "$build_version_message" "false" } -event_name_ask_message="Please enter an event name if you want to create an event, leave blank otherwise:" +event_name_ask_message="Please enter an event name (leave blank to skip event creation):" instance_security_group_id_ask_message="Please select the security group for the instance: " -load_balancer_ask_message="Please select/enter the load balancer: " +load_balancer_ask_message="Please select/enter the load balancer dns name: " region_ask_message="Please enter the region you want to use (e.g. eu-west-2): " instance_type_ask_message="Please enter the instance type (e.g. t2.medium): " -key_name_ask_message="Please enter the name of your keypair to connect to the instance (e.g. leon-keypair): " +key_name_ask_message="Please enter the name of your keypair to connect to the instance (e.g. leon-keypair). Leave blank to use ~/.ssh key: " instance_name_ask_message="Please enter a name for the instance: (e.g \"WC Santander 2017\"): " instance_short_name_ask_message="Please enter a short name for the instance (e.g. \"wcs17\"): " key_file_ask_message="Please enter the file path of the keypair or leave empty to use ~/.ssh key: " @@ -327,8 +334,7 @@ mongo_db_host_ask_message="Please enter the ip adress of the mongo db server: " mongo_db_port_ask_message="Please enter the port of the mongo db server: " user_username_ask_message="Please enter the username of your new user (leave blank to skip user creation): " user_password_ask_message="Please enter the password of your new user (leave blank to skip user creation): " -public_dns_name_ask_message="Please enter the public dns name: " -ssh_user_ask_message="Please enter the ssh user: " +ssh_user_ask_message="Please enter the ssh user to connect to the instance: " super_instance_message="Please select/enter the dns name of the superior instance: " description_message="Please enter a description for the server (leave blank to skip): " contact_person_message="Please enter the name of a contact person (leave blank to skip): " diff --git a/configuration/aws-automation/lib/functions_wrapper.sh b/configuration/aws-automation/lib/functions_wrapper.sh index f4ff00f0a3c..4e784b63539 100644 --- a/configuration/aws-automation/lib/functions_wrapper.sh +++ b/configuration/aws-automation/lib/functions_wrapper.sh @@ -34,7 +34,7 @@ function curl_wrapper(){ # ----------------------------------------------------------- function aws_wrapper(){ local out; - out=$(aws --region $region "$@") + out=$(aws --region $region "$@" 2>&1) if command_was_successful $?; then if [ "$DISPLAY_SUCCESS_FOR_THIS_COMMAND" != "false" ]; then success ${out:-"[ OK ]"} @@ -42,7 +42,7 @@ function aws_wrapper(){ echo $out | sanitize else error "[ ERROR ] $out" - return 1 + safeExit fi } diff --git a/configuration/aws-automation/lib/scenario_instance.sh b/configuration/aws-automation/lib/scenario_instance.sh index 38ab173e1be..abc045ba213 100644 --- a/configuration/aws-automation/lib/scenario_instance.sh +++ b/configuration/aws-automation/lib/scenario_instance.sh @@ -34,19 +34,22 @@ function instance_require(){ # @param $1 user data # ----------------------------------------------------------- function instance_execute() { + header "Instance Initialization" - local user_data=$(build_configuration "MONGODB_HOST=$default_mongodb_host" "MONGODB_PORT=$default_mongodb_port" "MONGODB_NAME=$(alphanumeric $instance_name)" \ - "REPLICATION_CHANNEL=$(alphanumeric $instance_name)" "SERVER_NAME=$(alphanumeric $instance_name)" "USE_ENVIRONMENT=live-server" \ - "INSTALL_FROM_RELEASE=$build_version" "SERVER_STARTUP_NOTIFY=$default_server_startup_notify") - - instance_id=$(exit_on_fail create_instance "$user_data") - public_dns_name=$(exit_on_fail query_public_dns_name $instance_id) - + local user_data=$(build_user_data) + instance_id=$(create_instance "$user_data") + public_dns_name=$(get_public_dns_name $instance_id) wait_for_ssh_connection $ssh_user $public_dns_name header "Event and user creation" + local port="8888" configure_application $public_dns_name $port $event_name $new_admin_password $user_username $user_pass +} +function build_user_data(){ + build_configuration "MONGODB_HOST=$default_mongodb_host" "MONGODB_PORT=$default_mongodb_port" "MONGODB_NAME=$(alphanumeric $instance_name)" \ + "REPLICATION_CHANNEL=$(alphanumeric $instance_name)" "SERVER_NAME=$(alphanumeric $instance_name)" "USE_ENVIRONMENT=live-server" \ + "INSTALL_FROM_RELEASE=$build_version" "SERVER_STARTUP_NOTIFY=$default_server_startup_notify" } diff --git a/configuration/aws-automation/lib/scenario_master_instance.sh b/configuration/aws-automation/lib/scenario_master_instance.sh index 81cc3c19bb0..a075900f6d1 100644 --- a/configuration/aws-automation/lib/scenario_master_instance.sh +++ b/configuration/aws-automation/lib/scenario_master_instance.sh @@ -43,7 +43,7 @@ function master_instance_execute() { "INSTALL_FROM_RELEASE=$build_version" "SERVER_STARTUP_NOTIFY=$default_server_startup_notify") instance_id=$(exit_on_fail create_instance "$user_data_master") - public_dns_name=$(exit_on_fail query_public_dns_name $instance_id) + public_dns_name=$(get_public_dns_name $instance_id) wait_for_ssh_connection $ssh_user $public_dns_name diff --git a/configuration/aws-automation/lib/util_functions.sh b/configuration/aws-automation/lib/util_functions.sh index d6b6789e134..91d1cf6c944 100644 --- a/configuration/aws-automation/lib/util_functions.sh +++ b/configuration/aws-automation/lib/util_functions.sh @@ -37,6 +37,7 @@ function uncomment_line_starting_with(){ sed -i '/$1/s/^#//g' $2 } + # ----------------------------------------------------------- # Checks if variable is a number # @param $1 returnvariablevalue @@ -46,21 +47,6 @@ function is_number(){ [[ $1 =~ ^-?[0-9]+$ ]] } -# ----------------------------------------------------------- -# Finds first missing number in array of sorted numbers -# @param $1 array of numbers -# @return first missing number -# ----------------------------------------------------------- -function find_first_missing_number_in_array(){ - arr=("$@") - for (( i = 0 ; i < $((${#arr[@]})) ; i++ )); do - if [ "$((${arr[$i]}+1))" != "${arr[$(($i + 1))]}" ] ;then - missing_number="$((${arr[$i]}+1))" - break - fi - done - echo $missing_number -} # ----------------------------------------------------------- diff --git a/configuration/aws-automation/lib/validation.sh b/configuration/aws-automation/lib/validation.sh new file mode 100644 index 00000000000..0ee358773e2 --- /dev/null +++ b/configuration/aws-automation/lib/validation.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +ValidHostnameRegex='^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$' +ValidIpAddressRegex='^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$' +ValidInstanceIdRegex='i-[a-zA-Z0-9]{17}' +ValidResourceARNRegex="arn:.+" + +function validate_resource_arn(){ + [[ "$1" =~ $ValidResourceARNRegex ]] && echo "$1" || error_message "ResourceARN \"$1\" not valid." +} + +function validate_instance_id(){ + [[ "$1" =~ $ValidInstanceIdRegex ]] && echo "$1" || error_message "Instance id \"$1\" not valid." +} + +function validate_hostname(){ + [[ "$1" =~ $ValidHostnameRegex ]] && echo "$1" || error_message "Hostname \"$1\" not valid." +} + +function validate_ipaddress(){ + [[ "$1" =~ $ValidIpAddressRegex ]] && echo "$1" || error_message "Ip address \"$1\" not valid." +} + +function error_message(){ + error "[ ERROR ] $1 (${FUNCNAME[@]})" + return 1 +}